Add print-ready PDF (#127)
This commit is contained in:
parent
0910f3909f
commit
c9ed60daf5
|
@ -16,8 +16,10 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
- name: Install plugin
|
- name: Install exercise plugin
|
||||||
run: cargo install --path helpers/mdbook-exercise-linker
|
run: cargo install --path helpers/mdbook-exercise-linker
|
||||||
|
- name: Install link shortener plugin
|
||||||
|
run: cargo install --path helpers/mdbook-link-shortener
|
||||||
- name: Install mdbook-pandoc and related dependencies
|
- name: Install mdbook-pandoc and related dependencies
|
||||||
run: |
|
run: |
|
||||||
cargo install mdbook-pandoc --locked --version 0.7.1
|
cargo install mdbook-pandoc --locked --version 0.7.1
|
||||||
|
@ -63,6 +65,8 @@ jobs:
|
||||||
with:
|
with:
|
||||||
tool: mdbook
|
tool: mdbook
|
||||||
- name: Build book
|
- name: Build book
|
||||||
|
env:
|
||||||
|
LINK_SHORTENER_VERIFY: "true"
|
||||||
run: |
|
run: |
|
||||||
cd book
|
cd book
|
||||||
mdbook build
|
mdbook build
|
||||||
|
@ -82,11 +86,25 @@ jobs:
|
||||||
# When you support multiple formats, the output directory changes
|
# When you support multiple formats, the output directory changes
|
||||||
# to include the format in its path.
|
# to include the format in its path.
|
||||||
path: book/book/html
|
path: book/book/html
|
||||||
# Upload the PDF book as an artifact
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: online-pdf
|
||||||
|
path: book/book/pandoc/pdf/100-exercises-to-learn-rust.pdf
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: paperback
|
name: paperback
|
||||||
path: book/book/pandoc/pdf/100-exercises-to-learn-rust.pdf
|
path: book/book/pandoc/paperback/100-exercises-to-learn-rust.pdf
|
||||||
|
|
||||||
|
is_fresh:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: sudo apt-get update && sudo apt-get install -y jq
|
||||||
|
- run: |
|
||||||
|
./helpers/json2redirects.sh book/link2alias.json > site/redirects
|
||||||
|
# Verify nothing has changed, meaning that the redirect file is up-to-date
|
||||||
|
- run: |
|
||||||
|
git diff --exit-code site/redirects
|
||||||
|
|
||||||
formatter:
|
formatter:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -163,6 +163,15 @@ version = "0.21.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bimap"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -280,6 +289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
|
checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -304,6 +314,18 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
|
@ -448,6 +470,12 @@ dependencies = [
|
||||||
name = "drop"
|
name = "drop"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "elasticlunr-rs"
|
name = "elasticlunr-rs"
|
||||||
version = "3.0.2"
|
version = "3.0.2"
|
||||||
|
@ -667,6 +695,15 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getopts"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -771,6 +808,12 @@ dependencies = [
|
||||||
name = "heap"
|
name = "heap"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
@ -1037,6 +1080,15 @@ dependencies = [
|
||||||
"ticket_fields",
|
"ticket_fields",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
@ -1182,7 +1234,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"opener",
|
"opener",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
"pulldown-cmark",
|
"pulldown-cmark 0.10.3",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1206,6 +1258,21 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdbook-link-shortener"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bimap",
|
||||||
|
"clap",
|
||||||
|
"itertools",
|
||||||
|
"mdbook",
|
||||||
|
"pulldown-cmark 0.11.0",
|
||||||
|
"pulldown-cmark-to-cmark",
|
||||||
|
"semver",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
|
@ -1615,7 +1682,20 @@ checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"memchr",
|
"memchr",
|
||||||
"pulldown-cmark-escape",
|
"pulldown-cmark-escape 0.10.1",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"getopts",
|
||||||
|
"memchr",
|
||||||
|
"pulldown-cmark-escape 0.11.0",
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1625,6 +1705,21 @@ version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
|
checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark-escape"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark-to-cmark"
|
||||||
|
version = "15.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9c77db841443d89a57ae94f22d29c022f6d9f41b00bddbf1f4024dbaf4bdce1"
|
||||||
|
dependencies = [
|
||||||
|
"pulldown-cmark 0.11.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.36"
|
version = "1.0.36"
|
||||||
|
@ -2290,6 +2385,12 @@ dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unwrap"
|
name = "unwrap"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["exercises/*/*", "helpers/common", "helpers/mdbook-exercise-linker", "helpers/ticket_fields"]
|
members = [
|
||||||
|
"exercises/*/*",
|
||||||
|
"helpers/common",
|
||||||
|
"helpers/mdbook-exercise-linker",
|
||||||
|
"helpers/mdbook-link-shortener",
|
||||||
|
"helpers/ticket_fields",
|
||||||
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
# This is needed to guarantee the expected behaviour on that specific exercise,
|
# This is needed to guarantee the expected behaviour on that specific exercise,
|
||||||
|
|
|
@ -39,8 +39,44 @@ header-includes = [
|
||||||
"\\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\\\\{\\},fontsize=\\small}",
|
"\\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\\\\{\\},fontsize=\\small}",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[output.pandoc.profile.paperback]
|
||||||
|
output-file = "100-exercises-to-learn-rust.pdf"
|
||||||
|
to = "latex"
|
||||||
|
highlight-style = "monochrome"
|
||||||
|
# We use `lualatext` because, right now, it's the only engine
|
||||||
|
# that supports fallback fonts, which we need for emojis.
|
||||||
|
pdf-engine = "lualatex"
|
||||||
|
|
||||||
|
[output.pandoc.profile.paperback.variables]
|
||||||
|
subtitle = "A hands-on course by Mainmatter"
|
||||||
|
# You can get these fonts here: https://fonts.google.com/selection?query=noto+color+
|
||||||
|
mainfont = "Noto Serif"
|
||||||
|
sansfont = "Noto Sans"
|
||||||
|
monofont = "Noto Sans Mono"
|
||||||
|
mainfontfallback = ["Noto Color Emoji:mode=harf"]
|
||||||
|
sansfontfallback = ["Noto Color Emoji:mode=harf"]
|
||||||
|
monofontfallback = [
|
||||||
|
"Noto Color Emoji:mode=harf",
|
||||||
|
]
|
||||||
|
urlstyle = "rm"
|
||||||
|
documentclass = "book"
|
||||||
|
fontsize = "11pt"
|
||||||
|
geometry = "papersize={8in,10in},top=2cm,bottom=2cm,left=2.4cm,right=2.4cm"
|
||||||
|
header-includes = [
|
||||||
|
# Reduce font size of code blocks
|
||||||
|
"\\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\\\\{\\},fontsize=\\small}",
|
||||||
|
]
|
||||||
|
links-as-notes = true
|
||||||
|
|
||||||
[output.html]
|
[output.html]
|
||||||
git-repository-url = "https://github.com/mainmatter/100-exercises-to-learn-rust"
|
git-repository-url = "https://github.com/mainmatter/100-exercises-to-learn-rust"
|
||||||
|
|
||||||
[preprocessor.exercise-linker]
|
[preprocessor.exercise-linker]
|
||||||
exercise_root_url = "https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises"
|
exercise_root_url = "https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises"
|
||||||
|
|
||||||
|
[preprocessor.link-shortener]
|
||||||
|
base_url = "https://ruex.io"
|
||||||
|
renderers = ["pandoc"]
|
||||||
|
mapping = "link2alias.json"
|
||||||
|
verify = false
|
||||||
|
after = ["exercise-linker"]
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
{
|
||||||
|
"https://blog.acolyer.org/2019/05/28/cheri-abi/": "f2u",
|
||||||
|
"https://crates.io": "f4q",
|
||||||
|
"https://crates.io/crates/cargo-modules": "f2n",
|
||||||
|
"https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-types": "ffr",
|
||||||
|
"https://doc.rust-lang.org/book/title-page.html": "f6t",
|
||||||
|
"https://doc.rust-lang.org/cargo/reference/cargo-targets.html#cargo-targets": "f4m",
|
||||||
|
"https://doc.rust-lang.org/cargo/reference/profiles.html": "ffc",
|
||||||
|
"https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html": "f45",
|
||||||
|
"https://doc.rust-lang.org/nomicon/": "f6u",
|
||||||
|
"https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast": "f2z",
|
||||||
|
"https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence": "fzf",
|
||||||
|
"https://doc.rust-lang.org/reference/lifetime-elision.html": "f4c",
|
||||||
|
"https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html": "fxy",
|
||||||
|
"https://doc.rust-lang.org/std/cmp/index.html": "fzm",
|
||||||
|
"https://doc.rust-lang.org/std/cmp/trait.PartialEq.html": "fzz",
|
||||||
|
"https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html": "fzb",
|
||||||
|
"https://doc.rust-lang.org/std/convert/trait.From.html#implementors": "fzp",
|
||||||
|
"https://doc.rust-lang.org/std/convert/trait.Into.html#implementors": "fzl",
|
||||||
|
"https://doc.rust-lang.org/std/iter/trait.FusedIterator.html": "f4s",
|
||||||
|
"https://doc.rust-lang.org/std/iter/trait.Iterator.html": "fxf",
|
||||||
|
"https://doc.rust-lang.org/std/keyword.for.html": "ffj",
|
||||||
|
"https://doc.rust-lang.org/std/keyword.while.html": "ffh",
|
||||||
|
"https://doc.rust-lang.org/std/macro.panic.html": "ffl",
|
||||||
|
"https://doc.rust-lang.org/std/mem/fn.size_of.html": "f27",
|
||||||
|
"https://doc.rust-lang.org/std/ops/index.html": "fzn",
|
||||||
|
"https://doc.rust-lang.org/std/ops/trait.Add.html": "fz4",
|
||||||
|
"https://doc.rust-lang.org/std/ops/trait.Deref.html#deref-coercion": "fzt",
|
||||||
|
"https://doc.rust-lang.org/std/ops/trait.Div.html": "fzv",
|
||||||
|
"https://doc.rust-lang.org/std/ops/trait.Mul.html": "fz6",
|
||||||
|
"https://doc.rust-lang.org/std/ops/trait.Rem.html": "fz8",
|
||||||
|
"https://doc.rust-lang.org/std/ops/trait.Sub.html": "fzx",
|
||||||
|
"https://doc.rust-lang.org/std/prelude/index.html": "f2c",
|
||||||
|
"https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MAX": "ffe",
|
||||||
|
"https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MIN": "ff7",
|
||||||
|
"https://doc.rust-lang.org/std/primitive.u32.html#associatedconstant.MAX": "ffw",
|
||||||
|
"https://doc.rust-lang.org/std/slice/struct.Iter.html": "f4d",
|
||||||
|
"https://doc.rust-lang.org/std/string/struct.String.html": "f26",
|
||||||
|
"https://doc.rust-lang.org/std/sync/atomic/index.html": "fxh",
|
||||||
|
"https://doc.rust-lang.org/std/vec/struct.Vec.html#method.iter": "f4j",
|
||||||
|
"https://docs.rs/dhat/latest/dhat/": "f2y",
|
||||||
|
"https://docs.rs/itertools/": "fx2",
|
||||||
|
"https://docs.rs/thiserror/latest/thiserror/": "f4n",
|
||||||
|
"https://docs.rs/tokio-stream/latest/tokio_stream/": "f65",
|
||||||
|
"https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.merge": "f6m",
|
||||||
|
"https://docs.rs/tokio-util/latest/tokio_util/sync/struct.CancellationToken.html": "f63",
|
||||||
|
"https://docs.rs/tokio/latest/tokio/task/struct.JoinError.html": "f6z",
|
||||||
|
"https://docs.rust-embedded.org/book/": "f6k",
|
||||||
|
"https://en.wikipedia.org/wiki/Dangling_pointer": "f2h",
|
||||||
|
"https://en.wikipedia.org/wiki/Data_segment": "fx7",
|
||||||
|
"https://en.wikipedia.org/wiki/Memory_address": "f2r",
|
||||||
|
"https://en.wikipedia.org/wiki/Stack_overflow": "f2e",
|
||||||
|
"https://en.wikipedia.org/wiki/Two%27s_complement": "ff9",
|
||||||
|
"https://en.wikipedia.org/wiki/UTF-8": "f2v",
|
||||||
|
"https://exercism.io": "f6r",
|
||||||
|
"https://github.com/LukeMathWalker/cargo-chef": "ffb",
|
||||||
|
"https://github.com/LukeMathWalker/wiremock-rs": "ffm",
|
||||||
|
"https://github.com/dtolnay/cargo-expand": "fzq",
|
||||||
|
"https://github.com/dtolnay/proc-macro-workshop": "fzw",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust": "ff6",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/01_intro/00_welcome": "ff3",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/01_intro/01_syntax": "ffq",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/00_intro": "ff5",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/01_integers": "fft",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/02_variables": "ffy",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/03_if_else": "ffu",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/04_panics": "ffk",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/05_factorial": "ffs",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/06_while": "ffg",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/07_for": "ffd",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/08_overflow": "f2f",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/09_saturating": "f22",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/10_as_casting": "f24",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/00_intro": "f2x",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/01_struct": "f28",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/02_validation": "f2b",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/03_modules": "f2m",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/04_visibility": "f23",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/05_encapsulation": "f2q",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/06_ownership": "f25",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/07_setters": "f2w",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/08_stack": "f29",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/09_heap": "f2p",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/10_references_in_memory": "f2l",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/11_destructor": "f2g",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/12_outro": "f2j",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/00_intro": "f2d",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/01_trait": "f2a",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/02_orphan_rule": "fz2",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/03_operator_overloading": "fz3",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/04_derive": "fz7",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/05_trait_bounds": "fz9",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/06_str_slice": "fzr",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/07_deref": "fzy",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/08_sized": "fzu",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/09_from": "fzk",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/10_assoc_vs_generic": "fzs",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/11_clone": "fzh",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/12_copy": "fzg",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/13_drop": "fzj",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/14_outro": "fzc",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/00_intro": "fza",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/01_enum": "f4f",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/02_match": "f42",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/03_variants_with_data": "f4z",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/04_if_let": "f44",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/05_nullability": "f4x",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/06_fallibility": "f46",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/07_unwrap": "f4v",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/08_error_enums": "f48",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/09_error_trait": "f4b",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/10_packages": "f43",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/11_dependencies": "f4w",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/12_thiserror": "f47",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/13_try_from": "f4e",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/14_source": "f49",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/15_outro": "f4y",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/00_intro": "f4u",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/01_arrays": "f4p",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/02_vec": "f4l",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/03_resizing": "f4k",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/04_iterators": "f4h",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/05_iter": "f4g",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/06_lifetimes": "f4a",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/07_combinators": "fxz",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/08_impl_trait": "fx4",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/09_impl_trait_2": "fxx",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/10_slices": "fx6",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/11_mutable_slices": "fxv",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/12_two_states": "fx8",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/13_index": "fxb",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/14_index_mut": "fxn",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/15_hashmap": "fxm",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/16_btreemap": "fx3",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/00_intro": "fxq",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/01_threads": "fxw",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/02_static": "fxe",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/03_leak": "fx9",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/04_scoped_threads": "fxr",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/05_channels": "fxt",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/06_interior_mutability": "fxu",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/07_ack": "fxp",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/08_client": "fxl",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/09_bounded": "fxk",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/10_patch": "fxs",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/11_locks": "fxj",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/12_rw_lock": "fxd",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/13_without_channels": "fxc",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/14_sync": "fxa",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/00_intro": "f6f",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/01_async_fn": "f62",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/02_spawn": "f64",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/03_runtime": "f6x",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/04_future": "f66",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/05_blocking": "f68",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/06_async_aware_primitives": "f6b",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/07_cancellation": "f6q",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/08_outro": "f6e",
|
||||||
|
"https://github.com/mainmatter/100-exercises-to-learn-rust/tree/solutions": "ffz",
|
||||||
|
"https://github.com/mainmatter/rust-advanced-testing-workshop": "fzd",
|
||||||
|
"https://github.com/rust-lang/rustlings": "f69",
|
||||||
|
"https://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/": "ffa",
|
||||||
|
"https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/": "f4r",
|
||||||
|
"https://mainmatter.com/contact/": "ff2",
|
||||||
|
"https://mainmatter.com/rust-consulting/": "fff",
|
||||||
|
"https://marabos.nl/atomics/": "fxg",
|
||||||
|
"https://nostarch.com/rust-rustaceans": "f6p",
|
||||||
|
"https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory": "f2k",
|
||||||
|
"https://owasp.org/www-community/vulnerabilities/Using_freed_memory": "f2s",
|
||||||
|
"https://pavex.dev": "ffn",
|
||||||
|
"https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=36e5ddbe3b3f741dfa9f74c956622bac": "ffp",
|
||||||
|
"https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=afedf7062298ca8f5a248bc551062eaa": "fx5",
|
||||||
|
"https://rust-exercises.com/100-exercises-to-learn-rust.pdf": "ffx",
|
||||||
|
"https://rust-exercises.com/100-exercises/": "ff4",
|
||||||
|
"https://rust-exercises.com/advanced-testing/": "f6s",
|
||||||
|
"https://rust-exercises.com/telemetry/": "f6h",
|
||||||
|
"https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case": "fze",
|
||||||
|
"https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_battles_buffered_streams.html": "f6w",
|
||||||
|
"https://ryhl.io/blog/async-what-is-blocking/": "f6v",
|
||||||
|
"https://tokio.rs/tokio/tutorial/select": "f6n",
|
||||||
|
"https://valgrind.org/docs/manual/dh-manual.html": "f2t",
|
||||||
|
"https://veykril.github.io/tlborm/": "fz5",
|
||||||
|
"https://without.boats/blog/the-scoped-task-trilemma/": "f67",
|
||||||
|
"https://www.lpalmieri.com/": "ffv",
|
||||||
|
"https://www.lpalmieri.com/posts/2020-12-11-zero-to-production-6-domain-modelling/": "f4t",
|
||||||
|
"https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/": "f6y",
|
||||||
|
"https://www.youtube.com/playlist?list=PLqbS7AVVErFirH9armw8yXlE6dacF-A6z": "f6l",
|
||||||
|
"https://zero2prod.com": "ff8"
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Ensure the JSON file is provided as an argument
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "Usage: $0 <input_json_file>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
input_file=$1
|
||||||
|
|
||||||
|
# Use jq to parse the JSON and format the output
|
||||||
|
jq -r 'to_entries[] | "/" + .value + " " + .key' "$input_file"
|
|
@ -3,7 +3,6 @@ use mdbook::book::Book;
|
||||||
use mdbook::preprocess::{Preprocessor, PreprocessorContext};
|
use mdbook::preprocess::{Preprocessor, PreprocessorContext};
|
||||||
use mdbook::BookItem;
|
use mdbook::BookItem;
|
||||||
|
|
||||||
/// A no-op preprocessor.
|
|
||||||
pub struct ExerciseLinker;
|
pub struct ExerciseLinker;
|
||||||
|
|
||||||
impl ExerciseLinker {
|
impl ExerciseLinker {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "mdbook-link-shortener"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.86"
|
||||||
|
bimap = { version = "0.6.3", features = ["serde"] }
|
||||||
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
|
itertools = "0.13.0"
|
||||||
|
mdbook = "0.4.40"
|
||||||
|
pulldown-cmark = "0.11.0"
|
||||||
|
pulldown-cmark-to-cmark = "15"
|
||||||
|
semver = "1.0.23"
|
||||||
|
serde_json = "1.0.117"
|
|
@ -0,0 +1,224 @@
|
||||||
|
use anyhow::{Context, Error};
|
||||||
|
use bimap::BiHashMap;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use mdbook::book::{Book, Chapter};
|
||||||
|
use mdbook::preprocess::{Preprocessor, PreprocessorContext};
|
||||||
|
use mdbook::BookItem;
|
||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
pub struct LinkShortener;
|
||||||
|
|
||||||
|
struct AliasGenerator {
|
||||||
|
cursors: [usize; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AliasGenerator {
|
||||||
|
const ALPHABET: &'static [u8] = b"f2z4x6v8bnm3q5w7e9rtyuplkshgjdca";
|
||||||
|
|
||||||
|
fn new() -> AliasGenerator {
|
||||||
|
AliasGenerator { cursors: [0, 0, 0] }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a 4 alphanumeric long alias, starting from "aaaa" and incrementing by one each time
|
||||||
|
/// until "9999", using only lowercase letters and numbers.
|
||||||
|
/// We skip ambiguous characters like "0", "o", "1", "l".
|
||||||
|
fn next(&mut self) -> String {
|
||||||
|
let mut alias = String::with_capacity(4);
|
||||||
|
for cursor in &mut self.cursors {
|
||||||
|
alias.push(Self::ALPHABET[*cursor] as char);
|
||||||
|
}
|
||||||
|
|
||||||
|
for cursor in self.cursors.iter_mut().rev() {
|
||||||
|
if *cursor == Self::ALPHABET.len() - 1 {
|
||||||
|
*cursor = 0;
|
||||||
|
} else {
|
||||||
|
*cursor += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alias
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a unique alias that is not already used by the `link2alias` map.
|
||||||
|
fn next_until_unique(&mut self, link2alias: &BiHashMap<String, String>) -> String {
|
||||||
|
let mut alias = self.next();
|
||||||
|
while link2alias.contains_right(&alias) {
|
||||||
|
alias = self.next();
|
||||||
|
}
|
||||||
|
alias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinkShortener {
|
||||||
|
pub fn new() -> LinkShortener {
|
||||||
|
LinkShortener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Preprocessor for LinkShortener {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"link-shortener"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book, Error> {
|
||||||
|
let config = ctx
|
||||||
|
.config
|
||||||
|
.get_preprocessor(self.name())
|
||||||
|
.context("Failed to get preprocessor configuration")?;
|
||||||
|
let root_url = {
|
||||||
|
let root_url = config.get("base_url").context("Failed to get `base_url`")?;
|
||||||
|
root_url
|
||||||
|
.as_str()
|
||||||
|
.context("`base_url` is not a string")?
|
||||||
|
.to_owned()
|
||||||
|
};
|
||||||
|
let mapping = {
|
||||||
|
let mapping = config.get("mapping").context("Failed to get `mapping`")?;
|
||||||
|
let mapping = mapping
|
||||||
|
.as_str()
|
||||||
|
.context("`mapping` is not a string")?
|
||||||
|
.to_owned();
|
||||||
|
PathBuf::from_str(&mapping).context("Failed to parse `mapping` as a path")?
|
||||||
|
};
|
||||||
|
let mut link2alias = {
|
||||||
|
match File::open(&mapping) {
|
||||||
|
Ok(file) => {
|
||||||
|
serde_json::from_reader(file).context("Failed to parse existing mapping")?
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
|
BiHashMap::new()
|
||||||
|
} else {
|
||||||
|
return Err(e).context("Failed to open existing mapping");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let verify = config
|
||||||
|
.get("verify")
|
||||||
|
.context("Failed to get `verify`")?
|
||||||
|
.as_bool()
|
||||||
|
.context("`verify` is not a boolean")?;
|
||||||
|
// Env var overrides config
|
||||||
|
let verify = std::env::var("LINK_SHORTENER_VERIFY")
|
||||||
|
.map(|v| v == "true")
|
||||||
|
.unwrap_or(verify);
|
||||||
|
|
||||||
|
let mut alias_gen = AliasGenerator::new();
|
||||||
|
|
||||||
|
book.sections.iter_mut().for_each(|i| {
|
||||||
|
if let BookItem::Chapter(c) = i {
|
||||||
|
c.content = replace_anchors(c, &root_url, &mut alias_gen, &mut link2alias, verify)
|
||||||
|
.expect("Error converting links for chapter");
|
||||||
|
for i in c.sub_items.iter_mut() {
|
||||||
|
if let BookItem::Chapter(sub_chapter) = i {
|
||||||
|
sub_chapter.content = replace_anchors(
|
||||||
|
sub_chapter,
|
||||||
|
&root_url,
|
||||||
|
&mut alias_gen,
|
||||||
|
&mut link2alias,
|
||||||
|
verify,
|
||||||
|
)
|
||||||
|
.expect("Error converting links for subchapter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if !verify {
|
||||||
|
std::fs::create_dir_all(mapping.parent().expect("Mapping file path has no parent"))?;
|
||||||
|
let mut file = File::create(&mapping).context("Failed to upsert mapping file")?;
|
||||||
|
let ordered = link2alias.iter().collect::<BTreeMap<_, _>>();
|
||||||
|
serde_json::to_writer_pretty(&mut file, &ordered)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(book)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supports_renderer(&self, _renderer: &str) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_anchors(
|
||||||
|
chapter: &mut Chapter,
|
||||||
|
root_url: &str,
|
||||||
|
alias_gen: &mut AliasGenerator,
|
||||||
|
link2alias: &mut BiHashMap<String, String>,
|
||||||
|
verify: bool,
|
||||||
|
) -> Result<String, anyhow::Error> {
|
||||||
|
use pulldown_cmark::{CowStr, Event, LinkType, Options, Parser, Tag};
|
||||||
|
use pulldown_cmark_to_cmark::cmark;
|
||||||
|
|
||||||
|
let mut buf = String::with_capacity(chapter.content.len());
|
||||||
|
|
||||||
|
let mut unshortened_links = BTreeSet::new();
|
||||||
|
let events = Parser::new_ext(&chapter.content, Options::all())
|
||||||
|
.map(|e| {
|
||||||
|
let Event::Start(Tag::Link {
|
||||||
|
link_type,
|
||||||
|
dest_url,
|
||||||
|
title,
|
||||||
|
id,
|
||||||
|
}) = &e
|
||||||
|
else {
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
|
||||||
|
match link_type {
|
||||||
|
LinkType::Autolink
|
||||||
|
| LinkType::Shortcut
|
||||||
|
| LinkType::Inline
|
||||||
|
| LinkType::Reference
|
||||||
|
| LinkType::Collapsed => {
|
||||||
|
if dest_url.starts_with("http") {
|
||||||
|
let alias = if let Some(alias) = link2alias.get_by_left(dest_url.as_ref()) {
|
||||||
|
alias.to_owned()
|
||||||
|
} else {
|
||||||
|
if verify {
|
||||||
|
unshortened_links.insert(dest_url.to_string());
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
let alias = alias_gen.next_until_unique(&link2alias);
|
||||||
|
alias
|
||||||
|
};
|
||||||
|
link2alias.insert(dest_url.to_string(), alias.clone());
|
||||||
|
|
||||||
|
Event::Start(Tag::Link {
|
||||||
|
link_type: link_type.to_owned(),
|
||||||
|
dest_url: CowStr::from(format!(
|
||||||
|
"{root_url}/{alias}",
|
||||||
|
root_url = root_url,
|
||||||
|
alias = alias
|
||||||
|
)),
|
||||||
|
title: title.clone(),
|
||||||
|
id: id.clone(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LinkType::Email
|
||||||
|
| LinkType::ReferenceUnknown
|
||||||
|
| LinkType::CollapsedUnknown
|
||||||
|
| LinkType::ShortcutUnknown => e,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
if verify && !unshortened_links.is_empty() {
|
||||||
|
let unshortened_links = unshortened_links.iter().join(", ");
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The following links are not shortened: {unshortened_links}\nRun again with `LINK_SHORTENER_VERIFY=false` to update the mapping \
|
||||||
|
with the shortened links."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
cmark(events.into_iter(), &mut buf)
|
||||||
|
.map(|_| buf)
|
||||||
|
.map_err(|err| anyhow::anyhow!("Markdown serialization failed: {err}"))
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
use clap::Parser;
|
||||||
|
use mdbook::errors::Error;
|
||||||
|
use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
|
||||||
|
use mdbook_link_shortener::LinkShortener;
|
||||||
|
use semver::{Version, VersionReq};
|
||||||
|
use std::io;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
#[derive(clap::Parser, Debug)]
|
||||||
|
#[command(version, about)]
|
||||||
|
pub struct Cli {
|
||||||
|
#[command(subcommand)]
|
||||||
|
sub: Option<SubCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Parser, Debug)]
|
||||||
|
pub enum SubCommand {
|
||||||
|
#[clap(name = "supports")]
|
||||||
|
Supports(Supports),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Parser, Debug)]
|
||||||
|
pub struct Supports {
|
||||||
|
#[arg(long)]
|
||||||
|
renderer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), anyhow::Error> {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
let preprocessor = LinkShortener::new();
|
||||||
|
|
||||||
|
if let Some(SubCommand::Supports(Supports { renderer })) = cli.sub {
|
||||||
|
let code = if preprocessor.supports_renderer(&renderer) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
process::exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_preprocessing(&preprocessor)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> {
|
||||||
|
let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
|
||||||
|
|
||||||
|
let book_version = Version::parse(&ctx.mdbook_version)?;
|
||||||
|
let version_req = VersionReq::parse(mdbook::MDBOOK_VERSION)?;
|
||||||
|
|
||||||
|
if !version_req.matches(&book_version) {
|
||||||
|
eprintln!(
|
||||||
|
"Warning: The {} plugin was built against version {} of mdbook, \
|
||||||
|
but we're being called from version {}",
|
||||||
|
pre.name(),
|
||||||
|
mdbook::MDBOOK_VERSION,
|
||||||
|
ctx.mdbook_version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let processed_book = pre.run(&ctx, book)?;
|
||||||
|
serde_json::to_writer(io::stdout(), &processed_book)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
/f2u https://blog.acolyer.org/2019/05/28/cheri-abi/
|
||||||
|
/f4q https://crates.io
|
||||||
|
/f2n https://crates.io/crates/cargo-modules
|
||||||
|
/ffr https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-types
|
||||||
|
/f6t https://doc.rust-lang.org/book/title-page.html
|
||||||
|
/f4m https://doc.rust-lang.org/cargo/reference/cargo-targets.html#cargo-targets
|
||||||
|
/ffc https://doc.rust-lang.org/cargo/reference/profiles.html
|
||||||
|
/f45 https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
|
||||||
|
/f6u https://doc.rust-lang.org/nomicon/
|
||||||
|
/f2z https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
|
||||||
|
/fzf https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
|
||||||
|
/f4c https://doc.rust-lang.org/reference/lifetime-elision.html
|
||||||
|
/fxy https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
|
||||||
|
/fzm https://doc.rust-lang.org/std/cmp/index.html
|
||||||
|
/fzz https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
|
||||||
|
/fzb https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html
|
||||||
|
/fzp https://doc.rust-lang.org/std/convert/trait.From.html#implementors
|
||||||
|
/fzl https://doc.rust-lang.org/std/convert/trait.Into.html#implementors
|
||||||
|
/f4s https://doc.rust-lang.org/std/iter/trait.FusedIterator.html
|
||||||
|
/fxf https://doc.rust-lang.org/std/iter/trait.Iterator.html
|
||||||
|
/ffj https://doc.rust-lang.org/std/keyword.for.html
|
||||||
|
/ffh https://doc.rust-lang.org/std/keyword.while.html
|
||||||
|
/ffl https://doc.rust-lang.org/std/macro.panic.html
|
||||||
|
/f27 https://doc.rust-lang.org/std/mem/fn.size_of.html
|
||||||
|
/fzn https://doc.rust-lang.org/std/ops/index.html
|
||||||
|
/fz4 https://doc.rust-lang.org/std/ops/trait.Add.html
|
||||||
|
/fzt https://doc.rust-lang.org/std/ops/trait.Deref.html#deref-coercion
|
||||||
|
/fzv https://doc.rust-lang.org/std/ops/trait.Div.html
|
||||||
|
/fz6 https://doc.rust-lang.org/std/ops/trait.Mul.html
|
||||||
|
/fz8 https://doc.rust-lang.org/std/ops/trait.Rem.html
|
||||||
|
/fzx https://doc.rust-lang.org/std/ops/trait.Sub.html
|
||||||
|
/f2c https://doc.rust-lang.org/std/prelude/index.html
|
||||||
|
/ffe https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MAX
|
||||||
|
/ff7 https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MIN
|
||||||
|
/ffw https://doc.rust-lang.org/std/primitive.u32.html#associatedconstant.MAX
|
||||||
|
/f4d https://doc.rust-lang.org/std/slice/struct.Iter.html
|
||||||
|
/f26 https://doc.rust-lang.org/std/string/struct.String.html
|
||||||
|
/fxh https://doc.rust-lang.org/std/sync/atomic/index.html
|
||||||
|
/f4j https://doc.rust-lang.org/std/vec/struct.Vec.html#method.iter
|
||||||
|
/f2y https://docs.rs/dhat/latest/dhat/
|
||||||
|
/fx2 https://docs.rs/itertools/
|
||||||
|
/f4n https://docs.rs/thiserror/latest/thiserror/
|
||||||
|
/f65 https://docs.rs/tokio-stream/latest/tokio_stream/
|
||||||
|
/f6m https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.merge
|
||||||
|
/f63 https://docs.rs/tokio-util/latest/tokio_util/sync/struct.CancellationToken.html
|
||||||
|
/f6z https://docs.rs/tokio/latest/tokio/task/struct.JoinError.html
|
||||||
|
/f6k https://docs.rust-embedded.org/book/
|
||||||
|
/f2h https://en.wikipedia.org/wiki/Dangling_pointer
|
||||||
|
/fx7 https://en.wikipedia.org/wiki/Data_segment
|
||||||
|
/f2r https://en.wikipedia.org/wiki/Memory_address
|
||||||
|
/f2e https://en.wikipedia.org/wiki/Stack_overflow
|
||||||
|
/ff9 https://en.wikipedia.org/wiki/Two%27s_complement
|
||||||
|
/f2v https://en.wikipedia.org/wiki/UTF-8
|
||||||
|
/f6r https://exercism.io
|
||||||
|
/ffb https://github.com/LukeMathWalker/cargo-chef
|
||||||
|
/ffm https://github.com/LukeMathWalker/wiremock-rs
|
||||||
|
/fzq https://github.com/dtolnay/cargo-expand
|
||||||
|
/fzw https://github.com/dtolnay/proc-macro-workshop
|
||||||
|
/ff6 https://github.com/mainmatter/100-exercises-to-learn-rust
|
||||||
|
/ff3 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/01_intro/00_welcome
|
||||||
|
/ffq https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/01_intro/01_syntax
|
||||||
|
/ff5 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/00_intro
|
||||||
|
/fft https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/01_integers
|
||||||
|
/ffy https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/02_variables
|
||||||
|
/ffu https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/03_if_else
|
||||||
|
/ffk https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/04_panics
|
||||||
|
/ffs https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/05_factorial
|
||||||
|
/ffg https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/06_while
|
||||||
|
/ffd https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/07_for
|
||||||
|
/f2f https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/08_overflow
|
||||||
|
/f22 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/09_saturating
|
||||||
|
/f24 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/02_basic_calculator/10_as_casting
|
||||||
|
/f2x https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/00_intro
|
||||||
|
/f28 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/01_struct
|
||||||
|
/f2b https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/02_validation
|
||||||
|
/f2m https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/03_modules
|
||||||
|
/f23 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/04_visibility
|
||||||
|
/f2q https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/05_encapsulation
|
||||||
|
/f25 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/06_ownership
|
||||||
|
/f2w https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/07_setters
|
||||||
|
/f29 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/08_stack
|
||||||
|
/f2p https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/09_heap
|
||||||
|
/f2l https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/10_references_in_memory
|
||||||
|
/f2g https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/11_destructor
|
||||||
|
/f2j https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/03_ticket_v1/12_outro
|
||||||
|
/f2d https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/00_intro
|
||||||
|
/f2a https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/01_trait
|
||||||
|
/fz2 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/02_orphan_rule
|
||||||
|
/fz3 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/03_operator_overloading
|
||||||
|
/fz7 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/04_derive
|
||||||
|
/fz9 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/05_trait_bounds
|
||||||
|
/fzr https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/06_str_slice
|
||||||
|
/fzy https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/07_deref
|
||||||
|
/fzu https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/08_sized
|
||||||
|
/fzk https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/09_from
|
||||||
|
/fzs https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/10_assoc_vs_generic
|
||||||
|
/fzh https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/11_clone
|
||||||
|
/fzg https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/12_copy
|
||||||
|
/fzj https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/13_drop
|
||||||
|
/fzc https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/04_traits/14_outro
|
||||||
|
/fza https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/00_intro
|
||||||
|
/f4f https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/01_enum
|
||||||
|
/f42 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/02_match
|
||||||
|
/f4z https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/03_variants_with_data
|
||||||
|
/f44 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/04_if_let
|
||||||
|
/f4x https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/05_nullability
|
||||||
|
/f46 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/06_fallibility
|
||||||
|
/f4v https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/07_unwrap
|
||||||
|
/f48 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/08_error_enums
|
||||||
|
/f4b https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/09_error_trait
|
||||||
|
/f43 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/10_packages
|
||||||
|
/f4w https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/11_dependencies
|
||||||
|
/f47 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/12_thiserror
|
||||||
|
/f4e https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/13_try_from
|
||||||
|
/f49 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/14_source
|
||||||
|
/f4y https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/05_ticket_v2/15_outro
|
||||||
|
/f4u https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/00_intro
|
||||||
|
/f4p https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/01_arrays
|
||||||
|
/f4l https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/02_vec
|
||||||
|
/f4k https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/03_resizing
|
||||||
|
/f4h https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/04_iterators
|
||||||
|
/f4g https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/05_iter
|
||||||
|
/f4a https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/06_lifetimes
|
||||||
|
/fxz https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/07_combinators
|
||||||
|
/fx4 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/08_impl_trait
|
||||||
|
/fxx https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/09_impl_trait_2
|
||||||
|
/fx6 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/10_slices
|
||||||
|
/fxv https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/11_mutable_slices
|
||||||
|
/fx8 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/12_two_states
|
||||||
|
/fxb https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/13_index
|
||||||
|
/fxn https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/14_index_mut
|
||||||
|
/fxm https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/15_hashmap
|
||||||
|
/fx3 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/06_ticket_management/16_btreemap
|
||||||
|
/fxq https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/00_intro
|
||||||
|
/fxw https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/01_threads
|
||||||
|
/fxe https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/02_static
|
||||||
|
/fx9 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/03_leak
|
||||||
|
/fxr https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/04_scoped_threads
|
||||||
|
/fxt https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/05_channels
|
||||||
|
/fxu https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/06_interior_mutability
|
||||||
|
/fxp https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/07_ack
|
||||||
|
/fxl https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/08_client
|
||||||
|
/fxk https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/09_bounded
|
||||||
|
/fxs https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/10_patch
|
||||||
|
/fxj https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/11_locks
|
||||||
|
/fxd https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/12_rw_lock
|
||||||
|
/fxc https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/13_without_channels
|
||||||
|
/fxa https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/07_threads/14_sync
|
||||||
|
/f6f https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/00_intro
|
||||||
|
/f62 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/01_async_fn
|
||||||
|
/f64 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/02_spawn
|
||||||
|
/f6x https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/03_runtime
|
||||||
|
/f66 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/04_future
|
||||||
|
/f68 https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/05_blocking
|
||||||
|
/f6b https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/06_async_aware_primitives
|
||||||
|
/f6q https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/07_cancellation
|
||||||
|
/f6e https://github.com/mainmatter/100-exercises-to-learn-rust/tree/main/exercises/08_futures/08_outro
|
||||||
|
/ffz https://github.com/mainmatter/100-exercises-to-learn-rust/tree/solutions
|
||||||
|
/fzd https://github.com/mainmatter/rust-advanced-testing-workshop
|
||||||
|
/f69 https://github.com/rust-lang/rustlings
|
||||||
|
/ffa https://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/
|
||||||
|
/f4r https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
|
||||||
|
/ff2 https://mainmatter.com/contact/
|
||||||
|
/fff https://mainmatter.com/rust-consulting/
|
||||||
|
/fxg https://marabos.nl/atomics/
|
||||||
|
/f6p https://nostarch.com/rust-rustaceans
|
||||||
|
/f2k https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory
|
||||||
|
/f2s https://owasp.org/www-community/vulnerabilities/Using_freed_memory
|
||||||
|
/ffn https://pavex.dev
|
||||||
|
/ffp https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=36e5ddbe3b3f741dfa9f74c956622bac
|
||||||
|
/fx5 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=afedf7062298ca8f5a248bc551062eaa
|
||||||
|
/ffx https://rust-exercises.com/100-exercises-to-learn-rust.pdf
|
||||||
|
/ff4 https://rust-exercises.com/100-exercises/
|
||||||
|
/f6s https://rust-exercises.com/advanced-testing/
|
||||||
|
/f6h https://rust-exercises.com/telemetry/
|
||||||
|
/fze https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case
|
||||||
|
/f6w https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_battles_buffered_streams.html
|
||||||
|
/f6v https://ryhl.io/blog/async-what-is-blocking/
|
||||||
|
/f6n https://tokio.rs/tokio/tutorial/select
|
||||||
|
/f2t https://valgrind.org/docs/manual/dh-manual.html
|
||||||
|
/fz5 https://veykril.github.io/tlborm/
|
||||||
|
/f67 https://without.boats/blog/the-scoped-task-trilemma/
|
||||||
|
/ffv https://www.lpalmieri.com/
|
||||||
|
/f4t https://www.lpalmieri.com/posts/2020-12-11-zero-to-production-6-domain-modelling/
|
||||||
|
/f6y https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/
|
||||||
|
/f6l https://www.youtube.com/playlist?list=PLqbS7AVVErFirH9armw8yXlE6dacF-A6z
|
||||||
|
/ff8 https://zero2prod.com
|
Loading…
Reference in New Issue