diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 000000000..5e3dd015f --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,6 @@ +coverage: + status: + patch: off + project: off +ignore: + - "test-binaries" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..b28e90ae7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..110315e11 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,47 @@ +name: Generate documentation +on: + push: + branches: + - main + +jobs: + doc: + name: Document + runs-on: ubuntu-latest + permissions: + contents: write # To push a branch + pull-requests: write # To create a PR from that branch + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install latest mdbook + run: | + tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name') + url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz" + mkdir mdbook + curl -sSL $url | tar -xz --directory=./mdbook + echo `pwd`/mdbook >> $GITHUB_PATH + - name: Install rust + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + - name: Generate reference manual + run: mdbook build docs + - name: Generate API documentation + run: cargo +nightly doc --workspace --no-deps --all-features --target-dir docs/api + - name: Deploy GitHub Pages + run: | + cd docs + git worktree add gh-pages + git config user.name "Deploy from CI" + git config user.email "" + cd gh-pages + git update-ref -d refs/heads/gh-pages + rm -rf * + mv ../book/* . + mkdir docs + mv ../api/doc/* docs + git add . + git commit -m "Deploy $GITHUB_SHA to gh-pages" + git push --force --set-upstream origin gh-pages diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 000000000..13bc0fc2f --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,124 @@ +name: Test and Check + +on: + push: + branches: [ main ] + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Build no-std + uses: actions-rs/cargo@v1 + with: + command: build + toolchain: stable + args: --no-default-features + + - name: Build stm32 + working-directory: statime-stm32 + run: cargo build + + # Build std is handled by test job + + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@v2 + with: + tool: cargo-llvm-cov + + - name: Run tests + run: cargo llvm-cov --all-features --lcov --output-path lcov.info + env: + RUST_BACKTRACE: 1 + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + files: lcov.info + fail_ci_if_error: false + + check: + name: Check style + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt, clippy + override: true + + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + toolchain: stable + args: --all --check + + - name: Run cargo clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + toolchain: stable + args: --workspace --all-features -- -D warnings + + - name: Run clippy (fuzzers) + uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 + with: + command: clippy + args: --manifest-path ./fuzz/Cargo.toml --all-targets -- -D warnings + + fuzz: + name: Smoke-test fuzzing targets + runs-on: ubuntu-20.04 + steps: + - name: Checkout sources + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Install stable toolchain + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af + with: + toolchain: nightly + override: true + default: true + - name: Install cargo fuzz + uses: taiki-e/install-action@70233fe3d27d863712ee34eede2087e36bde6b5e + with: + tool: cargo-fuzz + - name: Smoke-test fuzz targets + run: | + cargo fuzz build + for target in $(cargo fuzz list) ; do + cargo fuzz run $target -- -max_total_time=10 + done diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3b6b6caa0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +**/target +/docs/book +validation/measurement_report.aux +validation/measurement_report.fdb_latexmk +validation/measurement_report.fls +validation/measurement_report.log +validation-ht/measurement_report.aux +validation-ht/measurement_report.fdb_latexmk +validation-ht/measurement_report.fls +validation-ht/measurement_report.log +*swp +**/.idea diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 000000000..44024acab --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,10 @@ +unstable_features = true +format_macro_matchers = true +format_strings = true +hex_literal_case = "Lower" +imports_granularity = "Crate" +normalize_comments = true +normalize_doc_attributes = true +group_imports = "StdExternalCrate" +use_try_shorthand = true +wrap_comments = true diff --git a/404.html b/404.html new file mode 100644 index 000000000..b8b03d16d --- /dev/null +++ b/404.html @@ -0,0 +1,216 @@ + + + + + + Page not found - Statime Reference Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Document not found (404)

+

This URL is invalid, sorry. Please use the navigation bar or search to continue.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/FontAwesome/css/font-awesome.css b/FontAwesome/css/font-awesome.css new file mode 100644 index 000000000..540440ce8 --- /dev/null +++ b/FontAwesome/css/font-awesome.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/FontAwesome/fonts/FontAwesome.ttf b/FontAwesome/fonts/FontAwesome.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/FontAwesome/fonts/FontAwesome.ttf differ diff --git a/FontAwesome/fonts/fontawesome-webfont.eot b/FontAwesome/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.eot differ diff --git a/FontAwesome/fonts/fontawesome-webfont.svg b/FontAwesome/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/FontAwesome/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FontAwesome/fonts/fontawesome-webfont.ttf b/FontAwesome/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.ttf differ diff --git a/FontAwesome/fonts/fontawesome-webfont.woff b/FontAwesome/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.woff differ diff --git a/FontAwesome/fonts/fontawesome-webfont.woff2 b/FontAwesome/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.woff2 differ diff --git a/ayu-highlight.css b/ayu-highlight.css new file mode 100644 index 000000000..32c943222 --- /dev/null +++ b/ayu-highlight.css @@ -0,0 +1,78 @@ +/* +Based off of the Ayu theme +Original by Dempfi (https://github.com/dempfi/ayu) +*/ + +.hljs { + display: block; + overflow-x: auto; + background: #191f26; + color: #e6e1cf; +} + +.hljs-comment, +.hljs-quote { + color: #5c6773; + font-style: italic; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-attr, +.hljs-regexp, +.hljs-link, +.hljs-selector-id, +.hljs-selector-class { + color: #ff7733; +} + +.hljs-number, +.hljs-meta, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #ffee99; +} + +.hljs-string, +.hljs-bullet { + color: #b8cc52; +} + +.hljs-title, +.hljs-built_in, +.hljs-section { + color: #ffb454; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-symbol { + color: #ff7733; +} + +.hljs-name { + color: #36a3d9; +} + +.hljs-tag { + color: #00568d; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #91b362; +} + +.hljs-deletion { + color: #d96c75; +} diff --git a/book.js b/book.js new file mode 100644 index 000000000..aa12e7ecc --- /dev/null +++ b/book.js @@ -0,0 +1,697 @@ +"use strict"; + +// Fix back button cache problem +window.onunload = function () { }; + +// Global variable, shared between modules +function playground_text(playground, hidden = true) { + let code_block = playground.querySelector("code"); + + if (window.ace && code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + return editor.getValue(); + } else if (hidden) { + return code_block.textContent; + } else { + return code_block.innerText; + } +} + +(function codeSnippets() { + function fetch_with_timeout(url, options, timeout = 6000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); + } + + var playgrounds = Array.from(document.querySelectorAll(".playground")); + if (playgrounds.length > 0) { + fetch_with_timeout("https://play.rust-lang.org/meta/crates", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + }) + .then(response => response.json()) + .then(response => { + // get list of crates available in the rust playground + let playground_crates = response.crates.map(item => item["id"]); + playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); + }); + } + + function handle_crate_list_update(playground_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playground_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playground_block.querySelector("code"); + if (code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + editor.addEventListener("change", function (e) { + update_play_button(playground_block, playground_crates); + }); + // add Ctrl-Enter command to execute rust code + editor.commands.addCommand({ + name: "run", + bindKey: { + win: "Ctrl-Enter", + mac: "Ctrl-Enter" + }, + exec: _editor => run_rust_code(playground_block) + }); + } + } + } + + // updates the visibility of play button based on `no_run` class and + // used crates vs ones available on https://play.rust-lang.org + function update_play_button(pre_block, playground_crates) { + var play_button = pre_block.querySelector(".play-button"); + + // skip if code is `no_run` + if (pre_block.querySelector('code').classList.contains("no_run")) { + play_button.classList.add("hidden"); + return; + } + + // get list of `extern crate`'s from snippet + var txt = playground_text(pre_block); + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + var item; + while (item = re.exec(txt)) { + snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function (elem) { + return playground_crates.indexOf(elem) > -1; + }); + + if (all_available) { + play_button.classList.remove("hidden"); + } else { + play_button.classList.add("hidden"); + } + } + + function run_rust_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result hljs language-bash'; + + code_block.append(result_block); + } + + let text = playground_text(code_block); + let classes = code_block.querySelector('code').classList; + let edition = "2015"; + if(classes.contains("edition2018")) { + edition = "2018"; + } else if(classes.contains("edition2021")) { + edition = "2021"; + } + var params = { + version: "stable", + optimize: "0", + code: text, + edition: edition + }; + + if (text.indexOf("#![feature") !== -1) { + params.version = "nightly"; + } + + result_block.innerText = "Running..."; + + fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => { + if (response.result.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = response.result; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); + } + + // Syntax highlighting Configuration + hljs.configure({ + tabReplace: ' ', // 4 spaces + languages: [], // Languages used for auto-detection + }); + + let code_nodes = Array + .from(document.querySelectorAll('code')) + // Don't highlight `inline code` blocks in headers. + .filter(function (node) {return !node.parentElement.classList.contains("header"); }); + + if (window.ace) { + // language-rust class needs to be removed for editable + // blocks or highlightjs will capture events + code_nodes + .filter(function (node) {return node.classList.contains("editable"); }) + .forEach(function (block) { block.classList.remove('language-rust'); }); + + code_nodes + .filter(function (node) {return !node.classList.contains("editable"); }) + .forEach(function (block) { hljs.highlightBlock(block); }); + } else { + code_nodes.forEach(function (block) { hljs.highlightBlock(block); }); + } + + // Adding the hljs class gives code blocks the color css + // even if highlighting doesn't apply + code_nodes.forEach(function (block) { block.classList.add('hljs'); }); + + Array.from(document.querySelectorAll("code.hljs")).forEach(function (block) { + + var lines = Array.from(block.querySelectorAll('.boring')); + // If no lines were hidden, return + if (!lines.length) { return; } + block.classList.add("hide-boring"); + + var buttons = document.createElement('div'); + buttons.className = 'buttons'; + buttons.innerHTML = ""; + + // add expand button + var pre_block = block.parentNode; + pre_block.insertBefore(buttons, pre_block.firstChild); + + pre_block.querySelector('.buttons').addEventListener('click', function (e) { + if (e.target.classList.contains('fa-eye')) { + e.target.classList.remove('fa-eye'); + e.target.classList.add('fa-eye-slash'); + e.target.title = 'Hide lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.remove('hide-boring'); + } else if (e.target.classList.contains('fa-eye-slash')) { + e.target.classList.remove('fa-eye-slash'); + e.target.classList.add('fa-eye'); + e.target.title = 'Show hidden lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.add('hide-boring'); + } + }); + }); + + if (window.playground_copyable) { + Array.from(document.querySelectorAll('pre code')).forEach(function (block) { + var pre_block = block.parentNode; + if (!pre_block.classList.contains('playground')) { + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var clipButton = document.createElement('button'); + clipButton.className = 'fa fa-copy clip-button'; + clipButton.title = 'Copy to clipboard'; + clipButton.setAttribute('aria-label', clipButton.title); + clipButton.innerHTML = ''; + + buttons.insertBefore(clipButton, buttons.firstChild); + } + }); + } + + // Process playground code blocks + Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { + // Add play button + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var runCodeButton = document.createElement('button'); + runCodeButton.className = 'fa fa-play play-button'; + runCodeButton.hidden = true; + runCodeButton.title = 'Run this code'; + runCodeButton.setAttribute('aria-label', runCodeButton.title); + + buttons.insertBefore(runCodeButton, buttons.firstChild); + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + if (window.playground_copyable) { + var copyCodeClipboardButton = document.createElement('button'); + copyCodeClipboardButton.className = 'fa fa-copy clip-button'; + copyCodeClipboardButton.innerHTML = ''; + copyCodeClipboardButton.title = 'Copy to clipboard'; + copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title); + + buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild); + } + + let code_block = pre_block.querySelector("code"); + if (window.ace && code_block.classList.contains("editable")) { + var undoChangesButton = document.createElement('button'); + undoChangesButton.className = 'fa fa-history reset-button'; + undoChangesButton.title = 'Undo changes'; + undoChangesButton.setAttribute('aria-label', undoChangesButton.title); + + buttons.insertBefore(undoChangesButton, buttons.firstChild); + + undoChangesButton.addEventListener('click', function () { + let editor = window.ace.edit(code_block); + editor.setValue(editor.originalCode); + editor.clearSelection(); + }); + } + }); +})(); + +(function themes() { + var html = document.querySelector('html'); + var themeToggleButton = document.getElementById('theme-toggle'); + var themePopup = document.getElementById('theme-list'); + var themeColorMetaTag = document.querySelector('meta[name="theme-color"]'); + var stylesheets = { + ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"), + tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"), + highlight: document.querySelector("[href$='highlight.css']"), + }; + + function showThemes() { + themePopup.style.display = 'block'; + themeToggleButton.setAttribute('aria-expanded', true); + themePopup.querySelector("button#" + get_theme()).focus(); + } + + function updateThemeSelected() { + themePopup.querySelectorAll('.theme-selected').forEach(function (el) { + el.classList.remove('theme-selected'); + }); + themePopup.querySelector("button#" + get_theme()).classList.add('theme-selected'); + } + + function hideThemes() { + themePopup.style.display = 'none'; + themeToggleButton.setAttribute('aria-expanded', false); + themeToggleButton.focus(); + } + + function get_theme() { + var theme; + try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { } + if (theme === null || theme === undefined) { + return default_theme; + } else { + return theme; + } + } + + function set_theme(theme, store = true) { + let ace_theme; + + if (theme == 'coal' || theme == 'navy') { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = false; + stylesheets.highlight.disabled = true; + + ace_theme = "ace/theme/tomorrow_night"; + } else if (theme == 'ayu') { + stylesheets.ayuHighlight.disabled = false; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = true; + ace_theme = "ace/theme/tomorrow_night"; + } else { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = false; + ace_theme = "ace/theme/dawn"; + } + + setTimeout(function () { + themeColorMetaTag.content = getComputedStyle(document.documentElement).backgroundColor; + }, 1); + + if (window.ace && window.editors) { + window.editors.forEach(function (editor) { + editor.setTheme(ace_theme); + }); + } + + var previousTheme = get_theme(); + + if (store) { + try { localStorage.setItem('mdbook-theme', theme); } catch (e) { } + } + + html.classList.remove(previousTheme); + html.classList.add(theme); + updateThemeSelected(); + } + + // Set theme + var theme = get_theme(); + + set_theme(theme, false); + + themeToggleButton.addEventListener('click', function () { + if (themePopup.style.display === 'block') { + hideThemes(); + } else { + showThemes(); + } + }); + + themePopup.addEventListener('click', function (e) { + var theme; + if (e.target.className === "theme") { + theme = e.target.id; + } else if (e.target.parentElement.className === "theme") { + theme = e.target.parentElement.id; + } else { + return; + } + set_theme(theme); + }); + + themePopup.addEventListener('focusout', function(e) { + // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below) + if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) { + hideThemes(); + } + }); + + // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628 + document.addEventListener('click', function(e) { + if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) { + hideThemes(); + } + }); + + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (!themePopup.contains(e.target)) { return; } + + switch (e.key) { + case 'Escape': + e.preventDefault(); + hideThemes(); + break; + case 'ArrowUp': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.previousElementSibling) { + li.previousElementSibling.querySelector('button').focus(); + } + break; + case 'ArrowDown': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.nextElementSibling) { + li.nextElementSibling.querySelector('button').focus(); + } + break; + case 'Home': + e.preventDefault(); + themePopup.querySelector('li:first-child button').focus(); + break; + case 'End': + e.preventDefault(); + themePopup.querySelector('li:last-child button').focus(); + break; + } + }); +})(); + +(function sidebar() { + var body = document.querySelector("body"); + var sidebar = document.getElementById("sidebar"); + var sidebarLinks = document.querySelectorAll('#sidebar a'); + var sidebarToggleButton = document.getElementById("sidebar-toggle"); + var sidebarResizeHandle = document.getElementById("sidebar-resize-handle"); + var firstContact = null; + + function showSidebar() { + body.classList.remove('sidebar-hidden') + body.classList.add('sidebar-visible'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', 0); + }); + sidebarToggleButton.setAttribute('aria-expanded', true); + sidebar.setAttribute('aria-hidden', false); + try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { } + } + + + var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle'); + + function toggleSection(ev) { + ev.currentTarget.parentElement.classList.toggle('expanded'); + } + + Array.from(sidebarAnchorToggles).forEach(function (el) { + el.addEventListener('click', toggleSection); + }); + + function hideSidebar() { + body.classList.remove('sidebar-visible') + body.classList.add('sidebar-hidden'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', -1); + }); + sidebarToggleButton.setAttribute('aria-expanded', false); + sidebar.setAttribute('aria-hidden', true); + try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { } + } + + // Toggle sidebar + sidebarToggleButton.addEventListener('click', function sidebarToggle() { + if (body.classList.contains("sidebar-hidden")) { + var current_width = parseInt( + document.documentElement.style.getPropertyValue('--sidebar-width'), 10); + if (current_width < 150) { + document.documentElement.style.setProperty('--sidebar-width', '150px'); + } + showSidebar(); + } else if (body.classList.contains("sidebar-visible")) { + hideSidebar(); + } else { + if (getComputedStyle(sidebar)['transform'] === 'none') { + hideSidebar(); + } else { + showSidebar(); + } + } + }); + + sidebarResizeHandle.addEventListener('mousedown', initResize, false); + + function initResize(e) { + window.addEventListener('mousemove', resize, false); + window.addEventListener('mouseup', stopResize, false); + body.classList.add('sidebar-resizing'); + } + function resize(e) { + var pos = (e.clientX - sidebar.offsetLeft); + if (pos < 20) { + hideSidebar(); + } else { + if (body.classList.contains("sidebar-hidden")) { + showSidebar(); + } + pos = Math.min(pos, window.innerWidth - 100); + document.documentElement.style.setProperty('--sidebar-width', pos + 'px'); + } + } + //on mouseup remove windows functions mousemove & mouseup + function stopResize(e) { + body.classList.remove('sidebar-resizing'); + window.removeEventListener('mousemove', resize, false); + window.removeEventListener('mouseup', stopResize, false); + } + + document.addEventListener('touchstart', function (e) { + firstContact = { + x: e.touches[0].clientX, + time: Date.now() + }; + }, { passive: true }); + + document.addEventListener('touchmove', function (e) { + if (!firstContact) + return; + + var curX = e.touches[0].clientX; + var xDiff = curX - firstContact.x, + tDiff = Date.now() - firstContact.time; + + if (tDiff < 250 && Math.abs(xDiff) >= 150) { + if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) + showSidebar(); + else if (xDiff < 0 && curX < 300) + hideSidebar(); + + firstContact = null; + } + }, { passive: true }); +})(); + +(function chapterNavigation() { + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (window.search && window.search.hasFocus()) { return; } + var html = document.querySelector('html'); + + function next() { + var nextButton = document.querySelector('.nav-chapters.next'); + if (nextButton) { + window.location.href = nextButton.href; + } + } + function prev() { + var previousButton = document.querySelector('.nav-chapters.previous'); + if (previousButton) { + window.location.href = previousButton.href; + } + } + switch (e.key) { + case 'ArrowRight': + e.preventDefault(); + if (html.dir == 'rtl') { + prev(); + } else { + next(); + } + break; + case 'ArrowLeft': + e.preventDefault(); + if (html.dir == 'rtl') { + next(); + } else { + prev(); + } + break; + } + }); +})(); + +(function clipboard() { + var clipButtons = document.querySelectorAll('.clip-button'); + + function hideTooltip(elem) { + elem.firstChild.innerText = ""; + elem.className = 'fa fa-copy clip-button'; + } + + function showTooltip(elem, msg) { + elem.firstChild.innerText = msg; + elem.className = 'fa fa-copy tooltipped'; + } + + var clipboardSnippets = new ClipboardJS('.clip-button', { + text: function (trigger) { + hideTooltip(trigger); + let playground = trigger.closest("pre"); + return playground_text(playground, false); + } + }); + + Array.from(clipButtons).forEach(function (clipButton) { + clipButton.addEventListener('mouseout', function (e) { + hideTooltip(e.currentTarget); + }); + }); + + clipboardSnippets.on('success', function (e) { + e.clearSelection(); + showTooltip(e.trigger, "Copied!"); + }); + + clipboardSnippets.on('error', function (e) { + showTooltip(e.trigger, "Clipboard error!"); + }); +})(); + +(function scrollToTop () { + var menuTitle = document.querySelector('.menu-title'); + + menuTitle.addEventListener('click', function () { + document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' }); + }); +})(); + +(function controllMenu() { + var menu = document.getElementById('menu-bar'); + + (function controllPosition() { + var scrollTop = document.scrollingElement.scrollTop; + var prevScrollTop = scrollTop; + var minMenuY = -menu.clientHeight - 50; + // When the script loads, the page can be at any scroll (e.g. if you reforesh it). + menu.style.top = scrollTop + 'px'; + // Same as parseInt(menu.style.top.slice(0, -2), but faster + var topCache = menu.style.top.slice(0, -2); + menu.classList.remove('sticky'); + var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster + document.addEventListener('scroll', function () { + scrollTop = Math.max(document.scrollingElement.scrollTop, 0); + // `null` means that it doesn't need to be updated + var nextSticky = null; + var nextTop = null; + var scrollDown = scrollTop > prevScrollTop; + var menuPosAbsoluteY = topCache - scrollTop; + if (scrollDown) { + nextSticky = false; + if (menuPosAbsoluteY > 0) { + nextTop = prevScrollTop; + } + } else { + if (menuPosAbsoluteY > 0) { + nextSticky = true; + } else if (menuPosAbsoluteY < minMenuY) { + nextTop = prevScrollTop + minMenuY; + } + } + if (nextSticky === true && stickyCache === false) { + menu.classList.add('sticky'); + stickyCache = true; + } else if (nextSticky === false && stickyCache === true) { + menu.classList.remove('sticky'); + stickyCache = false; + } + if (nextTop !== null) { + menu.style.top = nextTop + 'px'; + topCache = nextTop; + } + prevScrollTop = scrollTop; + }, { passive: true }); + })(); + (function controllBorder() { + function updateBorder() { + if (menu.offsetTop === 0) { + menu.classList.remove('bordered'); + } else { + menu.classList.add('bordered'); + } + } + updateBorder(); + document.addEventListener('scroll', updateBorder, { passive: true }); + })(); +})(); diff --git a/clipboard.min.js b/clipboard.min.js new file mode 100644 index 000000000..02c549e35 --- /dev/null +++ b/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.4 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n .hljs { + color: var(--links); +} + +/* + body-container is necessary because mobile browsers don't seem to like + overflow-x on the body tag when there is a tag. +*/ +#body-container { + /* + This is used when the sidebar pushes the body content off the side of + the screen on small screens. Without it, dragging on mobile Safari + will want to reposition the viewport in a weird way. + */ + overflow-x: clip; +} + +/* Menu Bar */ + +#menu-bar, +#menu-bar-hover-placeholder { + z-index: 101; + margin: auto calc(0px - var(--page-padding)); +} +#menu-bar { + position: relative; + display: flex; + flex-wrap: wrap; + background-color: var(--bg); + border-block-end-color: var(--bg); + border-block-end-width: 1px; + border-block-end-style: solid; +} +#menu-bar.sticky, +.js #menu-bar-hover-placeholder:hover + #menu-bar, +.js #menu-bar:hover, +.js.sidebar-visible #menu-bar { + position: -webkit-sticky; + position: sticky; + top: 0 !important; +} +#menu-bar-hover-placeholder { + position: sticky; + position: -webkit-sticky; + top: 0; + height: var(--menu-bar-height); +} +#menu-bar.bordered { + border-block-end-color: var(--table-border-color); +} +#menu-bar i, #menu-bar .icon-button { + position: relative; + padding: 0 8px; + z-index: 10; + line-height: var(--menu-bar-height); + cursor: pointer; + transition: color 0.5s; +} +@media only screen and (max-width: 420px) { + #menu-bar i, #menu-bar .icon-button { + padding: 0 5px; + } +} + +.icon-button { + border: none; + background: none; + padding: 0; + color: inherit; +} +.icon-button i { + margin: 0; +} + +.right-buttons { + margin: 0 15px; +} +.right-buttons a { + text-decoration: none; +} + +.left-buttons { + display: flex; + margin: 0 5px; +} +.no-js .left-buttons button { + display: none; +} + +.menu-title { + display: inline-block; + font-weight: 200; + font-size: 2.4rem; + line-height: var(--menu-bar-height); + text-align: center; + margin: 0; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.js .menu-title { + cursor: pointer; +} + +.menu-bar, +.menu-bar:visited, +.nav-chapters, +.nav-chapters:visited, +.mobile-nav-chapters, +.mobile-nav-chapters:visited, +.menu-bar .icon-button, +.menu-bar a i { + color: var(--icons); +} + +.menu-bar i:hover, +.menu-bar .icon-button:hover, +.nav-chapters:hover, +.mobile-nav-chapters i:hover { + color: var(--icons-hover); +} + +/* Nav Icons */ + +.nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + + position: fixed; + top: 0; + bottom: 0; + margin: 0; + max-width: 150px; + min-width: 90px; + + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + + transition: color 0.5s, background-color 0.5s; +} + +.nav-chapters:hover { + text-decoration: none; + background-color: var(--theme-hover); + transition: background-color 0.15s, color 0.15s; +} + +.nav-wrapper { + margin-block-start: 50px; + display: none; +} + +.mobile-nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + width: 90px; + border-radius: 5px; + background-color: var(--sidebar-bg); +} + +/* Only Firefox supports flow-relative values */ +.previous { float: left; } +[dir=rtl] .previous { float: right; } + +/* Only Firefox supports flow-relative values */ +.next { + float: right; + right: var(--page-padding); +} +[dir=rtl] .next { + float: left; + right: unset; + left: var(--page-padding); +} + +/* Use the correct buttons for RTL layouts*/ +[dir=rtl] .previous i.fa-angle-left:before {content:"\f105";} +[dir=rtl] .next i.fa-angle-right:before { content:"\f104"; } + +@media only screen and (max-width: 1080px) { + .nav-wide-wrapper { display: none; } + .nav-wrapper { display: block; } +} + +/* sidebar-visible */ +@media only screen and (max-width: 1380px) { + #sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wide-wrapper { display: none; } + #sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wrapper { display: block; } +} + +/* Inline code */ + +:not(pre) > .hljs { + display: inline; + padding: 0.1em 0.3em; + border-radius: 3px; +} + +:not(pre):not(a) > .hljs { + color: var(--inline-code-color); + overflow-x: initial; +} + +a:hover > .hljs { + text-decoration: underline; +} + +pre { + position: relative; +} +pre > .buttons { + position: absolute; + z-index: 100; + right: 0px; + top: 2px; + margin: 0px; + padding: 2px 0px; + + color: var(--sidebar-fg); + cursor: pointer; + visibility: hidden; + opacity: 0; + transition: visibility 0.1s linear, opacity 0.1s linear; +} +pre:hover > .buttons { + visibility: visible; + opacity: 1 +} +pre > .buttons :hover { + color: var(--sidebar-active); + border-color: var(--icons-hover); + background-color: var(--theme-hover); +} +pre > .buttons i { + margin-inline-start: 8px; +} +pre > .buttons button { + cursor: inherit; + margin: 0px 5px; + padding: 3px 5px; + font-size: 14px; + + border-style: solid; + border-width: 1px; + border-radius: 4px; + border-color: var(--icons); + background-color: var(--theme-popup-bg); + transition: 100ms; + transition-property: color,border-color,background-color; + color: var(--icons); +} +@media (pointer: coarse) { + pre > .buttons button { + /* On mobile, make it easier to tap buttons. */ + padding: 0.3rem 1rem; + } +} +pre > code { + padding: 1rem; +} + +/* FIXME: ACE editors overlap their buttons because ACE does absolute + positioning within the code block which breaks padding. The only solution I + can think of is to move the padding to the outer pre tag (or insert a div + wrapper), but that would require fixing a whole bunch of CSS rules. +*/ +.hljs.ace_editor { + padding: 0rem 0rem; +} + +pre > .result { + margin-block-start: 10px; +} + +/* Search */ + +#searchresults a { + text-decoration: none; +} + +mark { + border-radius: 2px; + padding-block-start: 0; + padding-block-end: 1px; + padding-inline-start: 3px; + padding-inline-end: 3px; + margin-block-start: 0; + margin-block-end: -1px; + margin-inline-start: -3px; + margin-inline-end: -3px; + background-color: var(--search-mark-bg); + transition: background-color 300ms linear; + cursor: pointer; +} + +mark.fade-out { + background-color: rgba(0,0,0,0) !important; + cursor: auto; +} + +.searchbar-outer { + margin-inline-start: auto; + margin-inline-end: auto; + max-width: var(--content-max-width); +} + +#searchbar { + width: 100%; + margin-block-start: 5px; + margin-block-end: 0; + margin-inline-start: auto; + margin-inline-end: auto; + padding: 10px 16px; + transition: box-shadow 300ms ease-in-out; + border: 1px solid var(--searchbar-border-color); + border-radius: 3px; + background-color: var(--searchbar-bg); + color: var(--searchbar-fg); +} +#searchbar:focus, +#searchbar.active { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +.searchresults-header { + font-weight: bold; + font-size: 1em; + padding-block-start: 18px; + padding-block-end: 0; + padding-inline-start: 5px; + padding-inline-end: 0; + color: var(--searchresults-header-fg); +} + +.searchresults-outer { + margin-inline-start: auto; + margin-inline-end: auto; + max-width: var(--content-max-width); + border-block-end: 1px dashed var(--searchresults-border-color); +} + +ul#searchresults { + list-style: none; + padding-inline-start: 20px; +} +ul#searchresults li { + margin: 10px 0px; + padding: 2px; + border-radius: 2px; +} +ul#searchresults li.focus { + background-color: var(--searchresults-li-bg); +} +ul#searchresults span.teaser { + display: block; + clear: both; + margin-block-start: 5px; + margin-block-end: 0; + margin-inline-start: 20px; + margin-inline-end: 0; + font-size: 0.8em; +} +ul#searchresults span.teaser em { + font-weight: bold; + font-style: normal; +} + +/* Sidebar */ + +.sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: var(--sidebar-width); + font-size: 0.875em; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; + overscroll-behavior-y: contain; + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +[dir=rtl] .sidebar { left: unset; right: 0; } +.sidebar-resizing { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} +.no-js .sidebar, +.js:not(.sidebar-resizing) .sidebar { + transition: transform 0.3s; /* Animation: slide away */ +} +.sidebar code { + line-height: 2em; +} +.sidebar .sidebar-scrollbox { + overflow-y: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + padding: 10px 10px; +} +.sidebar .sidebar-resize-handle { + position: absolute; + cursor: col-resize; + width: 0; + right: 0; + top: 0; + bottom: 0; +} +[dir=rtl] .sidebar .sidebar-resize-handle { right: unset; left: 0; } +.js .sidebar .sidebar-resize-handle { + cursor: col-resize; + width: 5px; +} +/* sidebar-hidden */ +#sidebar-toggle-anchor:not(:checked) ~ .sidebar { + transform: translateX(calc(0px - var(--sidebar-width))); + z-index: -1; +} +[dir=rtl] #sidebar-toggle-anchor:not(:checked) ~ .sidebar { + transform: translateX(var(--sidebar-width)); +} +.sidebar::-webkit-scrollbar { + background: var(--sidebar-bg); +} +.sidebar::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} + +/* sidebar-visible */ +#sidebar-toggle-anchor:checked ~ .page-wrapper { + transform: translateX(var(--sidebar-width)); +} +[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper { + transform: translateX(calc(0px - var(--sidebar-width))); +} +@media only screen and (min-width: 620px) { + #sidebar-toggle-anchor:checked ~ .page-wrapper { + transform: none; + margin-inline-start: var(--sidebar-width); + } + [dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper { + transform: none; + } +} + +.chapter { + list-style: none outside none; + padding-inline-start: 0; + line-height: 2.2em; +} + +.chapter ol { + width: 100%; +} + +.chapter li { + display: flex; + color: var(--sidebar-non-existant); +} +.chapter li a { + display: block; + padding: 0; + text-decoration: none; + color: var(--sidebar-fg); +} + +.chapter li a:hover { + color: var(--sidebar-active); +} + +.chapter li a.active { + color: var(--sidebar-active); +} + +.chapter li > a.toggle { + cursor: pointer; + display: block; + margin-inline-start: auto; + padding: 0 10px; + user-select: none; + opacity: 0.68; +} + +.chapter li > a.toggle div { + transition: transform 0.5s; +} + +/* collapse the section */ +.chapter li:not(.expanded) + li > ol { + display: none; +} + +.chapter li.chapter-item { + line-height: 1.5em; + margin-block-start: 0.6em; +} + +.chapter li.expanded > a.toggle div { + transform: rotate(90deg); +} + +.spacer { + width: 100%; + height: 3px; + margin: 5px 0px; +} +.chapter .spacer { + background-color: var(--sidebar-spacer); +} + +@media (-moz-touch-enabled: 1), (pointer: coarse) { + .chapter li a { padding: 5px 0; } + .spacer { margin: 10px 0; } +} + +.section { + list-style: none outside none; + padding-inline-start: 20px; + line-height: 1.9em; +} + +/* Theme Menu Popup */ + +.theme-popup { + position: absolute; + left: 10px; + top: var(--menu-bar-height); + z-index: 1000; + border-radius: 4px; + font-size: 0.7em; + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); + margin: 0; + padding: 0; + list-style: none; + display: none; + /* Don't let the children's background extend past the rounded corners. */ + overflow: hidden; +} +[dir=rtl] .theme-popup { left: unset; right: 10px; } +.theme-popup .default { + color: var(--icons); +} +.theme-popup .theme { + width: 100%; + border: 0; + margin: 0; + padding: 2px 20px; + line-height: 25px; + white-space: nowrap; + text-align: start; + cursor: pointer; + color: inherit; + background: inherit; + font-size: inherit; +} +.theme-popup .theme:hover { + background-color: var(--theme-hover); +} + +.theme-selected::before { + display: inline-block; + content: "✓"; + margin-inline-start: -14px; + width: 14px; +} diff --git a/css/general.css b/css/general.css new file mode 100644 index 000000000..e7d20da72 --- /dev/null +++ b/css/general.css @@ -0,0 +1,234 @@ +/* Base styles and content styles */ + +@import 'variables.css'; + +:root { + /* Browser default font-size is 16px, this way 1 rem = 10px */ + font-size: 62.5%; + color-scheme: var(--color-scheme); +} + +html { + font-family: "Open Sans", sans-serif; + color: var(--fg); + background-color: var(--bg); + text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + margin: 0; + font-size: 1.6rem; + overflow-x: hidden; +} + +code { + font-family: var(--mono-font) !important; + font-size: var(--code-font-size); + direction: ltr !important; +} + +/* make long words/inline code not x overflow */ +main { + overflow-wrap: break-word; +} + +/* make wide tables scroll if they overflow */ +.table-wrapper { + overflow-x: auto; +} + +/* Don't change font size in headers. */ +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + font-size: unset; +} + +.left { float: left; } +.right { float: right; } +.boring { opacity: 0.6; } +.hide-boring .boring { display: none; } +.hidden { display: none !important; } + +h2, h3 { margin-block-start: 2.5em; } +h4, h5 { margin-block-start: 2em; } + +.header + .header h3, +.header + .header h4, +.header + .header h5 { + margin-block-start: 1em; +} + +h1:target::before, +h2:target::before, +h3:target::before, +h4:target::before, +h5:target::before, +h6:target::before { + display: inline-block; + content: "»"; + margin-inline-start: -30px; + width: 30px; +} + +/* This is broken on Safari as of version 14, but is fixed + in Safari Technology Preview 117 which I think will be Safari 14.2. + https://bugs.webkit.org/show_bug.cgi?id=218076 +*/ +:target { + /* Safari does not support logical properties */ + scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); +} + +.page { + outline: 0; + padding: 0 var(--page-padding); + margin-block-start: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ +} +.page-wrapper { + box-sizing: border-box; + background-color: var(--bg); +} +.no-js .page-wrapper, +.js:not(.sidebar-resizing) .page-wrapper { + transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} +[dir=rtl] .js:not(.sidebar-resizing) .page-wrapper { + transition: margin-right 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} + +.content { + overflow-y: auto; + padding: 0 5px 50px 5px; +} +.content main { + margin-inline-start: auto; + margin-inline-end: auto; + max-width: var(--content-max-width); +} +.content p { line-height: 1.45em; } +.content ol { line-height: 1.45em; } +.content ul { line-height: 1.45em; } +.content a { text-decoration: none; } +.content a:hover { text-decoration: underline; } +.content img, .content video { max-width: 100%; } +.content .header:link, +.content .header:visited { + color: var(--fg); +} +.content .header:link, +.content .header:visited:hover { + text-decoration: none; +} + +table { + margin: 0 auto; + border-collapse: collapse; +} +table td { + padding: 3px 20px; + border: 1px var(--table-border-color) solid; +} +table thead { + background: var(--table-header-bg); +} +table thead td { + font-weight: 700; + border: none; +} +table thead th { + padding: 3px 20px; +} +table thead tr { + border: 1px var(--table-header-bg) solid; +} +/* Alternate background colors for rows */ +table tbody tr:nth-child(2n) { + background: var(--table-alternate-bg); +} + + +blockquote { + margin: 20px 0; + padding: 0 20px; + color: var(--fg); + background-color: var(--quote-bg); + border-block-start: .1em solid var(--quote-border); + border-block-end: .1em solid var(--quote-border); +} + +.warning { + margin: 20px; + padding: 0 20px; + border-inline-start: 2px solid var(--warning-border); +} + +.warning:before { + position: absolute; + width: 3rem; + height: 3rem; + margin-inline-start: calc(-1.5rem - 21px); + content: "ⓘ"; + text-align: center; + background-color: var(--bg); + color: var(--warning-border); + font-weight: bold; + font-size: 2rem; +} + +blockquote .warning:before { + background-color: var(--quote-bg); +} + +kbd { + background-color: var(--table-border-color); + border-radius: 4px; + border: solid 1px var(--theme-popup-border); + box-shadow: inset 0 -1px 0 var(--theme-hover); + display: inline-block; + font-size: var(--code-font-size); + font-family: var(--mono-font); + line-height: 10px; + padding: 4px 5px; + vertical-align: middle; +} + +:not(.footnote-definition) + .footnote-definition, +.footnote-definition + :not(.footnote-definition) { + margin-block-start: 2em; +} +.footnote-definition { + font-size: 0.9em; + margin: 0.5em 0; +} +.footnote-definition p { + display: inline; +} + +.tooltiptext { + position: absolute; + visibility: hidden; + color: #fff; + background-color: #333; + transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ + left: -8px; /* Half of the width of the icon */ + top: -35px; + font-size: 0.8em; + text-align: center; + border-radius: 6px; + padding: 5px 8px; + margin: 5px; + z-index: 1000; +} +.tooltipped .tooltiptext { + visibility: visible; +} + +.chapter li.part-title { + color: var(--sidebar-fg); + margin: 5px 0px; + font-weight: bold; +} + +.result-no-output { + font-style: italic; +} diff --git a/css/print.css b/css/print.css new file mode 100644 index 000000000..dcf0ba64b --- /dev/null +++ b/css/print.css @@ -0,0 +1,50 @@ + +#sidebar, +#menu-bar, +.nav-chapters, +.mobile-nav-chapters { + display: none; +} + +#page-wrapper.page-wrapper { + transform: none; + margin-inline-start: 0px; + overflow-y: initial; +} + +#content { + max-width: none; + margin: 0; + padding: 0; +} + +.page { + overflow-y: initial; +} + +code { + direction: ltr !important; +} + +pre > .buttons { + z-index: 2; +} + +a, a:visited, a:active, a:hover { + color: #4183c4; + text-decoration: none; +} + +h1, h2, h3, h4, h5, h6 { + page-break-inside: avoid; + page-break-after: avoid; +} + +pre, code { + page-break-inside: avoid; + white-space: pre-wrap; +} + +.fa { + display: none !important; +} diff --git a/css/variables.css b/css/variables.css new file mode 100644 index 000000000..10a759094 --- /dev/null +++ b/css/variables.css @@ -0,0 +1,277 @@ + +/* Globals */ + +:root { + --sidebar-width: 300px; + --page-padding: 15px; + --content-max-width: 750px; + --menu-bar-height: 50px; + --mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace; + --code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */ +} + +/* Themes */ + +.ayu { + --bg: hsl(210, 25%, 8%); + --fg: #c5c5c5; + + --sidebar-bg: #14191f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #5c6773; + --sidebar-active: #ffb454; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #0096cf; + + --inline-code-color: #ffb454; + + --theme-popup-bg: #14191f; + --theme-popup-border: #5c6773; + --theme-hover: #191f26; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --warning-border: #ff8e00; + + --table-border-color: hsl(210, 25%, 13%); + --table-header-bg: hsl(210, 25%, 28%); + --table-alternate-bg: hsl(210, 25%, 11%); + + --searchbar-border-color: #848484; + --searchbar-bg: #424242; + --searchbar-fg: #fff; + --searchbar-shadow-color: #d4c89f; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #252932; + --search-mark-bg: #e3b171; + + --color-scheme: dark; +} + +.coal { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --warning-border: #ff8e00; + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + + --color-scheme: dark; +} + +.light { + --bg: hsl(0, 0%, 100%); + --fg: hsl(0, 0%, 0%); + + --sidebar-bg: #fafafa; + --sidebar-fg: hsl(0, 0%, 0%); + --sidebar-non-existant: #aaaaaa; + --sidebar-active: #1f1fff; + --sidebar-spacer: #f4f4f4; + + --scrollbar: #8F8F8F; + + --icons: #747474; + --icons-hover: #000000; + + --links: #20609f; + + --inline-code-color: #301900; + + --theme-popup-bg: #fafafa; + --theme-popup-border: #cccccc; + --theme-hover: #e6e6e6; + + --quote-bg: hsl(197, 37%, 96%); + --quote-border: hsl(197, 37%, 91%); + + --warning-border: #ff8e00; + + --table-border-color: hsl(0, 0%, 95%); + --table-header-bg: hsl(0, 0%, 80%); + --table-alternate-bg: hsl(0, 0%, 97%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #e4f2fe; + --search-mark-bg: #a2cff5; + + --color-scheme: light; +} + +.navy { + --bg: hsl(226, 23%, 11%); + --fg: #bcbdd0; + + --sidebar-bg: #282d3f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505274; + --sidebar-active: #2b79a2; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #161923; + --theme-popup-border: #737480; + --theme-hover: #282e40; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --warning-border: #ff8e00; + + --table-border-color: hsl(226, 23%, 16%); + --table-header-bg: hsl(226, 23%, 31%); + --table-alternate-bg: hsl(226, 23%, 14%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #aeaec6; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #5f5f71; + --searchresults-border-color: #5c5c68; + --searchresults-li-bg: #242430; + --search-mark-bg: #a2cff5; + + --color-scheme: dark; +} + +.rust { + --bg: hsl(60, 9%, 87%); + --fg: #262625; + + --sidebar-bg: #3b2e2a; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505254; + --sidebar-active: #e69f67; + --sidebar-spacer: #45373a; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #262625; + + --links: #2b79a2; + + --inline-code-color: #6e6b5e; + + --theme-popup-bg: #e1e1db; + --theme-popup-border: #b38f6b; + --theme-hover: #99908a; + + --quote-bg: hsl(60, 5%, 75%); + --quote-border: hsl(60, 5%, 70%); + + --warning-border: #ff8e00; + + --table-border-color: hsl(60, 9%, 82%); + --table-header-bg: #b3a497; + --table-alternate-bg: hsl(60, 9%, 84%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #dec2a2; + --search-mark-bg: #e69f67; + + --color-scheme: light; +} + +@media (prefers-color-scheme: dark) { + .light.no-js { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --warning-border: #ff8e00; + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + } +} diff --git a/docs/crates.js b/docs/crates.js new file mode 100644 index 000000000..c4c4491a2 --- /dev/null +++ b/docs/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["statime","statime_linux"]; \ No newline at end of file diff --git a/docs/help.html b/docs/help.html new file mode 100644 index 000000000..421276008 --- /dev/null +++ b/docs/help.html @@ -0,0 +1 @@ +Rustdoc help

Rustdoc help

Back
\ No newline at end of file diff --git a/docs/implementors/clock_steering/trait.Clock.js b/docs/implementors/clock_steering/trait.Clock.js new file mode 100644 index 000000000..4352a61e6 --- /dev/null +++ b/docs/implementors/clock_steering/trait.Clock.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime_linux":[["impl Clock for LinuxClock"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/clone/trait.Clone.js b/docs/implementors/core/clone/trait.Clone.js new file mode 100644 index 000000000..17d2b3675 --- /dev/null +++ b/docs/implementors/core/clone/trait.Clone.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Clone for ClockAccuracy"],["impl Clone for Time"],["impl Clone for LeapIndicator"],["impl Clone for SdoId"],["impl Clone for ClockQuality"],["impl Clone for InstanceConfig"],["impl Clone for Duration"],["impl<'a> Clone for FuzzMessage<'a>"],["impl Clone for Measurement"],["impl Clone for Interval"],["impl Clone for TimeSource"],["impl Clone for TimePropertiesDS"],["impl<A: Clone> Clone for PortConfig<A>"],["impl Clone for DelayMechanism"],["impl Clone for ClockIdentity"]], +"statime_linux":[["impl Clone for PortConfig"],["impl Clone for LinuxClock"],["impl Clone for Config"],["impl Clone for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.Eq.js b/docs/implementors/core/cmp/trait.Eq.js new file mode 100644 index 000000000..cc664f5f0 --- /dev/null +++ b/docs/implementors/core/cmp/trait.Eq.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Eq for TimePropertiesDS"],["impl<A: Eq> Eq for PortConfig<A>"],["impl<'a> Eq for FuzzMessage<'a>"],["impl Eq for ClockIdentity"],["impl Eq for DelayMechanism"],["impl Eq for ClockAccuracy"],["impl Eq for Interval"],["impl Eq for Time"],["impl Eq for SdoId"],["impl Eq for Measurement"],["impl Eq for Duration"],["impl Eq for InstanceConfig"],["impl Eq for LeapIndicator"],["impl Eq for TimeSource"],["impl Eq for ClockQuality"]], +"statime_linux":[["impl Eq for Config"],["impl Eq for PortConfig"],["impl Eq for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.Ord.js b/docs/implementors/core/cmp/trait.Ord.js new file mode 100644 index 000000000..5c47c6a8f --- /dev/null +++ b/docs/implementors/core/cmp/trait.Ord.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl Ord for ClockIdentity"],["impl Ord for Duration"],["impl Ord for Time"],["impl Ord for Interval"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.PartialEq.js b/docs/implementors/core/cmp/trait.PartialEq.js new file mode 100644 index 000000000..726174b5f --- /dev/null +++ b/docs/implementors/core/cmp/trait.PartialEq.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl PartialEq<InstanceConfig> for InstanceConfig"],["impl PartialEq<ClockQuality> for ClockQuality"],["impl<'a> PartialEq<FuzzMessage<'a>> for FuzzMessage<'a>"],["impl PartialEq<Duration> for Duration"],["impl PartialEq<LeapIndicator> for LeapIndicator"],["impl PartialEq<TimePropertiesDS> for TimePropertiesDS"],["impl PartialEq<SdoId> for SdoId"],["impl<A: PartialEq> PartialEq<PortConfig<A>> for PortConfig<A>"],["impl PartialEq<TimeSource> for TimeSource"],["impl PartialEq<Interval> for Interval"],["impl PartialEq<ClockAccuracy> for ClockAccuracy"],["impl PartialEq<Measurement> for Measurement"],["impl PartialEq<DelayMechanism> for DelayMechanism"],["impl PartialEq<Time> for Time"],["impl PartialEq<ClockIdentity> for ClockIdentity"]], +"statime_linux":[["impl PartialEq<Config> for Config"],["impl PartialEq<PortConfig> for PortConfig"],["impl PartialEq<NetworkMode> for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.PartialOrd.js b/docs/implementors/core/cmp/trait.PartialOrd.js new file mode 100644 index 000000000..9db1fccea --- /dev/null +++ b/docs/implementors/core/cmp/trait.PartialOrd.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl PartialOrd<ClockIdentity> for ClockIdentity"],["impl PartialOrd<Duration> for Duration"],["impl PartialOrd<Time> for Time"],["impl PartialOrd<Interval> for Interval"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/convert/trait.From.js b/docs/implementors/core/convert/trait.From.js new file mode 100644 index 000000000..9e6dbd4e0 --- /dev/null +++ b/docs/implementors/core/convert/trait.From.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl From<Duration> for Duration"],["impl From<i8> for Interval"]], +"statime_linux":[["impl From<PortConfig> for PortConfig<Option<Vec<ClockIdentity>>>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/default/trait.Default.js b/docs/implementors/core/default/trait.Default.js new file mode 100644 index 000000000..975914b5c --- /dev/null +++ b/docs/implementors/core/default/trait.Default.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Default for ClockAccuracy"],["impl Default for LeapIndicator"],["impl Default for Time"],["impl Default for Duration"],["impl Default for ClockIdentity"],["impl Default for TimeSource"],["impl Default for Measurement"],["impl Default for TimePropertiesDS"],["impl Default for ClockQuality"],["impl Default for SdoId"]], +"statime_linux":[["impl Default for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/error/trait.Error.js b/docs/implementors/core/error/trait.Error.js new file mode 100644 index 000000000..c596f0568 --- /dev/null +++ b/docs/implementors/core/error/trait.Error.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime_linux":[["impl Error for ConfigError"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/fmt/trait.Debug.js b/docs/implementors/core/fmt/trait.Debug.js new file mode 100644 index 000000000..3ad680038 --- /dev/null +++ b/docs/implementors/core/fmt/trait.Debug.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl<L: Debug, A: Debug, R: Debug, C: Debug, F: Debug + Filter> Debug for Port<L, A, R, C, F>where\n F::Config: Debug,"],["impl Debug for Duration"],["impl<'a> Debug for PortActionIterator<'a>"],["impl Debug for ClockAccuracy"],["impl<'a> Debug for FuzzMessage<'a>"],["impl Debug for Interval"],["impl Debug for LeapIndicator"],["impl Debug for TimePropertiesDS"],["impl Debug for TimeSource"],["impl<'a> Debug for PortAction<'a>"],["impl Debug for InstanceConfig"],["impl Debug for ClockIdentity"],["impl<A: Debug> Debug for PortConfig<A>"],["impl Debug for TimestampContext"],["impl Debug for DelayMechanism"],["impl<'a> Debug for InBmca<'a>"],["impl Debug for BasicFilter"],["impl Debug for Measurement"],["impl Debug for ClockQuality"],["impl Debug for SdoId"],["impl Debug for Time"],["impl<'a> Debug for Running<'a>"]], +"statime_linux":[["impl Debug for Config"],["impl Debug for ConfigError"],["impl Debug for LinuxClock"],["impl Debug for NetworkMode"],["impl Debug for PortConfig"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/fmt/trait.Display.js b/docs/implementors/core/fmt/trait.Display.js new file mode 100644 index 000000000..63a247f80 --- /dev/null +++ b/docs/implementors/core/fmt/trait.Display.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Display for SdoId"],["impl Display for Duration"],["impl Display for Time"]], +"statime_linux":[["impl Display for ConfigError"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/hash/trait.Hash.js b/docs/implementors/core/hash/trait.Hash.js new file mode 100644 index 000000000..67886c028 --- /dev/null +++ b/docs/implementors/core/hash/trait.Hash.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl Hash for SdoId"],["impl Hash for InstanceConfig"],["impl Hash for Interval"],["impl Hash for ClockIdentity"],["impl<A: Hash> Hash for PortConfig<A>"],["impl Hash for DelayMechanism"],["impl Hash for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/iter/traits/iterator/trait.Iterator.js b/docs/implementors/core/iter/traits/iterator/trait.Iterator.js new file mode 100644 index 000000000..24c39680d --- /dev/null +++ b/docs/implementors/core/iter/traits/iterator/trait.Iterator.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl<'a> Iterator for PortActionIterator<'a>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Copy.js b/docs/implementors/core/marker/trait.Copy.js new file mode 100644 index 000000000..1749a6348 --- /dev/null +++ b/docs/implementors/core/marker/trait.Copy.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Copy for Interval"],["impl<A: Copy> Copy for PortConfig<A>"],["impl Copy for InstanceConfig"],["impl Copy for SdoId"],["impl Copy for ClockQuality"],["impl Copy for LeapIndicator"],["impl Copy for TimePropertiesDS"],["impl Copy for Measurement"],["impl Copy for Time"],["impl Copy for Duration"],["impl Copy for DelayMechanism"],["impl Copy for TimeSource"],["impl Copy for ClockIdentity"],["impl Copy for ClockAccuracy"]], +"statime_linux":[["impl Copy for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Freeze.js b/docs/implementors/core/marker/trait.Freeze.js new file mode 100644 index 000000000..a511ddf80 --- /dev/null +++ b/docs/implementors/core/marker/trait.Freeze.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Freeze for InstanceConfig",1,["statime::config::instance::InstanceConfig"]],["impl Freeze for DelayMechanism",1,["statime::config::port::DelayMechanism"]],["impl<A> Freeze for PortConfig<A>where\n A: Freeze,",1,["statime::config::port::PortConfig"]],["impl Freeze for ClockAccuracy",1,["statime::datastructures::common::clock_accuracy::ClockAccuracy"]],["impl Freeze for ClockIdentity",1,["statime::datastructures::common::clock_identity::ClockIdentity"]],["impl Freeze for ClockQuality",1,["statime::datastructures::common::clock_quality::ClockQuality"]],["impl Freeze for LeapIndicator",1,["statime::datastructures::common::leap_indicator::LeapIndicator"]],["impl Freeze for TimeSource",1,["statime::datastructures::common::time_source::TimeSource"]],["impl Freeze for TimePropertiesDS",1,["statime::datastructures::datasets::time_properties::TimePropertiesDS"]],["impl Freeze for SdoId",1,["statime::datastructures::messages::header::SdoId"]],["impl<'a> Freeze for FuzzMessage<'a>",1,["statime::datastructures::messages::fuzz::FuzzMessage"]],["impl Freeze for BasicFilter",1,["statime::filters::basic::BasicFilter"]],["impl Freeze for Measurement",1,["statime::port::measurement::Measurement"]],["impl<L, A, R, C, F> Freeze for Port<L, A, R, C, F>where\n A: Freeze,\n C: Freeze,\n F: Freeze,\n L: Freeze,\n R: Freeze,\n <F as Filter>::Config: Freeze,",1,["statime::port::Port"]],["impl<'a> Freeze for Running<'a>",1,["statime::port::Running"]],["impl<'a> Freeze for InBmca<'a>",1,["statime::port::InBmca"]],["impl Freeze for TimestampContext",1,["statime::port::TimestampContext"]],["impl<'a> Freeze for PortAction<'a>",1,["statime::port::PortAction"]],["impl<'a> Freeze for PortActionIterator<'a>",1,["statime::port::PortActionIterator"]],["impl<F> !Freeze for PtpInstance<F>",1,["statime::ptp_instance::PtpInstance"]],["impl Freeze for Duration",1,["statime::time::duration::Duration"]],["impl Freeze for Time",1,["statime::time::instant::Time"]],["impl Freeze for Interval",1,["statime::time::interval::Interval"]]], +"statime_linux":[["impl Freeze for LinuxClock",1,["statime_linux::clock::LinuxClock"]],["impl Freeze for Config",1,["statime_linux::config::Config"]],["impl Freeze for PortConfig",1,["statime_linux::config::PortConfig"]],["impl Freeze for NetworkMode",1,["statime_linux::config::NetworkMode"]],["impl Freeze for ConfigError",1,["statime_linux::config::ConfigError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Send.js b/docs/implementors/core/marker/trait.Send.js new file mode 100644 index 000000000..f47758367 --- /dev/null +++ b/docs/implementors/core/marker/trait.Send.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Send for InstanceConfig",1,["statime::config::instance::InstanceConfig"]],["impl Send for DelayMechanism",1,["statime::config::port::DelayMechanism"]],["impl<A> Send for PortConfig<A>where\n A: Send,",1,["statime::config::port::PortConfig"]],["impl Send for ClockAccuracy",1,["statime::datastructures::common::clock_accuracy::ClockAccuracy"]],["impl Send for ClockIdentity",1,["statime::datastructures::common::clock_identity::ClockIdentity"]],["impl Send for ClockQuality",1,["statime::datastructures::common::clock_quality::ClockQuality"]],["impl Send for LeapIndicator",1,["statime::datastructures::common::leap_indicator::LeapIndicator"]],["impl Send for TimeSource",1,["statime::datastructures::common::time_source::TimeSource"]],["impl Send for TimePropertiesDS",1,["statime::datastructures::datasets::time_properties::TimePropertiesDS"]],["impl Send for SdoId",1,["statime::datastructures::messages::header::SdoId"]],["impl<'a> Send for FuzzMessage<'a>",1,["statime::datastructures::messages::fuzz::FuzzMessage"]],["impl Send for BasicFilter",1,["statime::filters::basic::BasicFilter"]],["impl Send for Measurement",1,["statime::port::measurement::Measurement"]],["impl<L, A, R, C, F> Send for Port<L, A, R, C, F>where\n A: Send,\n C: Send,\n F: Send,\n L: Send,\n R: Send,\n <F as Filter>::Config: Send,",1,["statime::port::Port"]],["impl<'a> Send for Running<'a>",1,["statime::port::Running"]],["impl<'a> Send for InBmca<'a>",1,["statime::port::InBmca"]],["impl Send for TimestampContext",1,["statime::port::TimestampContext"]],["impl<'a> Send for PortAction<'a>",1,["statime::port::PortAction"]],["impl<'a> Send for PortActionIterator<'a>",1,["statime::port::PortActionIterator"]],["impl<F> Send for PtpInstance<F>where\n F: Send,",1,["statime::ptp_instance::PtpInstance"]],["impl Send for Duration",1,["statime::time::duration::Duration"]],["impl Send for Time",1,["statime::time::instant::Time"]],["impl Send for Interval",1,["statime::time::interval::Interval"]]], +"statime_linux":[["impl Send for LinuxClock",1,["statime_linux::clock::LinuxClock"]],["impl Send for Config",1,["statime_linux::config::Config"]],["impl Send for PortConfig",1,["statime_linux::config::PortConfig"]],["impl Send for NetworkMode",1,["statime_linux::config::NetworkMode"]],["impl Send for ConfigError",1,["statime_linux::config::ConfigError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.StructuralEq.js b/docs/implementors/core/marker/trait.StructuralEq.js new file mode 100644 index 000000000..45d72accf --- /dev/null +++ b/docs/implementors/core/marker/trait.StructuralEq.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl StructuralEq for Time"],["impl StructuralEq for DelayMechanism"],["impl StructuralEq for TimePropertiesDS"],["impl StructuralEq for Measurement"],["impl StructuralEq for Duration"],["impl StructuralEq for TimeSource"],["impl StructuralEq for InstanceConfig"],["impl<A> StructuralEq for PortConfig<A>"],["impl StructuralEq for ClockAccuracy"],["impl StructuralEq for ClockQuality"],["impl StructuralEq for Interval"],["impl StructuralEq for ClockIdentity"],["impl<'a> StructuralEq for FuzzMessage<'a>"],["impl StructuralEq for SdoId"],["impl StructuralEq for LeapIndicator"]], +"statime_linux":[["impl StructuralEq for PortConfig"],["impl StructuralEq for Config"],["impl StructuralEq for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.StructuralPartialEq.js b/docs/implementors/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 000000000..a61679261 --- /dev/null +++ b/docs/implementors/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl StructuralPartialEq for SdoId"],["impl StructuralPartialEq for TimeSource"],["impl<'a> StructuralPartialEq for FuzzMessage<'a>"],["impl StructuralPartialEq for TimePropertiesDS"],["impl StructuralPartialEq for ClockAccuracy"],["impl StructuralPartialEq for LeapIndicator"],["impl StructuralPartialEq for Interval"],["impl StructuralPartialEq for DelayMechanism"],["impl StructuralPartialEq for InstanceConfig"],["impl<A> StructuralPartialEq for PortConfig<A>"],["impl StructuralPartialEq for Duration"],["impl StructuralPartialEq for ClockIdentity"],["impl StructuralPartialEq for Measurement"],["impl StructuralPartialEq for ClockQuality"],["impl StructuralPartialEq for Time"]], +"statime_linux":[["impl StructuralPartialEq for Config"],["impl StructuralPartialEq for PortConfig"],["impl StructuralPartialEq for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Sync.js b/docs/implementors/core/marker/trait.Sync.js new file mode 100644 index 000000000..7f8e5df03 --- /dev/null +++ b/docs/implementors/core/marker/trait.Sync.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Sync for InstanceConfig",1,["statime::config::instance::InstanceConfig"]],["impl Sync for DelayMechanism",1,["statime::config::port::DelayMechanism"]],["impl<A> Sync for PortConfig<A>where\n A: Sync,",1,["statime::config::port::PortConfig"]],["impl Sync for ClockAccuracy",1,["statime::datastructures::common::clock_accuracy::ClockAccuracy"]],["impl Sync for ClockIdentity",1,["statime::datastructures::common::clock_identity::ClockIdentity"]],["impl Sync for ClockQuality",1,["statime::datastructures::common::clock_quality::ClockQuality"]],["impl Sync for LeapIndicator",1,["statime::datastructures::common::leap_indicator::LeapIndicator"]],["impl Sync for TimeSource",1,["statime::datastructures::common::time_source::TimeSource"]],["impl Sync for TimePropertiesDS",1,["statime::datastructures::datasets::time_properties::TimePropertiesDS"]],["impl Sync for SdoId",1,["statime::datastructures::messages::header::SdoId"]],["impl<'a> Sync for FuzzMessage<'a>",1,["statime::datastructures::messages::fuzz::FuzzMessage"]],["impl Sync for BasicFilter",1,["statime::filters::basic::BasicFilter"]],["impl Sync for Measurement",1,["statime::port::measurement::Measurement"]],["impl<L, A, R, C, F> Sync for Port<L, A, R, C, F>where\n A: Sync,\n C: Sync,\n F: Sync,\n L: Sync,\n R: Sync,\n <F as Filter>::Config: Sync,",1,["statime::port::Port"]],["impl<'a> Sync for Running<'a>",1,["statime::port::Running"]],["impl<'a> Sync for InBmca<'a>",1,["statime::port::InBmca"]],["impl Sync for TimestampContext",1,["statime::port::TimestampContext"]],["impl<'a> Sync for PortAction<'a>",1,["statime::port::PortAction"]],["impl<'a> Sync for PortActionIterator<'a>",1,["statime::port::PortActionIterator"]],["impl<F> Sync for PtpInstance<F>where\n F: Sync,",1,["statime::ptp_instance::PtpInstance"]],["impl Sync for Duration",1,["statime::time::duration::Duration"]],["impl Sync for Time",1,["statime::time::instant::Time"]],["impl Sync for Interval",1,["statime::time::interval::Interval"]]], +"statime_linux":[["impl Sync for LinuxClock",1,["statime_linux::clock::LinuxClock"]],["impl Sync for Config",1,["statime_linux::config::Config"]],["impl Sync for PortConfig",1,["statime_linux::config::PortConfig"]],["impl Sync for NetworkMode",1,["statime_linux::config::NetworkMode"]],["impl Sync for ConfigError",1,["statime_linux::config::ConfigError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Unpin.js b/docs/implementors/core/marker/trait.Unpin.js new file mode 100644 index 000000000..bd8971a42 --- /dev/null +++ b/docs/implementors/core/marker/trait.Unpin.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl Unpin for InstanceConfig",1,["statime::config::instance::InstanceConfig"]],["impl Unpin for DelayMechanism",1,["statime::config::port::DelayMechanism"]],["impl<A> Unpin for PortConfig<A>where\n A: Unpin,",1,["statime::config::port::PortConfig"]],["impl Unpin for ClockAccuracy",1,["statime::datastructures::common::clock_accuracy::ClockAccuracy"]],["impl Unpin for ClockIdentity",1,["statime::datastructures::common::clock_identity::ClockIdentity"]],["impl Unpin for ClockQuality",1,["statime::datastructures::common::clock_quality::ClockQuality"]],["impl Unpin for LeapIndicator",1,["statime::datastructures::common::leap_indicator::LeapIndicator"]],["impl Unpin for TimeSource",1,["statime::datastructures::common::time_source::TimeSource"]],["impl Unpin for TimePropertiesDS",1,["statime::datastructures::datasets::time_properties::TimePropertiesDS"]],["impl Unpin for SdoId",1,["statime::datastructures::messages::header::SdoId"]],["impl<'a> Unpin for FuzzMessage<'a>",1,["statime::datastructures::messages::fuzz::FuzzMessage"]],["impl Unpin for BasicFilter",1,["statime::filters::basic::BasicFilter"]],["impl Unpin for Measurement",1,["statime::port::measurement::Measurement"]],["impl<L, A, R, C, F> Unpin for Port<L, A, R, C, F>where\n A: Unpin,\n C: Unpin,\n F: Unpin,\n L: Unpin,\n R: Unpin,\n <F as Filter>::Config: Unpin,",1,["statime::port::Port"]],["impl<'a> Unpin for Running<'a>",1,["statime::port::Running"]],["impl<'a> Unpin for InBmca<'a>",1,["statime::port::InBmca"]],["impl Unpin for TimestampContext",1,["statime::port::TimestampContext"]],["impl<'a> Unpin for PortAction<'a>",1,["statime::port::PortAction"]],["impl<'a> Unpin for PortActionIterator<'a>",1,["statime::port::PortActionIterator"]],["impl<F> Unpin for PtpInstance<F>where\n F: Unpin,",1,["statime::ptp_instance::PtpInstance"]],["impl Unpin for Duration",1,["statime::time::duration::Duration"]],["impl Unpin for Time",1,["statime::time::instant::Time"]],["impl Unpin for Interval",1,["statime::time::interval::Interval"]]], +"statime_linux":[["impl Unpin for LinuxClock",1,["statime_linux::clock::LinuxClock"]],["impl Unpin for Config",1,["statime_linux::config::Config"]],["impl Unpin for PortConfig",1,["statime_linux::config::PortConfig"]],["impl Unpin for NetworkMode",1,["statime_linux::config::NetworkMode"]],["impl Unpin for ConfigError",1,["statime_linux::config::ConfigError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Add.js b/docs/implementors/core/ops/arith/trait.Add.js new file mode 100644 index 000000000..185bfe4ff --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Add.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl Add<Duration> for Duration"],["impl Add<Duration> for Time"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.AddAssign.js b/docs/implementors/core/ops/arith/trait.AddAssign.js new file mode 100644 index 000000000..cd5e6e328 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.AddAssign.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl AddAssign<Duration> for Duration"],["impl AddAssign<Duration> for Time"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Div.js b/docs/implementors/core/ops/arith/trait.Div.js new file mode 100644 index 000000000..daa9fcaed --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Div.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl<TF: ToFixed> Div<TF> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.DivAssign.js b/docs/implementors/core/ops/arith/trait.DivAssign.js new file mode 100644 index 000000000..ac6a3b36e --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.DivAssign.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl<TF: ToFixed> DivAssign<TF> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Mul.js b/docs/implementors/core/ops/arith/trait.Mul.js new file mode 100644 index 000000000..d94bbae49 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Mul.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl<TF: ToFixed> Mul<TF> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.MulAssign.js b/docs/implementors/core/ops/arith/trait.MulAssign.js new file mode 100644 index 000000000..f3743c050 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.MulAssign.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl<TF: ToFixed> MulAssign<TF> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Neg.js b/docs/implementors/core/ops/arith/trait.Neg.js new file mode 100644 index 000000000..d571e8d66 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Neg.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl Neg for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Rem.js b/docs/implementors/core/ops/arith/trait.Rem.js new file mode 100644 index 000000000..0635f7b67 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Rem.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl Rem<Duration> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.RemAssign.js b/docs/implementors/core/ops/arith/trait.RemAssign.js new file mode 100644 index 000000000..8bbb64912 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.RemAssign.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl RemAssign<Duration> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Sub.js b/docs/implementors/core/ops/arith/trait.Sub.js new file mode 100644 index 000000000..c66609f5c --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Sub.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl Sub<Duration> for Time"],["impl Sub<Time> for Time"],["impl Sub<Duration> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.SubAssign.js b/docs/implementors/core/ops/arith/trait.SubAssign.js new file mode 100644 index 000000000..7db4c0d2a --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.SubAssign.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[["impl SubAssign<Duration> for Time"],["impl SubAssign<Duration> for Duration"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js b/docs/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js new file mode 100644 index 000000000..8467088e2 --- /dev/null +++ b/docs/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl RefUnwindSafe for InstanceConfig",1,["statime::config::instance::InstanceConfig"]],["impl RefUnwindSafe for DelayMechanism",1,["statime::config::port::DelayMechanism"]],["impl<A> RefUnwindSafe for PortConfig<A>where\n A: RefUnwindSafe,",1,["statime::config::port::PortConfig"]],["impl RefUnwindSafe for ClockAccuracy",1,["statime::datastructures::common::clock_accuracy::ClockAccuracy"]],["impl RefUnwindSafe for ClockIdentity",1,["statime::datastructures::common::clock_identity::ClockIdentity"]],["impl RefUnwindSafe for ClockQuality",1,["statime::datastructures::common::clock_quality::ClockQuality"]],["impl RefUnwindSafe for LeapIndicator",1,["statime::datastructures::common::leap_indicator::LeapIndicator"]],["impl RefUnwindSafe for TimeSource",1,["statime::datastructures::common::time_source::TimeSource"]],["impl RefUnwindSafe for TimePropertiesDS",1,["statime::datastructures::datasets::time_properties::TimePropertiesDS"]],["impl RefUnwindSafe for SdoId",1,["statime::datastructures::messages::header::SdoId"]],["impl<'a> RefUnwindSafe for FuzzMessage<'a>",1,["statime::datastructures::messages::fuzz::FuzzMessage"]],["impl RefUnwindSafe for BasicFilter",1,["statime::filters::basic::BasicFilter"]],["impl RefUnwindSafe for Measurement",1,["statime::port::measurement::Measurement"]],["impl<L, A, R, C, F> RefUnwindSafe for Port<L, A, R, C, F>where\n A: RefUnwindSafe,\n C: RefUnwindSafe,\n F: RefUnwindSafe,\n L: RefUnwindSafe,\n R: RefUnwindSafe,\n <F as Filter>::Config: RefUnwindSafe,",1,["statime::port::Port"]],["impl<'a> !RefUnwindSafe for Running<'a>",1,["statime::port::Running"]],["impl<'a> !RefUnwindSafe for InBmca<'a>",1,["statime::port::InBmca"]],["impl RefUnwindSafe for TimestampContext",1,["statime::port::TimestampContext"]],["impl<'a> RefUnwindSafe for PortAction<'a>",1,["statime::port::PortAction"]],["impl<'a> RefUnwindSafe for PortActionIterator<'a>",1,["statime::port::PortActionIterator"]],["impl<F> !RefUnwindSafe for PtpInstance<F>",1,["statime::ptp_instance::PtpInstance"]],["impl RefUnwindSafe for Duration",1,["statime::time::duration::Duration"]],["impl RefUnwindSafe for Time",1,["statime::time::instant::Time"]],["impl RefUnwindSafe for Interval",1,["statime::time::interval::Interval"]]], +"statime_linux":[["impl RefUnwindSafe for LinuxClock",1,["statime_linux::clock::LinuxClock"]],["impl RefUnwindSafe for Config",1,["statime_linux::config::Config"]],["impl RefUnwindSafe for PortConfig",1,["statime_linux::config::PortConfig"]],["impl RefUnwindSafe for NetworkMode",1,["statime_linux::config::NetworkMode"]],["impl !RefUnwindSafe for ConfigError",1,["statime_linux::config::ConfigError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/panic/unwind_safe/trait.UnwindSafe.js b/docs/implementors/core/panic/unwind_safe/trait.UnwindSafe.js new file mode 100644 index 000000000..985222f2e --- /dev/null +++ b/docs/implementors/core/panic/unwind_safe/trait.UnwindSafe.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"statime":[["impl UnwindSafe for InstanceConfig",1,["statime::config::instance::InstanceConfig"]],["impl UnwindSafe for DelayMechanism",1,["statime::config::port::DelayMechanism"]],["impl<A> UnwindSafe for PortConfig<A>where\n A: UnwindSafe,",1,["statime::config::port::PortConfig"]],["impl UnwindSafe for ClockAccuracy",1,["statime::datastructures::common::clock_accuracy::ClockAccuracy"]],["impl UnwindSafe for ClockIdentity",1,["statime::datastructures::common::clock_identity::ClockIdentity"]],["impl UnwindSafe for ClockQuality",1,["statime::datastructures::common::clock_quality::ClockQuality"]],["impl UnwindSafe for LeapIndicator",1,["statime::datastructures::common::leap_indicator::LeapIndicator"]],["impl UnwindSafe for TimeSource",1,["statime::datastructures::common::time_source::TimeSource"]],["impl UnwindSafe for TimePropertiesDS",1,["statime::datastructures::datasets::time_properties::TimePropertiesDS"]],["impl UnwindSafe for SdoId",1,["statime::datastructures::messages::header::SdoId"]],["impl<'a> UnwindSafe for FuzzMessage<'a>",1,["statime::datastructures::messages::fuzz::FuzzMessage"]],["impl UnwindSafe for BasicFilter",1,["statime::filters::basic::BasicFilter"]],["impl UnwindSafe for Measurement",1,["statime::port::measurement::Measurement"]],["impl<L, A, R, C, F> UnwindSafe for Port<L, A, R, C, F>where\n A: UnwindSafe,\n C: UnwindSafe,\n F: UnwindSafe,\n L: UnwindSafe,\n R: UnwindSafe,\n <F as Filter>::Config: UnwindSafe,",1,["statime::port::Port"]],["impl<'a> !UnwindSafe for Running<'a>",1,["statime::port::Running"]],["impl<'a> !UnwindSafe for InBmca<'a>",1,["statime::port::InBmca"]],["impl UnwindSafe for TimestampContext",1,["statime::port::TimestampContext"]],["impl<'a> UnwindSafe for PortAction<'a>",1,["statime::port::PortAction"]],["impl<'a> UnwindSafe for PortActionIterator<'a>",1,["statime::port::PortActionIterator"]],["impl<F> UnwindSafe for PtpInstance<F>where\n F: UnwindSafe,",1,["statime::ptp_instance::PtpInstance"]],["impl UnwindSafe for Duration",1,["statime::time::duration::Duration"]],["impl UnwindSafe for Time",1,["statime::time::instant::Time"]],["impl UnwindSafe for Interval",1,["statime::time::interval::Interval"]]], +"statime_linux":[["impl UnwindSafe for LinuxClock",1,["statime_linux::clock::LinuxClock"]],["impl UnwindSafe for Config",1,["statime_linux::config::Config"]],["impl UnwindSafe for PortConfig",1,["statime_linux::config::PortConfig"]],["impl UnwindSafe for NetworkMode",1,["statime_linux::config::NetworkMode"]],["impl !UnwindSafe for ConfigError",1,["statime_linux::config::ConfigError"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/serde/de/trait.Deserialize.js b/docs/implementors/serde/de/trait.Deserialize.js new file mode 100644 index 000000000..4f20478be --- /dev/null +++ b/docs/implementors/serde/de/trait.Deserialize.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime_linux":[["impl<'de> Deserialize<'de> for PortConfig"],["impl<'de> Deserialize<'de> for Config"],["impl<'de> Deserialize<'de> for NetworkMode"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/statime/clock/trait.Clock.js b/docs/implementors/statime/clock/trait.Clock.js new file mode 100644 index 000000000..79a13af18 --- /dev/null +++ b/docs/implementors/statime/clock/trait.Clock.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime_linux":[["impl Clock for LinuxClock"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/statime/filters/trait.Filter.js b/docs/implementors/statime/filters/trait.Filter.js new file mode 100644 index 000000000..7db77e0a6 --- /dev/null +++ b/docs/implementors/statime/filters/trait.Filter.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/statime_linux/socket/trait.PtpTargetAddress.js b/docs/implementors/statime_linux/socket/trait.PtpTargetAddress.js new file mode 100644 index 000000000..1d3d3405d --- /dev/null +++ b/docs/implementors/statime_linux/socket/trait.PtpTargetAddress.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"statime_linux":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/search-index.js b/docs/search-index.js new file mode 100644 index 000000000..f595ba973 --- /dev/null +++ b/docs/search-index.js @@ -0,0 +1,6 @@ +var searchIndex = JSON.parse('{\ +"statime":{"doc":"Statime is a library providing an implementation of PTP …","t":"NDIEDDQEDNQIDNNDDNDNNERNNNNNNDNNNNNNNNSNNNNNNNDEDDNNNDNNNNNNNDNNNDNNNSNDDEDNNNNNNNNSLMLLLLLLMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMKLLLLMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMKLLLLLLLLLKLLLLLLKMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMLLLLLKKMLKLLLLLLMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMM","n":["AtomicClock","BasicFilter","Clock","ClockAccuracy","ClockIdentity","ClockQuality","Config","DelayMechanism","Duration","E2E","Error","Filter","FuzzMessage","Gnss","HandSet","InBmca","InstanceConfig","InternalOscillator","Interval","Leap59","Leap61","LeapIndicator","MAX_DATA_LEN","MS1","MS10","MS100","MS25","MS250","MS2_5","Measurement","NS1","NS10","NS100","NS25","NS250","NS2_5","NoLeap","Ntp","ONE_SECOND","Other","PS1","PS10","PS100","PS25","PS250","PS2_5","Port","PortAction","PortActionIterator","PortConfig","ProfileSpecific","ProfileSpecific","Ptp","PtpInstance","Reserved","Reserved","ResetAnnounceReceiptTimer","ResetAnnounceTimer","ResetDelayRequestTimer","ResetFilterUpdateTimer","ResetSyncTimer","Running","S1","S10","SGT10","SdoId","SendGeneral","SendTimeCritical","SerialTimeCode","TWO_SECONDS","TerrestrialRadio","Time","TimePropertiesDS","TimeSource","TimestampContext","US1","US10","US100","US25","US250","US2_5","Unknown","Unknown","ZERO","abs","acceptable_master_list","add","add","add_assign","add_assign","add_port","announce_duration","announce_interval","announce_receipt_timeout","as_core_duration","as_duration","as_f64","as_log_2","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","az","bmca","bmca_interval","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","cast_from","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_as","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","clock_accuracy","clock_class","clock_identity","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","cmp","cmp","default","default","default","default","default","default","default","default","default","default","delay","delay_asymmetry","delay_mechanism","demobilize","demobilize","deserialize","div","div_assign","domain_number","empty","end_bmca","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","event_time","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_fixed_nanos","from_fixed_nanos","from_interval","from_log_2","from_log_interval","from_micros","from_micros","from_millis","from_millis","from_nanos","from_nanos","from_nanos_subnanos","from_seconds","from_secs","from_secs","handle_announce_receipt_timer","handle_announce_timer","handle_delay_request_timer","handle_filter_update_timer","handle_general_receive","handle_send_timestamp","handle_sync_timer","handle_timecritical_receive","hash","hash","hash","hash","hash","hash","hash","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into_iter","is_ptp","is_steering","leap_indicator","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","lossy_into","master_only","measurement","measurement","min_delay_req_interval","mul","mul_assign","nanos","nanos","nanos_lossy","nanos_rounded","neg","new","new","new","new","new_arbitrary_time","new_ptp_time","next","now","offset","offset_scaled_log_variance","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","partial_cmp","partial_cmp","partial_cmp","partial_cmp","priority_1","priority_2","raw_delay_offset","raw_sync_offset","rem","rem_assign","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_as","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","sdo_id","seconds","seconds","secs","secs","serialize","set_frequency","set_properties","slave_only","start_bmca","step_clock","sub","sub","sub","sub_assign","sub_assign","subsec_nanos","sync_interval","tlv","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","to_string","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","update","update","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","interval","context","data","data","duration","duration","duration","duration","duration"],"q":[[0,"statime"],[825,"statime::DelayMechanism"],[826,"statime::PortAction"],[834,"rand::rng"],[835,"core::time"],[836,"core::option"],[837,"core::clone"],[838,"core::cmp"],[839,"core::error"],[840,"core::result"],[841,"fixed::traits"],[842,"core::cmp"],[843,"core::fmt"],[844,"core::hash"],[845,"fixed::types"],[846,"alloc::string"],[847,"core::any"]],"d":["","A simple averaging filter","Clock manipulation and querying interface","How accurate the underlying clock device is expected to be …","The identity of a PTP node.","A description of the accuracy and type of a clock.","","Which delay mechanism a port is using.","A duration is a span of time that can also be negative.","End to end delay mechanism. Delay measurement is done …","","A filter for post-processing time measurements.","","","","","","","","the last minute of the current UTC day contains 59 seconds.","the last minute of the current UTC day contains 61 seconds.","","","Accurate within 1 ms","Accurate within 10 ms","Accurate within 100 ms","Accurate within 25 ms","Accurate within 250 ms","Accurate within 2.5 ms","A single measurement as produced by a PTP port. Depending …","Accurate within 1 ns","Accurate within 10 ns","Accurate within 100 ns","Accurate within 25 ns","Accurate within 250 ns","Accurate within 2.5 ns","","","","","Accurate within 1 ps","Accurate within 10 ps","Accurate within 100 ps","Accurate within 25 ps","Accurate within 250 ps","Accurate within 2.5 ps","A single port of the PTP instance","","Guarantees to end user: Any set of actions will only ever …","Configuration items of the PTP PortDS dataset. Dynamical …","Specific to a profile","","","A PTP node.","Reserved","","","","","","","","Accurate within 1 s","Accurate within 10 s","Accurate within >10 s","A wrapper type for PTP Sdo Identifiers.","","","","","","Time represents a specific moment in time.","A concrete implementation of the PTP Time Properties …","What the time values for a system are derived from","","Accurate within 1 us","Accurate within 10 us","Accurate within 100 us","Accurate within 25 us","Accurate within 250 us","Accurate within 2.5 us","Accuracy is unknown","Time source is unknown. This is not an official variant …","","Takes the absolute (non-negative) value of the duration","","","","","","Add and initialize this port","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","The accuracy of the clock","The PTP clock class.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Delay to the remote PTP node.","","","Handle ending of time synchronization from the source …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Time this measurement was made.","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","Create an instance with the given amount of nanoseconds, …","Create an instance with the given amount of nanoseconds …","Converts a interval (as defined by the PTP spec) to a …","","Converts a log interval (as defined by the PTP spec) to a …","Create an instance with the given amount of microseconds","Create an instance with the given amount of microseconds …","Create an instance with the given amount of milliseconds","Create an instance with the given amount of milliseconds …","Create an instance with the given amount of nanoseconds","Create an instance with the given amount of nanoseconds …","","Create an instance with the given amount of seconds","Create an instance with the given amount of seconds","Create an instance with the given amount of seconds from …","","","","","","","","","","","","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","Is the current timescale the ptp (utc-derived) timescale?","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Put a new measurement in the filter. The filter can then …","","","","","Get the total amount of nanoseconds","Get the total amount of nanoseconds since the origin","Get the total amount of nanoseconds, losing some precision","","","Create a new instance of the filter.","","Create a new sdo id","","Create a Time Properties data set for an Arbitrary …","Create a Time Properties data set for the PTP timescale.","","Get the current time of the clock","Offset to the remote PTP node.","2-log of the variance (in seconds^2) of the clock when not …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Raw offset calculated from a delay message","Raw offset calculated from a sync message","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Get the total amount of seconds","","Get the total amount of seconds","Get the total amount of seconds since the origin","","Set the frequency of the clock, returning the time at …","Adjust the timescale properties of the clock, including …","","","Change the current time of the clock by offset. Returns …","","","","","","Get all the nanoseconds that are under a second","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Update initiated through FilterUpdate::next_update timeout.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[24,0,0,0,0,0,8,0,0,18,15,0,0,24,24,0,0,24,0,23,23,0,0,20,20,20,20,20,20,0,20,20,20,20,20,20,23,24,11,24,20,20,20,20,20,20,0,0,0,0,20,24,24,0,20,24,43,43,43,43,43,0,20,20,20,0,43,43,24,11,24,0,0,0,0,20,20,20,20,20,20,20,24,1,1,5,1,2,1,2,4,5,5,5,11,11,11,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,4,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,22,22,17,17,18,5,20,21,22,23,24,25,26,27,28,1,2,11,17,18,5,20,21,22,23,24,25,26,27,28,1,2,11,21,1,2,11,20,21,22,23,24,25,26,28,1,2,28,5,5,8,30,27,1,1,17,35,7,17,18,5,20,21,22,23,24,25,26,27,28,1,2,11,17,18,5,20,21,22,23,24,25,26,27,28,1,2,11,28,17,18,5,20,21,22,23,24,25,26,26,27,30,28,7,36,6,42,43,35,1,1,2,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,11,1,2,1,11,1,1,2,1,2,1,2,2,1,1,2,7,7,7,7,7,7,7,7,17,18,5,21,26,1,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,35,25,7,25,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,5,8,30,5,1,1,1,2,1,1,1,8,4,26,30,25,25,35,15,28,22,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,21,1,2,11,17,17,28,28,1,1,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,17,1,11,1,2,27,15,15,17,7,15,1,2,2,1,2,2,5,27,17,18,5,20,21,22,23,24,25,26,27,28,1,2,11,26,1,2,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,8,30,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,4,17,18,5,20,21,22,23,24,25,26,27,30,28,7,36,6,42,43,35,1,2,11,58,59,59,60,61,62,63,64,65],"f":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[1,1],0,[[1,1]],[[2,1]],[[1,1],3],[[2,1],3],[[[4,[-1]],[5,[-2]],-3,-4],[[7,[6,-2,-4,-3,-1]]],8,[],[],9],[[[5,[-1]],-2],10,[],9],0,0,[11,10],[11,1],[11,12],[11,13],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[[[4,[-1]],[14,[[7,[6,-2,-3,-4,-1]]]]],3,8,0,9,15],[[[4,[-1]]],10,8],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],0,0,0,[17,17],[18,18],[[[5,[-1]]],[[5,[-1]]],19],[20,20],[21,21],[22,22],[23,23],[24,24],[25,25],[26,26],[27,27],[28,28],[1,1],[2,2],[11,11],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[21,21],29],[[1,1],29],[[2,2],29],[[11,11],29],[[],20],[[],21],[[],22],[[],23],[[],24],[[],25],[[],26],[[],28],[[],1],[[],2],0,0,0,[[-1,-2],3,[],15],[[30,-1],3,15],[[[14,[31]]],[[33,[27,[0,[32]]]]]],[[1,-1],[],34],[[1,-1],3,34],0,[[],35],[[[7,[6,-1,-2,-3,-4]]],[[3,[[7,[36,-1,-2,-3,-4]],35]]],[],[],[],8],[[17,17],37],[[18,18],37],[[[5,[-1]],[5,[-1]]],37,38],[[20,20],37],[[21,21],37],[[22,22],37],[[23,23],37],[[24,24],37],[[25,25],37],[[26,26],37],[[27,27],37],[[28,28],37],[[1,1],37],[[2,2],37],[[11,11],37],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],[[-1,-2],37,[],[]],0,[[17,39],40],[[18,39],40],[[[5,[-1]],39],40,41],[[20,39],40],[[21,39],40],[[22,39],40],[[23,39],40],[[24,39],40],[[25,39],40],[[26,39],40],[[26,39],40],[[27,39],40],[[30,39],40],[[28,39],40],[[[7,[-1,-2,-3,-4,-5]],39],40,41,41,41,41,[41,8]],[[36,39],40],[[6,39],40],[[42,39],40],[[43,39],40],[[35,39],40],[[1,39],40],[[1,39],40],[[2,39],40],[[2,39],40],[[11,39],40],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[13,11],[-1,-1,[]],[-1,1,34],[-1,2,34],[11,1],[13,11],[13,1],[44,1],[45,2],[44,1],[45,2],[44,1],[45,2],[[45,46],2],[12,1],[44,1],[45,2],[[[7,[36,-1,-2,-3,-4]]],35,[],9,15,8],[[[7,[36,-1,-2,-3,-4]]],35,[],9,15,8],[[[7,[36,-1,-2,-3,-4]]],35,[],9,15,8],[[[7,[36,-1,-2,-3,-4]]],35,[],9,15,8],[[[7,[36,-1,-2,-3,-4]],[14,[31]]],35,0,9,15,8],[[[7,[36,-1,-2,-3,-4]],42,2],35,[],9,15,8],[[[7,[36,-1,-2,-3,-4]]],35,[],9,15,8],[[[7,[36,-1,-2,-3,-4]],[14,[31]],2],35,0,9,15,8],[[17,-1],3,47],[[18,-1],3,47],[[[5,[-1]],-2],3,48,47],[[21,-1],3,47],[[26,-1],3,47],[[1,-1],3,47],[[11,-1],3,47],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[25,37],[[[7,[-1,-2,-3,-4,-5]]],37,[],[],[],[],8],[25,23],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,[[16,[-2]]],[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,0,[[[5,[-1]]],11,[]],[[1,-1],[],34],[[1,-1],3,34],[1,49],[2,50],[1,12],[1,51],[1],[[],-1,[]],[[17,25],[[4,[-1]]],[]],[52,[[16,[26]]]],[12,30],[[37,37,24],25],[[[16,[53]],23,37,37,24],25],[35,16],[-1,2,[]],0,0,[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[-1,[[3,[-2,37]]],[],[]],[[21,21],[[16,[29]]]],[[1,1],[[16,[29]]]],[[2,2],[[16,[29]]]],[[11,11],[[16,[29]]]],0,0,0,0,[[1,1]],[[1,1],3],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,[1,12],[11,12],[1,44],[2,45],[[27,[14,[31]]],[[33,[54,[0,[32]]]]]],[[-1,12],[[33,[2]]],[]],[[-1,25],[[33,[3]]],[]],0,[[[7,[36,-1,-2,-3,-4]]],[[7,[6,-1,-2,-3,-4]]],[],9,15,8],[[-1,1],[[33,[2]]],[]],[[1,1]],[[2,1]],[[2,2]],[[1,1],3],[[2,1],3],[2,46],0,[27,[[0,[55]]]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,56,[]],[-1,56,[]],[-1,56,[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,[[33,[-2]]],[],[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,57,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,0,0,0,0,0,0,0],"c":[],"p":[[3,"Duration",0],[3,"Time",0],[15,"tuple"],[3,"PtpInstance",0],[3,"PortConfig",0],[3,"InBmca",0],[3,"Port",0],[8,"Filter",0],[8,"Rng",834],[3,"Duration",835],[3,"Interval",0],[15,"f64"],[15,"i8"],[15,"slice"],[8,"Clock",0],[4,"Option",836],[3,"InstanceConfig",0],[4,"DelayMechanism",0],[8,"Clone",837],[4,"ClockAccuracy",0],[3,"ClockIdentity",0],[3,"ClockQuality",0],[4,"LeapIndicator",0],[4,"TimeSource",0],[3,"TimePropertiesDS",0],[3,"SdoId",0],[3,"FuzzMessage",0],[3,"Measurement",0],[4,"Ordering",838],[3,"BasicFilter",0],[15,"u8"],[8,"Error",839],[4,"Result",840],[8,"ToFixed",841],[3,"PortActionIterator",0],[3,"Running",0],[15,"bool"],[8,"PartialEq",838],[3,"Formatter",842],[6,"Result",842],[8,"Debug",842],[3,"TimestampContext",0],[4,"PortAction",0],[15,"i64"],[15,"u64"],[15,"u32"],[8,"Hasher",843],[8,"Hash",843],[6,"I96F32",844],[6,"U96F32",844],[15,"i128"],[15,"u16"],[15,"i16"],[15,"usize"],[8,"Iterator",845],[3,"String",846],[3,"TypeId",847],[13,"E2E",825],[13,"SendTimeCritical",826],[13,"SendGeneral",826],[13,"ResetAnnounceTimer",826],[13,"ResetSyncTimer",826],[13,"ResetDelayRequestTimer",826],[13,"ResetAnnounceReceiptTimer",826],[13,"ResetFilterUpdateTimer",826]]},\ +"statime_linux":{"doc":"","t":"AAASDLLLLLLMLLLLLLFLLLLLLLLLLLLLLLLLLLLLLLLLDENNNEDNMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMLLLMLLLLLLLLLLLLLLLLLLLLLLMMLLLLMLLLLLLLLMMLLLLLLLLMMMLLLLLLLLMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLSSSSIFFFFF","n":["clock","config","socket","CLOCK_REALTIME","LinuxClock","az","borrow","borrow_mut","cast_from","checked_as","checked_cast_from","clock","clone","clone_into","error_estimate_update","fmt","from","into","libc_timespec_into_instant","lossless_try_into","lossy_into","now","now","open","overflowing_as","overflowing_cast_from","resolution","saturating_as","saturating_cast_from","set_frequency","set_frequency","set_leap_seconds","set_properties","step_clock","step_clock","to_owned","try_from","try_into","type_id","unwrapped_as","unwrapped_cast_from","vzip","wrapping_as","wrapping_cast_from","Config","ConfigError","Io","Ipv4","Ipv6","NetworkMode","PortConfig","Toml","acceptable_master_list","announce_interval","announce_receipt_timeout","az","az","az","az","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","cast_from","cast_from","cast_from","cast_from","checked_as","checked_as","checked_as","checked_as","checked_cast_from","checked_cast_from","checked_cast_from","checked_cast_from","clone","clone","clone","clone_into","clone_into","clone_into","default","delay_asymetry","delay_mechanism","deserialize","deserialize","deserialize","domain","eq","eq","eq","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","equivalent","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from_file","hardware_clock","interface","into","into","into","into","loglevel","lossless_try_into","lossless_try_into","lossless_try_into","lossless_try_into","lossy_into","lossy_into","lossy_into","lossy_into","master_only","network_mode","overflowing_as","overflowing_as","overflowing_as","overflowing_as","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","overflowing_cast_from","ports","priority1","priority2","saturating_as","saturating_as","saturating_as","saturating_as","saturating_cast_from","saturating_cast_from","saturating_cast_from","saturating_cast_from","sdo_id","sync_interval","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_as","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","unwrapped_cast_from","vzip","vzip","vzip","vzip","warn_when_unreasonable","wrapping_as","wrapping_as","wrapping_as","wrapping_as","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","wrapping_cast_from","PDELAY_EVENT","PDELAY_GENERAL","PRIMARY_EVENT","PRIMARY_GENERAL","PtpTargetAddress","open_ipv4_event_socket","open_ipv4_general_socket","open_ipv6_event_socket","open_ipv6_general_socket","timestamp_to_time"],"q":[[0,"statime_linux"],[3,"statime_linux::clock"],[44,"statime_linux::config"],[189,"statime_linux::socket"],[199,"core::option"],[200,"core::time"],[201,"core::result"],[202,"core::fmt"],[203,"core::fmt"],[204,"statime::time::instant"],[205,"clock_steering"],[206,"std::io::error"],[207,"std::path"],[208,"core::convert"],[209,"clock_steering"],[210,"statime::time::duration"],[211,"clock_steering"],[212,"serde::de"],[213,"alloc::string"],[214,"timestamped_socket::interface"],[215,"timestamped_socket::socket"],[216,"core::net::socket_addr"],[217,"timestamped_socket::socket"]],"d":["Implementation of the abstract clock for the linux platform","","Event and General sockets for linux systems","","","","","","","","","","","","","","Returns the argument unchanged.","Calls U::from(self).","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Parse config from file","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Warns about unreasonable config values","","","","","","","","","","","","","","","","","",""],"i":[0,0,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,25,23,23,0,0,25,22,22,22,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,21,22,23,23,22,22,21,22,23,21,21,22,23,21,21,21,22,22,22,23,23,23,21,22,23,25,25,21,22,23,25,21,22,22,21,22,23,25,21,21,22,23,25,21,22,23,25,22,22,21,22,23,25,21,22,23,25,21,21,21,21,22,23,25,21,22,23,25,21,22,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,25,21,22,23,25,21,21,22,23,25,21,22,23,25,34,34,34,34,0,0,0,0,0,0],"f":[0,0,0,0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],0,[2,2],[[-1,-2],3,[],[]],[[2,4,4],[[5,[3]]]],[[2,6],7],[-1,-1,[]],[-1,-2,[],[]],[8,9],[-1,[[1,[-2]]],[],[]],[-1,-2,[],[]],[2,9],[2,[[5,[10]]]],[-1,[[11,[2]]],[[13,[12]]]],[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],[2,[[5,[10]]]],[-1,-2,[],[]],[-1,-2,[],[]],[[2,15],[[5,[10]]]],[[2,15],[[5,[9]]]],[[2,16],[[5,[3]]]],[[2,17],[[5,[3]]]],[[2,18],[[5,[9]]]],[[2,19],[[5,[10]]]],[-1,-2,[],[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,20,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,0,0,0,0,0,0,0,0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[21,21],[22,22],[23,23],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[-1,-2],3,[],[]],[[],23],0,0,[-1,[[5,[21]]],24],[-1,[[5,[22]]],24],[-1,[[5,[23]]],24],0,[[21,21],14],[[22,22],14],[[23,23],14],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[-1,-2],14,[],[]],[[21,6],7],[[22,6],7],[[23,6],7],[[25,6],7],[[25,6],7],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[12,[[5,[21,25]]]],0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,[[1,[-2]]],[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],[-1,[[3,[-2,14]]],[],[]],0,0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,26,[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,[[5,[-2]]],[],[]],[-1,20,[]],[-1,20,[]],[-1,20,[]],[-1,20,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[21,3],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,0,0,0,0,[[27,28],[[11,[[31,[29,30]]]]]],[27,[[11,[[31,[29,30]]]]]],[[27,28],[[11,[[31,[32,30]]]]]],[27,[[11,[[31,[32,30]]]]]],[33,9]],"c":[],"p":[[4,"Option",199],[3,"LinuxClock",3],[15,"tuple"],[3,"Duration",200],[4,"Result",201],[3,"Formatter",202],[6,"Result",202],[3,"timespec",203],[3,"Time",204],[3,"Timestamp",205],[6,"Result",206],[3,"Path",207],[8,"AsRef",208],[15,"bool"],[15,"f64"],[4,"LeapIndicator",205],[3,"TimePropertiesDS",209],[3,"Duration",210],[3,"TimeOffset",205],[3,"TypeId",211],[3,"Config",44],[3,"PortConfig",44],[4,"NetworkMode",44],[8,"Deserializer",212],[4,"ConfigError",44],[3,"String",213],[3,"InterfaceName",214],[4,"InterfaceTimestampMode",215],[3,"SocketAddrV4",216],[3,"Open",215],[3,"Socket",215],[3,"SocketAddrV6",216],[3,"Timestamp",215],[8,"PtpTargetAddress",189]]}\ +}'); +if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)}; +if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; diff --git a/docs/settings.html b/docs/settings.html new file mode 100644 index 000000000..eae7ece20 --- /dev/null +++ b/docs/settings.html @@ -0,0 +1 @@ +Rustdoc settings

Rustdoc settings

Back
\ No newline at end of file diff --git a/docs/src-files.js b/docs/src-files.js new file mode 100644 index 000000000..af3a9b0ce --- /dev/null +++ b/docs/src-files.js @@ -0,0 +1,5 @@ +var srcIndex = JSON.parse('{\ +"statime":["",[["bmc",[],["acceptable_master.rs","bmca.rs","dataset_comparison.rs","foreign_master.rs","mod.rs"]],["config",[],["instance.rs","mod.rs","port.rs"]],["datastructures",[["common",[],["clock_accuracy.rs","clock_identity.rs","clock_quality.rs","leap_indicator.rs","mod.rs","port_identity.rs","time_interval.rs","time_source.rs","timestamp.rs","tlv.rs"]],["datasets",[],["current.rs","default.rs","mod.rs","parent.rs","time_properties.rs"]],["messages",[],["announce.rs","control_field.rs","delay_req.rs","delay_resp.rs","follow_up.rs","header.rs","management.rs","mod.rs","p_delay_req.rs","p_delay_resp.rs","p_delay_resp_follow_up.rs","signalling.rs","sync.rs"]]],["mod.rs"]],["filters",[],["basic.rs","mod.rs"]],["port",[["state",[],["master.rs","mod.rs","slave.rs"]]],["measurement.rs","mod.rs","sequence_id.rs"]],["time",[],["duration.rs","instant.rs","interval.rs","mod.rs"]]],["clock.rs","lib.rs","ptp_instance.rs"]],\ +"statime_linux":["",[["clock",[],["mod.rs"]],["config",[],["mod.rs"]]],["lib.rs","socket.rs"]]\ +}'); +createSrcSidebar(); diff --git a/docs/src/statime/bmc/acceptable_master.rs.html b/docs/src/statime/bmc/acceptable_master.rs.html new file mode 100644 index 000000000..a2d81136a --- /dev/null +++ b/docs/src/statime/bmc/acceptable_master.rs.html @@ -0,0 +1,107 @@ +acceptable_master.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+
use crate::ClockIdentity;
+
+pub trait AcceptableMasterList {
+    fn is_acceptable(&self, identity: ClockIdentity) -> bool;
+}
+
+impl AcceptableMasterList for () {
+    fn is_acceptable(&self, _identity: ClockIdentity) -> bool {
+        true
+    }
+}
+
+impl AcceptableMasterList for &[ClockIdentity] {
+    fn is_acceptable(&self, identity: ClockIdentity) -> bool {
+        self.contains(&identity)
+    }
+}
+
+impl<const CAP: usize> AcceptableMasterList for arrayvec::ArrayVec<ClockIdentity, CAP> {
+    fn is_acceptable(&self, identity: ClockIdentity) -> bool {
+        self.contains(&identity)
+    }
+}
+
+#[cfg(feature = "std")]
+impl AcceptableMasterList for std::vec::Vec<ClockIdentity> {
+    fn is_acceptable(&self, identity: ClockIdentity) -> bool {
+        self.contains(&identity)
+    }
+}
+
+#[cfg(feature = "std")]
+impl AcceptableMasterList for std::collections::BTreeSet<ClockIdentity> {
+    fn is_acceptable(&self, identity: ClockIdentity) -> bool {
+        self.contains(&identity)
+    }
+}
+
+#[cfg(feature = "std")]
+impl AcceptableMasterList for std::collections::HashSet<ClockIdentity> {
+    fn is_acceptable(&self, identity: ClockIdentity) -> bool {
+        self.contains(&identity)
+    }
+}
+
+impl<T: AcceptableMasterList> AcceptableMasterList for Option<T> {
+    fn is_acceptable(&self, identity: ClockIdentity) -> bool {
+        match self {
+            Some(list) => list.is_acceptable(identity),
+            None => true,
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/bmc/bmca.rs.html b/docs/src/statime/bmc/bmca.rs.html new file mode 100644 index 000000000..17938e893 --- /dev/null +++ b/docs/src/statime/bmc/bmca.rs.html @@ -0,0 +1,1465 @@ +bmca.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+
//! Implementation of the best master clock algorithm [Bmca]
+
+use core::cmp::Ordering;
+
+use super::{
+    acceptable_master::AcceptableMasterList,
+    dataset_comparison::{ComparisonDataset, DatasetOrdering},
+    foreign_master::ForeignMasterList,
+};
+use crate::{
+    datastructures::{
+        common::{PortIdentity, TimeInterval},
+        datasets::DefaultDS,
+        messages::{AnnounceMessage, Header},
+    },
+    port::state::PortState,
+    Duration,
+};
+
+/// Object implementing the Best Master Clock Algorithm
+///
+/// Usage:
+///
+/// - Every port has its own instance.
+/// - When a port receives an announce message, it has to register it with the
+///   [Bmca::register_announce_message] method
+/// - When it is time to run the algorithm, the ptp runtime has to take all the
+///   best announce messages using [Bmca::take_best_port_announce_message]
+/// - Of the resulting set, the best global one needs to be determined. This can
+///   be done using [Bmca::find_best_announce_message]
+/// - Then to get the recommended state for each port,
+///   [Bmca::calculate_recommended_state] needs to be called
+#[derive(Debug)]
+pub(crate) struct Bmca<A> {
+    foreign_master_list: ForeignMasterList,
+    acceptable_master_list: A,
+    own_port_identity: PortIdentity,
+}
+
+impl<A> Bmca<A> {
+    pub(crate) fn new(
+        acceptable_master_list: A,
+        own_port_announce_interval: TimeInterval,
+        own_port_identity: PortIdentity,
+    ) -> Self {
+        Self {
+            foreign_master_list: ForeignMasterList::new(
+                own_port_announce_interval,
+                own_port_identity,
+            ),
+            acceptable_master_list,
+            own_port_identity,
+        }
+    }
+
+    pub(crate) fn step_age(&mut self, step: Duration) {
+        self.foreign_master_list.step_age(step);
+    }
+
+    /// Finds the best announce message in the given iterator.
+    /// The port identity in the tuple is the identity of the port that received
+    /// the announce message.
+    pub(crate) fn find_best_announce_message(
+        announce_messages: impl IntoIterator<Item = BestAnnounceMessage>,
+    ) -> Option<BestAnnounceMessage> {
+        announce_messages
+            .into_iter()
+            .max_by(BestAnnounceMessage::compare)
+    }
+
+    fn compare_d0_best(
+        d0: &ComparisonDataset,
+        opt_best: Option<BestAnnounceMessage>,
+    ) -> MessageComparison {
+        match opt_best {
+            None => MessageComparison::Better,
+            Some(best) => {
+                let dataset =
+                    ComparisonDataset::from_announce_message(&best.message, &best.identity);
+
+                match d0.compare(&dataset).as_ordering() {
+                    Ordering::Less => MessageComparison::Worse(best),
+                    Ordering::Equal => MessageComparison::Same,
+                    Ordering::Greater => MessageComparison::Better,
+                }
+            }
+        }
+    }
+
+    /// Calculates the recommended port state. This has to be run for every
+    /// port. The PTP spec calls this the State Decision Algorithm.
+    ///
+    /// - `own_data`: Called 'D0' by the PTP spec. The DefaultDS data of our own
+    ///   ptp instance.
+    /// - `best_global_announce_message`: Called 'Ebest' by the PTP spec. This
+    ///   is the best announce message and the
+    /// identity of the port that received it of all of the best port announce
+    /// messages.
+    /// - `best_port_announce_message`: Called 'Erbest' by the PTP spec. This is
+    ///   the best announce message and the
+    /// identity of the port that received it of the port we are calculating the
+    /// recommended state for.
+    /// - `port_state`: The current state of the port we are doing the
+    ///   calculation for.
+    ///
+    /// If None is returned, then the port should remain in the same state as it
+    /// is now.
+    pub(crate) fn calculate_recommended_state<F>(
+        own_data: &DefaultDS,
+        best_global_announce_message: Option<BestAnnounceMessage>,
+        best_port_announce_message: Option<BestAnnounceMessage>,
+        port_state: &PortState<F>,
+    ) -> Option<RecommendedState> {
+        if best_global_announce_message.is_none() && matches!(port_state, PortState::Listening) {
+            None
+        } else if (1..=127).contains(&own_data.clock_quality.clock_class) {
+            // only consider the best message of the port
+            Some(Self::calculate_recommended_state_low_class(
+                own_data,
+                best_port_announce_message,
+            ))
+        } else {
+            // see if the best of this port is better than the global best
+            Some(Self::calculate_recommended_state_high_class(
+                own_data,
+                best_global_announce_message,
+                best_port_announce_message,
+            ))
+        }
+    }
+
+    fn calculate_recommended_state_low_class(
+        own_data: &DefaultDS,
+        best_port_announce_message: Option<BestAnnounceMessage>,
+    ) -> RecommendedState {
+        let d0 = ComparisonDataset::from_own_data(own_data);
+
+        match Self::compare_d0_best(&d0, best_port_announce_message) {
+            MessageComparison::Better => RecommendedState::M1(*own_data),
+            MessageComparison::Same => RecommendedState::M1(*own_data),
+            MessageComparison::Worse(port) => RecommendedState::P1(port.message),
+        }
+    }
+
+    fn calculate_recommended_state_high_class(
+        own_data: &DefaultDS,
+        best_global_announce_message: Option<BestAnnounceMessage>,
+        best_port_announce_message: Option<BestAnnounceMessage>,
+    ) -> RecommendedState {
+        let d0 = ComparisonDataset::from_own_data(own_data);
+
+        match Self::compare_d0_best(&d0, best_global_announce_message) {
+            MessageComparison::Better => RecommendedState::M2(*own_data),
+            MessageComparison::Same => RecommendedState::M2(*own_data),
+            MessageComparison::Worse(global_message) => match best_port_announce_message {
+                None => RecommendedState::M3(global_message.message),
+                Some(port_message) => Self::compare_global_and_port(global_message, port_message),
+            },
+        }
+    }
+
+    fn compare_global_and_port(
+        global_message: BestAnnounceMessage,
+        port_message: BestAnnounceMessage,
+    ) -> RecommendedState {
+        if global_message == port_message {
+            // effectively, E_best == E_rbest
+            RecommendedState::S1(global_message.message)
+        } else {
+            let ebest = ComparisonDataset::from_announce_message(
+                &global_message.message,
+                &global_message.identity,
+            );
+
+            let erbest = ComparisonDataset::from_announce_message(
+                &port_message.message,
+                &port_message.identity,
+            );
+
+            // E_best better by topology than E_rbest
+            if matches!(ebest.compare(&erbest), DatasetOrdering::BetterByTopology) {
+                RecommendedState::P2(port_message.message)
+            } else {
+                RecommendedState::M3(global_message.message)
+            }
+        }
+    }
+}
+
+impl<A: AcceptableMasterList> Bmca<A> {
+    /// Register a received announce message to the BMC algorithm
+    pub(crate) fn register_announce_message(
+        &mut self,
+        header: &Header,
+        announce_message: &AnnounceMessage,
+    ) {
+        // Ignore messages comming from the same port
+        if announce_message.header.source_port_identity != self.own_port_identity
+            && self
+                .acceptable_master_list
+                .is_acceptable(announce_message.header.source_port_identity.clock_identity)
+        {
+            self.foreign_master_list.register_announce_message(
+                header,
+                announce_message,
+                Duration::ZERO,
+            );
+        }
+    }
+
+    pub(crate) fn reregister_announce_message(
+        &mut self,
+        header: &Header,
+        announce_message: &AnnounceMessage,
+        age: Duration,
+    ) {
+        // Ignore messages comming from the same port
+        if announce_message.header.source_port_identity != self.own_port_identity
+            && self
+                .acceptable_master_list
+                .is_acceptable(announce_message.header.source_port_identity.clock_identity)
+        {
+            self.foreign_master_list
+                .register_announce_message(header, announce_message, age);
+        }
+    }
+
+    /// Takes the Erbest from this port
+    pub(crate) fn take_best_port_announce_message(&mut self) -> Option<BestAnnounceMessage> {
+        // Find the announce message we want to use from each foreign master that has
+        // qualified messages
+        let announce_messages = self.foreign_master_list.take_qualified_announce_messages();
+
+        // The best of the foreign master messages is our erbest
+        let erbest = Self::find_best_announce_message(announce_messages.map(|message| {
+            BestAnnounceMessage {
+                header: message.header,
+                message: message.message,
+                age: message.age,
+                identity: self.own_port_identity,
+            }
+        }));
+
+        if let Some(best) = &erbest {
+            // All messages that were considered have been removed from the
+            // foreignmasterlist. However, the one that has been selected as the
+            // Erbest must not be removed, so let's just reregister it.
+            self.reregister_announce_message(&best.header, &best.message, best.age);
+        }
+
+        erbest
+    }
+}
+
+#[derive(Debug)]
+enum MessageComparison {
+    Better,
+    Same,
+    Worse(BestAnnounceMessage),
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) struct BestAnnounceMessage {
+    header: Header,
+    message: AnnounceMessage,
+    age: Duration,
+    identity: PortIdentity,
+}
+
+impl BestAnnounceMessage {
+    fn compare(&self, other: &Self) -> Ordering {
+        // use the age as a tie-break if needed (prefer newer messages)
+        let tie_break = other.age.cmp(&self.age);
+        self.compare_dataset(other).as_ordering().then(tie_break)
+    }
+
+    fn compare_dataset(&self, other: &Self) -> DatasetOrdering {
+        let data1 = ComparisonDataset::from_announce_message(&self.message, &self.identity);
+        let data2 = ComparisonDataset::from_announce_message(&other.message, &other.identity);
+
+        data1.compare(&data2)
+    }
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) enum RecommendedState {
+    M1(DefaultDS),
+    M2(DefaultDS),
+    M3(AnnounceMessage),
+    P1(AnnounceMessage),
+    P2(AnnounceMessage),
+    S1(AnnounceMessage),
+}
+
+#[cfg(test)]
+
+mod tests {
+    use super::*;
+    use crate::{
+        config::InstanceConfig,
+        datastructures::messages::{Header, PtpVersion},
+        ClockIdentity,
+    };
+
+    fn default_announce_message_header() -> Header {
+        Header {
+            sdo_id: Default::default(),
+            version: PtpVersion::new(2, 1).unwrap(),
+            domain_number: Default::default(),
+            alternate_master_flag: false,
+            two_step_flag: false,
+            unicast_flag: false,
+            ptp_profile_specific_1: false,
+            ptp_profile_specific_2: false,
+            leap61: false,
+            leap59: false,
+            current_utc_offset_valid: false,
+            ptp_timescale: false,
+            time_tracable: false,
+            frequency_tracable: false,
+            synchronization_uncertain: false,
+            correction_field: Default::default(),
+            source_port_identity: Default::default(),
+            sequence_id: Default::default(),
+            log_message_interval: Default::default(),
+        }
+    }
+
+    fn default_announce_message() -> AnnounceMessage {
+        AnnounceMessage {
+            header: default_announce_message_header(),
+            origin_timestamp: Default::default(),
+            current_utc_offset: Default::default(),
+            grandmaster_priority_1: Default::default(),
+            grandmaster_clock_quality: Default::default(),
+            grandmaster_priority_2: Default::default(),
+            grandmaster_identity: Default::default(),
+            steps_removed: Default::default(),
+            time_source: Default::default(),
+        }
+    }
+
+    fn default_best_announce_message() -> BestAnnounceMessage {
+        let header = default_announce_message_header();
+        let message = default_announce_message();
+
+        let identity = PortIdentity {
+            clock_identity: ClockIdentity([0; 8]),
+            port_number: 0,
+        };
+
+        BestAnnounceMessage {
+            header,
+            message,
+            age: Duration::ZERO,
+            identity,
+        }
+    }
+
+    #[test]
+    fn test_master_registration() {
+        let mut bmca = Bmca::new((), TimeInterval(100.into()), PortIdentity::default());
+        let mut announce = default_announce_message();
+        announce.header.source_port_identity.clock_identity.0 = [1, 2, 3, 4, 5, 6, 7, 8];
+
+        bmca.register_announce_message(&announce.header, &announce);
+        bmca.register_announce_message(&announce.header, &announce);
+        bmca.register_announce_message(&announce.header, &announce);
+
+        assert!(bmca.take_best_port_announce_message().is_some());
+        assert!(bmca.take_best_port_announce_message().is_some());
+    }
+
+    #[test]
+    fn test_acceptable_master_filter() {
+        let mut bmca = Bmca::new(
+            std::vec![],
+            TimeInterval(100.into()),
+            PortIdentity::default(),
+        );
+        let mut announce = default_announce_message();
+        announce.header.source_port_identity.clock_identity.0 = [1, 2, 3, 4, 5, 6, 7, 8];
+
+        bmca.register_announce_message(&announce.header, &announce);
+        bmca.register_announce_message(&announce.header, &announce);
+        bmca.register_announce_message(&announce.header, &announce);
+
+        assert!(bmca.take_best_port_announce_message().is_none());
+    }
+
+    #[test]
+    fn best_announce_message_compare_equal() {
+        let message1 = default_best_announce_message();
+        let message2 = default_best_announce_message();
+
+        let ordering = message1.compare_dataset(&message2).as_ordering();
+        assert_eq!(ordering, Ordering::Equal);
+    }
+
+    #[test]
+    fn best_announce_message_compare() {
+        let mut message1 = default_best_announce_message();
+        let mut message2 = default_best_announce_message();
+
+        // identities are different
+        message1.message.grandmaster_identity = ClockIdentity([0; 8]);
+        message2.message.grandmaster_identity = ClockIdentity([1; 8]);
+
+        // higher priority is worse in this ordering
+        message1.message.grandmaster_priority_1 = 0;
+        message2.message.grandmaster_priority_1 = 1;
+
+        // hence we expect message1 to be better than message2
+        assert_eq!(message1.compare_dataset(&message2), DatasetOrdering::Better);
+        assert_eq!(message2.compare_dataset(&message1), DatasetOrdering::Worse);
+
+        assert_eq!(message1.compare(&message2), Ordering::Greater);
+        assert_eq!(message2.compare(&message1), Ordering::Less);
+    }
+
+    #[test]
+    fn best_announce_message_max_tie_break() {
+        let mut message1 = default_best_announce_message();
+        let mut message2 = default_best_announce_message();
+
+        message1.age = Duration::from_micros(2);
+        message2.age = Duration::from_micros(1);
+
+        // the newest message should be preferred
+        assert!(message2.age < message1.age);
+
+        let ordering = message1.compare_dataset(&message2).as_ordering();
+        assert_eq!(ordering, Ordering::Equal);
+
+        // so message1 is lower in the ordering than message2
+        assert_eq!(message1.compare(&message2), Ordering::Less)
+    }
+
+    fn default_own_data() -> DefaultDS {
+        let clock_identity = Default::default();
+        let priority_1 = 0;
+        let priority_2 = 0;
+        let domain_number = 0;
+        let slave_only = false;
+        let sdo_id = Default::default();
+
+        DefaultDS::new(InstanceConfig {
+            clock_identity,
+            priority_1,
+            priority_2,
+            domain_number,
+            slave_only,
+            sdo_id,
+        })
+    }
+
+    #[test]
+    fn recommend_state_no_best() {
+        let mut own_data = default_own_data();
+
+        // zero is reserved
+        own_data.clock_quality.clock_class = 1;
+
+        let call = |port_state: &PortState<()>| {
+            Bmca::<()>::calculate_recommended_state(&own_data, None, None, port_state)
+        };
+
+        // when E_best is empty and the port state is listening, it should remain
+        // listening
+        assert!(call(&PortState::Listening).is_none());
+
+        // otherwise it should return a recommendation
+        assert!(matches!(
+            call(&PortState::Passive),
+            Some(RecommendedState::M1(_))
+        ))
+    }
+
+    #[test]
+    fn recommend_state_low_class() {
+        let clock_identity = Default::default();
+        let priority_1 = 0;
+        let priority_2 = 0;
+        let domain_number = 0;
+        let slave_only = false;
+        let sdo_id = Default::default();
+
+        let mut own_data = DefaultDS::new(InstanceConfig {
+            clock_identity,
+            priority_1,
+            priority_2,
+            domain_number,
+            slave_only,
+            sdo_id,
+        });
+
+        own_data.clock_quality.clock_class = 1;
+        assert!((1..=127).contains(&own_data.clock_quality.clock_class));
+
+        // D0 is the same as E_rbest; this is unreachable in practice, but we return M1
+        // in this case
+        let d0 = ComparisonDataset::from_own_data(&own_data);
+        let port_message = default_best_announce_message();
+
+        assert!(matches!(
+            Bmca::<()>::compare_d0_best(&d0, Some(port_message)),
+            MessageComparison::Same
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::M1(own_data)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                None,
+                Some(port_message),
+                &PortState::Passive,
+            )
+        );
+
+        // D0 is the better than E_rbest; M1 is expected
+        let d0 = ComparisonDataset::from_own_data(&own_data);
+        let mut port_message = default_best_announce_message();
+
+        port_message.identity.port_number = 1;
+
+        assert!(matches!(
+            Bmca::<()>::compare_d0_best(&d0, Some(port_message)),
+            MessageComparison::Better
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::M1(own_data)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                None,
+                Some(port_message),
+                &PortState::Passive,
+            )
+        );
+
+        // D0 is NOT better than E_rbest; P1 is expected
+        let mut own_data = own_data;
+
+        let mut port_message = default_best_announce_message();
+
+        own_data.clock_identity = ClockIdentity([0; 8]);
+        port_message.message.grandmaster_identity = ClockIdentity([1; 8]);
+
+        own_data.priority_1 = 1;
+        port_message.message.grandmaster_priority_1 = 0;
+
+        let d0 = ComparisonDataset::from_own_data(&own_data);
+
+        assert!(matches!(
+            Bmca::<()>::compare_d0_best(&d0, Some(port_message)),
+            MessageComparison::Worse(_)
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::P1(port_message.message)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                None,
+                Some(port_message),
+                &PortState::Passive,
+            )
+        );
+    }
+
+    #[test]
+    fn recommend_state_high() {
+        let mut own_data = default_own_data();
+
+        own_data.clock_quality.clock_class = 128;
+        assert!(!(1..=127).contains(&own_data.clock_quality.clock_class));
+
+        // D0 is the same as E_best; this is unreachable in practice, but we return M2
+        // in this case
+        let d0 = ComparisonDataset::from_own_data(&own_data);
+        let global_message = default_best_announce_message();
+
+        assert!(matches!(
+            Bmca::<()>::compare_d0_best(&d0, Some(global_message)),
+            MessageComparison::Same
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::M2(own_data)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                Some(global_message),
+                None,
+                &PortState::Passive,
+            )
+        );
+
+        // D0 is better than E_best; M1 is expected
+        let d0 = ComparisonDataset::from_own_data(&own_data);
+        let mut global_message = default_best_announce_message();
+
+        global_message.identity.port_number = 1;
+
+        assert!(matches!(
+            Bmca::<()>::compare_d0_best(&d0, Some(global_message)),
+            MessageComparison::Better
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::M2(own_data)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                Some(global_message),
+                None,
+                &PortState::Passive,
+            )
+        );
+
+        // D0 is NOT better than E_best
+        let mut own_data = own_data;
+
+        let mut global_message = default_best_announce_message();
+
+        own_data.clock_identity = ClockIdentity([0; 8]);
+        global_message.message.grandmaster_identity = ClockIdentity([1; 8]);
+
+        own_data.priority_1 = 1;
+        global_message.message.grandmaster_priority_1 = 0;
+
+        let d0 = ComparisonDataset::from_own_data(&own_data);
+
+        assert!(matches!(
+            Bmca::<()>::compare_d0_best(&d0, Some(global_message)),
+            MessageComparison::Worse(_)
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::S1(global_message.message)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                Some(global_message),
+                Some(global_message),
+                &PortState::Passive,
+            )
+        );
+    }
+
+    #[test]
+    fn ebest_better_by_topology_no() {
+        let mut own_data = default_own_data();
+        let mut global_message = default_best_announce_message();
+
+        // take the erest branch
+        own_data.clock_quality.clock_class = 128;
+
+        own_data.clock_identity = ClockIdentity([0; 8]);
+        global_message.message.grandmaster_identity = ClockIdentity([1; 8]);
+
+        own_data.priority_1 = 1;
+        global_message.message.grandmaster_priority_1 = 0;
+
+        let mut port_message = global_message;
+
+        global_message.age = Duration::from_micros(4);
+        port_message.age = Duration::from_micros(2);
+
+        let ebest = ComparisonDataset::from_announce_message(
+            &global_message.message,
+            &global_message.identity,
+        );
+
+        let erbest =
+            ComparisonDataset::from_announce_message(&port_message.message, &port_message.identity);
+
+        assert!(!matches!(
+            ebest.compare(&erbest),
+            DatasetOrdering::BetterByTopology
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::M3(global_message.message)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                Some(global_message),
+                Some(port_message),
+                &PortState::Passive,
+            )
+        );
+    }
+
+    #[test]
+    fn ebest_better_by_topology_yes() {
+        let mut own_data = default_own_data();
+        let mut global_message = default_best_announce_message();
+
+        // take the erest branch
+        own_data.clock_quality.clock_class = 128;
+
+        own_data.clock_identity = ClockIdentity([0; 8]);
+        global_message.message.grandmaster_identity = ClockIdentity([1; 8]);
+
+        own_data.priority_1 = 1;
+        global_message.message.grandmaster_priority_1 = 0;
+
+        let mut port_message = global_message;
+
+        global_message.age = Duration::from_micros(4);
+        port_message.age = Duration::from_micros(2);
+
+        let ebest = ComparisonDataset::from_announce_message(
+            &global_message.message,
+            &global_message.identity,
+        );
+
+        let erbest =
+            ComparisonDataset::from_announce_message(&port_message.message, &port_message.identity);
+
+        assert!(!matches!(
+            ebest.compare(&erbest),
+            DatasetOrdering::BetterByTopology
+        ));
+
+        assert_eq!(
+            Some(RecommendedState::M3(global_message.message)),
+            Bmca::<()>::calculate_recommended_state::<()>(
+                &own_data,
+                Some(global_message),
+                Some(port_message),
+                &PortState::Passive,
+            )
+        );
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/bmc/dataset_comparison.rs.html b/docs/src/statime/bmc/dataset_comparison.rs.html new file mode 100644 index 000000000..8e75efb91 --- /dev/null +++ b/docs/src/statime/bmc/dataset_comparison.rs.html @@ -0,0 +1,535 @@ +dataset_comparison.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+
//! Implementation of chapter 9.3.4 Data set comparison algorithm
+
+use core::cmp::Ordering;
+
+use crate::datastructures::{
+    common::{ClockIdentity, ClockQuality, PortIdentity},
+    datasets::DefaultDS,
+    messages::AnnounceMessage,
+};
+
+/// A collection of data that is gathered from other sources (mainly announce
+/// messages and the DefaultDS). When gathered from two different sources, the
+/// [compare](crate::bmc::dataset_comparison::ComparisonDataset) method can be
+/// used to find out which source is better according to the dataset comparison
+/// algorithm.
+#[derive(Eq, PartialEq, Default, Debug)]
+pub(crate) struct ComparisonDataset {
+    gm_priority_1: u8,
+    gm_identity: ClockIdentity,
+    gm_clock_quality: ClockQuality,
+    gm_priority_2: u8,
+    steps_removed: u16,
+    identity_of_senders: ClockIdentity,
+    identity_of_receiver: PortIdentity,
+}
+
+impl ComparisonDataset {
+    /// Create a ComparisonDataset from the data in an announce message and the
+    /// port identity of the port that received the announce message
+    pub(crate) fn from_announce_message(
+        message: &AnnounceMessage,
+        port_receiver_identity: &PortIdentity,
+    ) -> Self {
+        Self {
+            gm_priority_1: message.grandmaster_priority_1,
+            gm_identity: message.grandmaster_identity,
+            gm_clock_quality: message.grandmaster_clock_quality,
+            gm_priority_2: message.grandmaster_priority_2,
+            steps_removed: message.steps_removed,
+            identity_of_senders: message.header.source_port_identity.clock_identity,
+            identity_of_receiver: *port_receiver_identity,
+        }
+    }
+
+    pub(crate) fn from_own_data(data: &DefaultDS) -> Self {
+        Self {
+            gm_priority_1: data.priority_1,
+            gm_identity: data.clock_identity,
+            gm_clock_quality: data.clock_quality,
+            gm_priority_2: data.priority_2,
+            steps_removed: 0,
+            identity_of_senders: data.clock_identity,
+            identity_of_receiver: PortIdentity {
+                clock_identity: data.clock_identity,
+                port_number: 0,
+            },
+        }
+    }
+
+    /// Returns the ordering of `self` in comparison to other.
+    pub(crate) fn compare(&self, other: &Self) -> DatasetOrdering {
+        if self.gm_identity == other.gm_identity {
+            Self::compare_same_identity(self, other)
+        } else {
+            Self::compare_different_identity(self, other)
+        }
+    }
+
+    /// PTP grandmaster instances are different
+    fn compare_different_identity(&self, other: &Self) -> DatasetOrdering {
+        let self_quality = self.gm_clock_quality;
+        let other_quality = other.gm_clock_quality;
+
+        // Figure 34
+        let ordering = (self.gm_priority_1.cmp(&other.gm_priority_1))
+            .then_with(|| self_quality.clock_class.cmp(&other_quality.clock_class))
+            // The spec assumes numerical ordering (which is the reverse of the semantic ordering)
+            .then_with(|| self_quality.clock_accuracy.cmp_numeric(&other_quality.clock_accuracy))
+            .then_with(|| self_quality.offset_scaled_log_variance.cmp(&other_quality.offset_scaled_log_variance))
+            .then_with(|| self.gm_priority_2.cmp(&other.gm_priority_2))
+            .then_with(|| self.gm_identity.cmp(&other.gm_identity));
+
+        match ordering {
+            Ordering::Equal => unreachable!("gm_identity is guaranteed to be different"),
+            Ordering::Greater => DatasetOrdering::Worse,
+            Ordering::Less => DatasetOrdering::Better,
+        }
+    }
+
+    /// Potentially the same PTP grandmaster instance
+    fn compare_same_identity(&self, other: &Self) -> DatasetOrdering {
+        let steps_removed_difference = self.steps_removed as i32 - other.steps_removed as i32;
+
+        // Figure 35
+        match steps_removed_difference {
+            2..=i32::MAX => DatasetOrdering::Worse,
+            i32::MIN..=-2 => DatasetOrdering::Better,
+            1 => match Ord::cmp(
+                &self.identity_of_receiver.clock_identity,
+                &self.identity_of_senders,
+            ) {
+                Ordering::Less => DatasetOrdering::Better,
+                Ordering::Equal => DatasetOrdering::Error1,
+                Ordering::Greater => DatasetOrdering::BetterByTopology,
+            },
+            -1 => match Ord::cmp(
+                &other.identity_of_receiver.clock_identity,
+                &other.identity_of_senders,
+            ) {
+                Ordering::Less => DatasetOrdering::Worse,
+                Ordering::Equal => DatasetOrdering::Error1,
+                Ordering::Greater => DatasetOrdering::WorseByTopology,
+            },
+            0 => {
+                let senders = self.identity_of_senders.cmp(&other.identity_of_senders);
+                let receivers = Ord::cmp(
+                    &self.identity_of_receiver.port_number,
+                    &other.identity_of_receiver.port_number,
+                );
+
+                match senders.then(receivers) {
+                    Ordering::Less => DatasetOrdering::BetterByTopology,
+                    Ordering::Equal => DatasetOrdering::Error2,
+                    Ordering::Greater => DatasetOrdering::WorseByTopology,
+                }
+            }
+        }
+    }
+}
+
+/// The ordering result of the dataset comparison algorithm
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DatasetOrdering {
+    /// The [ComparisonDataset] is better than the one being compared against
+    Better,
+    /// The [ComparisonDataset] is of equal quality as the one being compared
+    /// against, but is preferred because of the network topology
+    BetterByTopology,
+    /// The [ComparisonDataset] is equal in quality and topology
+    Error1,
+    /// The [ComparisonDataset] is probably based on the same set of data
+    Error2,
+    /// The [ComparisonDataset] is of equal quality as the one being compared
+    /// against, but is not preferred because of the network topology
+    WorseByTopology,
+    /// The [ComparisonDataset] is worse than the one being compared against
+    Worse,
+}
+
+impl DatasetOrdering {
+    pub const fn as_ordering(self) -> Ordering {
+        // We get errors if two announce messages are (functionally) the same
+        // in that case either option is a valid choice
+        match self {
+            DatasetOrdering::Better | DatasetOrdering::BetterByTopology => Ordering::Greater,
+            DatasetOrdering::Error1 | DatasetOrdering::Error2 => Ordering::Equal,
+            DatasetOrdering::WorseByTopology | DatasetOrdering::Worse => Ordering::Less,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::datastructures::common::ClockAccuracy;
+
+    const IDENTITY_A: ClockIdentity = ClockIdentity([1, 1, 1, 1, 1, 1, 1, 1]);
+    const IDENTITY_B: ClockIdentity = ClockIdentity([2, 2, 2, 2, 2, 2, 2, 2]);
+    const IDENTITY_C: ClockIdentity = ClockIdentity([3, 3, 3, 3, 3, 3, 3, 3]);
+
+    fn get_default_test_pair() -> (ComparisonDataset, ComparisonDataset) {
+        Default::default()
+    }
+
+    #[test]
+    fn figure_34() {
+        // Start with two identical datasets
+        let (mut a, mut b) = get_default_test_pair();
+
+        // Now we work bottom up to test everything
+        // Every time we we change which one is better or worse so we know that it's not
+        // still the previous result coming through
+
+        a.gm_identity = IDENTITY_A;
+        b.gm_identity = IDENTITY_B;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Better);
+        assert_eq!(b.compare(&a), DatasetOrdering::Worse);
+
+        a.gm_priority_2 = 1;
+        b.gm_priority_2 = 0;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Worse);
+        assert_eq!(b.compare(&a), DatasetOrdering::Better);
+
+        a.gm_clock_quality.offset_scaled_log_variance = 0;
+        b.gm_clock_quality.offset_scaled_log_variance = 1;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Better);
+        assert_eq!(b.compare(&a), DatasetOrdering::Worse);
+
+        a.gm_clock_quality.clock_accuracy = ClockAccuracy::US1;
+        b.gm_clock_quality.clock_accuracy = ClockAccuracy::NS1;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Worse);
+        assert_eq!(b.compare(&a), DatasetOrdering::Better);
+
+        a.gm_clock_quality.clock_class = 0;
+        b.gm_clock_quality.clock_class = 1;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Better);
+        assert_eq!(b.compare(&a), DatasetOrdering::Worse);
+
+        a.gm_priority_1 = 1;
+        b.gm_priority_1 = 0;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Worse);
+        assert_eq!(b.compare(&a), DatasetOrdering::Better);
+    }
+
+    #[test]
+    fn figure_35() {
+        let (mut a, mut b) = get_default_test_pair();
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Error2);
+        assert_eq!(b.compare(&a), DatasetOrdering::Error2);
+
+        a.identity_of_receiver.port_number = 1;
+        b.identity_of_receiver.port_number = 0;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::WorseByTopology);
+        assert_eq!(b.compare(&a), DatasetOrdering::BetterByTopology);
+
+        a.identity_of_senders = IDENTITY_A;
+        b.identity_of_senders = IDENTITY_B;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::BetterByTopology);
+        assert_eq!(b.compare(&a), DatasetOrdering::WorseByTopology);
+
+        a.steps_removed = 0;
+        a.identity_of_receiver.clock_identity = IDENTITY_A;
+        b.steps_removed = 1;
+        b.identity_of_receiver.clock_identity = IDENTITY_B;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Error1);
+        assert_eq!(b.compare(&a), DatasetOrdering::Error1);
+
+        a.identity_of_receiver.clock_identity = IDENTITY_B;
+        b.identity_of_receiver.clock_identity = IDENTITY_C;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::WorseByTopology);
+        assert_eq!(b.compare(&a), DatasetOrdering::BetterByTopology);
+
+        // the inverse of the identity_of_senders
+        a.identity_of_receiver.clock_identity = IDENTITY_B;
+        b.identity_of_receiver.clock_identity = IDENTITY_A;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Worse);
+        assert_eq!(b.compare(&a), DatasetOrdering::Better);
+
+        a.steps_removed = 0;
+        b.steps_removed = 2;
+
+        assert_eq!(a.compare(&b), DatasetOrdering::Better);
+        assert_eq!(b.compare(&a), DatasetOrdering::Worse);
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/bmc/foreign_master.rs.html b/docs/src/statime/bmc/foreign_master.rs.html new file mode 100644 index 000000000..a910324ac --- /dev/null +++ b/docs/src/statime/bmc/foreign_master.rs.html @@ -0,0 +1,503 @@ +foreign_master.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+
//! Implementation of the [ForeignMasterList]
+
+use arrayvec::ArrayVec;
+
+use crate::{
+    datastructures::{
+        common::{PortIdentity, TimeInterval},
+        messages::{AnnounceMessage, Header},
+    },
+    time::Duration,
+};
+
+/// The time window in which announce messages are valid.
+/// To get the real window, multiply it with the announce interval of the port.
+const FOREIGN_MASTER_TIME_WINDOW: u16 = 4;
+
+/// This is the amount of announce messages that must have been received within
+/// the time window for a foreign master to be valid
+const FOREIGN_MASTER_THRESHOLD: usize = 2;
+
+/// The maximum amount of announce message to store within the time window
+const MAX_ANNOUNCE_MESSAGES: usize = 8;
+
+/// The maximum amount of foreign masters to store at the same time
+const MAX_FOREIGN_MASTERS: usize = 8;
+
+#[derive(Debug)]
+pub struct ForeignMaster {
+    foreign_master_port_identity: PortIdentity,
+    // Must have a capacity of at least 2
+    announce_messages: ArrayVec<ForeignAnnounceMessage, MAX_ANNOUNCE_MESSAGES>,
+}
+
+#[derive(Debug)]
+pub(crate) struct ForeignAnnounceMessage {
+    pub(crate) header: Header,
+    pub(crate) message: AnnounceMessage,
+    pub(crate) age: Duration,
+}
+
+impl ForeignMaster {
+    fn new(header: Header, announce_message: AnnounceMessage) -> Self {
+        let message = ForeignAnnounceMessage {
+            header,
+            message: announce_message,
+            age: Duration::ZERO,
+        };
+
+        let mut messages = ArrayVec::<_, MAX_ANNOUNCE_MESSAGES>::new();
+        messages.push(message);
+
+        Self {
+            foreign_master_port_identity: announce_message.header.source_port_identity,
+            announce_messages: messages,
+        }
+    }
+
+    fn foreign_master_port_identity(&self) -> PortIdentity {
+        self.foreign_master_port_identity
+    }
+
+    /// Removes all messages that fall outside of the
+    /// [FOREIGN_MASTER_TIME_WINDOW].
+    ///
+    /// Returns true if this foreign master has no more announce messages left.
+    fn purge_old_messages(&mut self, announce_interval: TimeInterval) -> bool {
+        let cutoff_age = Duration::from(announce_interval) * FOREIGN_MASTER_TIME_WINDOW;
+        self.announce_messages.retain(|m| m.age < cutoff_age);
+
+        self.announce_messages.is_empty()
+    }
+
+    fn register_announce_message(
+        &mut self,
+        header: Header,
+        announce_message: AnnounceMessage,
+        announce_interval: TimeInterval,
+        age: Duration,
+    ) {
+        self.purge_old_messages(announce_interval);
+
+        let new_message = ForeignAnnounceMessage {
+            header,
+            message: announce_message,
+            age,
+        };
+
+        // Try to add new message; otherwise remove the first message and then add
+        if let Err(e) = self.announce_messages.try_push(new_message) {
+            self.announce_messages.remove(0);
+            self.announce_messages.push(e.element());
+        }
+    }
+
+    fn step_age(&mut self, step: Duration, announce_interval: TimeInterval) -> bool {
+        for message in &mut self.announce_messages {
+            message.age += step;
+        }
+
+        self.purge_old_messages(announce_interval)
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct ForeignMasterList {
+    // Must have a capacity of at least 5
+    foreign_masters: ArrayVec<ForeignMaster, MAX_FOREIGN_MASTERS>,
+    own_port_announce_interval: TimeInterval,
+    own_port_identity: PortIdentity,
+}
+
+impl ForeignMasterList {
+    /// - `port_announce_interval`: The time interval derived from the
+    ///   PortDS.log_announce_interval
+    /// - `port_identity`: The identity of the port for which this list is used
+    pub(crate) fn new(
+        own_port_announce_interval: TimeInterval,
+        own_port_identity: PortIdentity,
+    ) -> Self {
+        Self {
+            foreign_masters: ArrayVec::<ForeignMaster, MAX_FOREIGN_MASTERS>::new(),
+            own_port_announce_interval,
+            own_port_identity,
+        }
+    }
+
+    pub(crate) fn step_age(&mut self, step: Duration) {
+        for i in (0..self.foreign_masters.len()).rev() {
+            // Purge the old timestamps so we can check the FOREIGN_MASTER_THRESHOLD
+            if self.foreign_masters[i].step_age(step, self.own_port_announce_interval) {
+                // There are no announce messages left, so let's remove this foreign master
+                self.foreign_masters.remove(i);
+                continue;
+            }
+        }
+    }
+
+    /// Takes the qualified announce message of all foreign masters that have
+    /// one
+    pub(crate) fn take_qualified_announce_messages(
+        &mut self,
+    ) -> impl Iterator<Item = ForeignAnnounceMessage> {
+        let mut qualified_foreign_masters = ArrayVec::<_, MAX_FOREIGN_MASTERS>::new();
+
+        for i in (0..self.foreign_masters.len()).rev() {
+            // A foreign master must have at least FOREIGN_MASTER_THRESHOLD messages in the
+            // last FOREIGN_MASTER_TIME_WINDOW to be qualified, so we filter out
+            // any that don't have that
+            if self.foreign_masters[i].announce_messages.len() > FOREIGN_MASTER_THRESHOLD {
+                // Only the most recent announce message is qualified, so we remove that one
+                // from the list
+                let last_index = self.foreign_masters[i].announce_messages.len() - 1;
+                qualified_foreign_masters
+                    .push(self.foreign_masters[i].announce_messages.remove(last_index));
+                continue;
+            }
+        }
+
+        qualified_foreign_masters.into_iter()
+    }
+
+    pub(crate) fn register_announce_message(
+        &mut self,
+        header: &Header,
+        announce_message: &AnnounceMessage,
+        age: Duration,
+    ) {
+        if !self.is_announce_message_qualified(announce_message) {
+            // We don't want to store unqualified messages
+            return;
+        }
+
+        let port_announce_interval = self.own_port_announce_interval;
+
+        // Is the foreign master that the message represents already known?
+        if let Some(foreign_master) =
+            self.get_foreign_master_mut(announce_message.header.source_port_identity)
+        {
+            // Yes, so add the announce message to it
+            foreign_master.register_announce_message(
+                *header,
+                *announce_message,
+                port_announce_interval,
+                age,
+            );
+        } else {
+            // No, insert a new foreign master, if there is room in the array
+            if self.foreign_masters.len() < MAX_FOREIGN_MASTERS {
+                self.foreign_masters
+                    .push(ForeignMaster::new(*header, *announce_message));
+            }
+        }
+    }
+
+    fn get_foreign_master_mut(
+        &mut self,
+        port_identity: PortIdentity,
+    ) -> Option<&mut ForeignMaster> {
+        self.foreign_masters
+            .iter_mut()
+            .find(|fm| fm.foreign_master_port_identity() == port_identity)
+    }
+
+    fn get_foreign_master(&self, port_identity: PortIdentity) -> Option<&ForeignMaster> {
+        self.foreign_masters
+            .iter()
+            .find(|fm| fm.foreign_master_port_identity() == port_identity)
+    }
+
+    fn is_announce_message_qualified(&self, announce_message: &AnnounceMessage) -> bool {
+        let source_identity = announce_message.header.source_port_identity;
+
+        // 1. The message must not come from our own ptp instance. Since every instance
+        // only has 1 clock, we can check the clock identity. That must be
+        // different.
+        if source_identity.clock_identity == self.own_port_identity.clock_identity {
+            return false;
+        }
+
+        // 2. The announce message must be newer than the one(s) we already have
+        // We can check the sequence id for that (with some logic for u16 rollover)
+        if let Some(foreign_master) = self.get_foreign_master(source_identity) {
+            if let Some(last_announce_message) = foreign_master.announce_messages.last() {
+                let announce_sequence_id = announce_message.header.sequence_id;
+                let last_sequence_id = last_announce_message.header.sequence_id;
+
+                if last_sequence_id >= FOREIGN_MASTER_TIME_WINDOW {
+                    if announce_sequence_id < last_sequence_id {
+                        return false;
+                    }
+                } else if announce_sequence_id - last_sequence_id
+                    > u16::MAX - FOREIGN_MASTER_TIME_WINDOW
+                {
+                    return false;
+                }
+            }
+        }
+
+        // 3. The announce message must not have a steps removed of 255 and greater
+        if announce_message.steps_removed >= 255 {
+            return false;
+        }
+
+        // 4. The announce message may not be from a foreign master with fewer messages
+        // than FOREIGN_MASTER_THRESHOLD, but that is handled in the
+        // `take_qualified_announce_messages` method.
+
+        // Otherwise, the announce message is qualified
+        true
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/bmc/mod.rs.html b/docs/src/statime/bmc/mod.rs.html new file mode 100644 index 000000000..572473eff --- /dev/null +++ b/docs/src/statime/bmc/mod.rs.html @@ -0,0 +1,13 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+
//! Implementation of the best master clock datastructures and logic
+
+pub mod acceptable_master;
+pub mod bmca;
+pub mod dataset_comparison;
+pub mod foreign_master;
+
\ No newline at end of file diff --git a/docs/src/statime/clock.rs.html b/docs/src/statime/clock.rs.html new file mode 100644 index 000000000..a31692deb --- /dev/null +++ b/docs/src/statime/clock.rs.html @@ -0,0 +1,97 @@ +clock.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+
//! Definitions and implementations of the abstract clock types
+
+use crate::{
+    datastructures::datasets::TimePropertiesDS,
+    time::{Duration, Time},
+};
+
+/// Clock manipulation and querying interface
+///
+/// The clock trait is the primary way the PTP stack interfaces with the
+/// system's clock. It's implementation should be provided by the user of the
+/// Statime crate, and should provide information on and ways to manipulate the
+/// system's clock. An implementation of this trait for linux is provided in the
+/// statime-linux crate.
+///
+/// Note that the clock implementation is responsible for handling leap seconds.
+/// On most operating systems, this will be provided for by the OS, but on some
+/// platforms this may require extra logic.
+pub trait Clock {
+    type Error: core::fmt::Debug;
+
+    /// Get the current time of the clock
+    fn now(&self) -> Time;
+
+    /// Change the current time of the clock by offset. Returns
+    /// the time at which the change was applied.
+    ///
+    /// The applied correction should be as close as possible to
+    /// the requested correction. The reported time of the change
+    /// should be as close as possible to the time the change was
+    /// applied
+    fn step_clock(&mut self, offset: Duration) -> Result<Time, Self::Error>;
+
+    /// Set the frequency of the clock, returning the time
+    /// at which the change was applied. The value is in ppm
+    /// difference from the clocks base frequency.
+    ///
+    /// The applied correction should be as close as possible to
+    /// the requested correction. The reported time of the change
+    /// should be as close as possible to the time the change was
+    /// applied
+    fn set_frequency(&mut self, ppm: f64) -> Result<Time, Self::Error>;
+
+    /// Adjust the timescale properties of the clock, including
+    /// things like the leap indicator, to the extend supported by the
+    /// system.
+    fn set_properties(&mut self, time_properties_ds: &TimePropertiesDS) -> Result<(), Self::Error>;
+}
+
\ No newline at end of file diff --git a/docs/src/statime/config/instance.rs.html b/docs/src/statime/config/instance.rs.html new file mode 100644 index 000000000..89ebf4087 --- /dev/null +++ b/docs/src/statime/config/instance.rs.html @@ -0,0 +1,23 @@ +instance.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+
use crate::{ClockIdentity, SdoId};
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub struct InstanceConfig {
+    pub clock_identity: ClockIdentity,
+    pub priority_1: u8,
+    pub priority_2: u8,
+    pub domain_number: u8,
+    pub slave_only: bool,
+    pub sdo_id: SdoId,
+}
+
\ No newline at end of file diff --git a/docs/src/statime/config/mod.rs.html b/docs/src/statime/config/mod.rs.html new file mode 100644 index 000000000..ebd2dd355 --- /dev/null +++ b/docs/src/statime/config/mod.rs.html @@ -0,0 +1,11 @@ +mod.rs - source
1
+2
+3
+4
+5
+
mod instance;
+mod port;
+
+pub use instance::InstanceConfig;
+pub use port::{DelayMechanism, PortConfig};
+
\ No newline at end of file diff --git a/docs/src/statime/config/port.rs.html b/docs/src/statime/config/port.rs.html new file mode 100644 index 000000000..cd2ac9562 --- /dev/null +++ b/docs/src/statime/config/port.rs.html @@ -0,0 +1,103 @@ +port.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+
use rand::Rng;
+
+use crate::{time::Interval, Duration};
+
+/// Which delay mechanism a port is using.
+///
+/// Currently, statime only supports the end to end (E2E) delay mechanism.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub enum DelayMechanism {
+    /// End to end delay mechanism. Delay measurement is done directly to the
+    /// chosen master, across potential transparent nodes in between.
+    ///
+    /// the interval corresponds to the PortDS logMinDelayReqInterval
+    E2E { interval: Interval },
+    // No support for other delay mechanisms
+}
+
+/// Configuration items of the PTP PortDS dataset. Dynamical fields are kept
+/// as part of [crate::port::Port].
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub struct PortConfig<A> {
+    pub acceptable_master_list: A,
+    pub delay_mechanism: DelayMechanism,
+    pub announce_interval: Interval,
+    // more like announce_message_retries. Specifies how many announce_intervals to wait until the
+    // announce message expires.
+    pub announce_receipt_timeout: u8,
+    pub sync_interval: Interval,
+    pub master_only: bool,
+    pub delay_asymmetry: Duration,
+    // Notes:
+    // Fields specific for delay mechanism are kept as part of [DelayMechanism].
+    // Version is always 2.1, so not stored (versionNumber, minorVersionNumber)
+}
+
+impl<A> PortConfig<A> {
+    pub fn min_delay_req_interval(&self) -> Interval {
+        match self.delay_mechanism {
+            DelayMechanism::E2E { interval } => interval,
+        }
+    }
+
+    // section 9.2.6.12
+    pub fn announce_duration(&self, rng: &mut impl Rng) -> core::time::Duration {
+        // add some randomness so that not all timers expire at the same time
+        let factor = 1.0 + rng.sample::<f64, _>(rand::distributions::Open01);
+        let duration = self.announce_interval.as_core_duration();
+
+        duration.mul_f64(factor * self.announce_receipt_timeout as u32 as f64)
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/clock_accuracy.rs.html b/docs/src/statime/datastructures/common/clock_accuracy.rs.html new file mode 100644 index 000000000..f67aa1b35 --- /dev/null +++ b/docs/src/statime/datastructures/common/clock_accuracy.rs.html @@ -0,0 +1,353 @@ +clock_accuracy.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+
use core::cmp::Ordering;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+/// How accurate the underlying clock device is expected to be when not
+/// synchronized.
+pub enum ClockAccuracy {
+    /// Reserved
+    Reserved,
+    /// Accurate within 1 ps
+    PS1,
+    /// Accurate within 2.5 ps
+    PS2_5,
+    /// Accurate within 10 ps
+    PS10,
+    /// Accurate within 25 ps
+    PS25,
+    /// Accurate within 100 ps
+    PS100,
+    /// Accurate within 250 ps
+    PS250,
+    /// Accurate within 1 ns
+    NS1,
+    /// Accurate within 2.5 ns
+    NS2_5,
+    /// Accurate within 10 ns
+    NS10,
+    /// Accurate within 25 ns
+    NS25,
+    /// Accurate within 100 ns
+    NS100,
+    /// Accurate within 250 ns
+    NS250,
+    /// Accurate within 1 us
+    US1,
+    /// Accurate within 2.5 us
+    US2_5,
+    /// Accurate within 10 us
+    US10,
+    /// Accurate within 25 us
+    US25,
+    /// Accurate within 100 us
+    US100,
+    /// Accurate within 250 us
+    US250,
+    /// Accurate within 1 ms
+    MS1,
+    /// Accurate within 2.5 ms
+    MS2_5,
+    /// Accurate within 10 ms
+    MS10,
+    /// Accurate within 25 ms
+    MS25,
+    /// Accurate within 100 ms
+    MS100,
+    /// Accurate within 250 ms
+    MS250,
+    /// Accurate within 1 s
+    S1,
+    /// Accurate within 10 s
+    S10,
+    /// Accurate within >10 s
+    SGT10,
+    /// Specific to a profile
+    ProfileSpecific(u8),
+    /// Accuracy is unknown
+    Unknown,
+}
+
+impl ClockAccuracy {
+    pub(crate) fn to_primitive(self) -> u8 {
+        match self {
+            Self::Reserved => 0x00,
+            Self::PS1 => 0x17,
+            Self::PS2_5 => 0x18,
+            Self::PS10 => 0x19,
+            Self::PS25 => 0x1a,
+            Self::PS100 => 0x1b,
+            Self::PS250 => 0x1c,
+            Self::NS1 => 0x1d,
+            Self::NS2_5 => 0x1e,
+            Self::NS10 => 0x1f,
+            Self::NS25 => 0x20,
+            Self::NS100 => 0x21,
+            Self::NS250 => 0x22,
+            Self::US1 => 0x23,
+            Self::US2_5 => 0x24,
+            Self::US10 => 0x25,
+            Self::US25 => 0x26,
+            Self::US100 => 0x27,
+            Self::US250 => 0x28,
+            Self::MS1 => 0x29,
+            Self::MS2_5 => 0x2a,
+            Self::MS10 => 0x2b,
+            Self::MS25 => 0x2c,
+            Self::MS100 => 0x2d,
+            Self::MS250 => 0x2e,
+            Self::S1 => 0x2f,
+            Self::S10 => 0x30,
+            Self::SGT10 => 0x31,
+            Self::ProfileSpecific(value) => 0x80 + value,
+            Self::Unknown => 0xfe,
+        }
+    }
+
+    pub(crate) fn from_primitive(value: u8) -> Self {
+        match value {
+            0x00..=0x16 | 0x32..=0x7f | 0xff => Self::Reserved,
+            0x17 => Self::PS1,
+            0x18 => Self::PS2_5,
+            0x19 => Self::PS10,
+            0x1a => Self::PS25,
+            0x1b => Self::PS100,
+            0x1c => Self::PS250,
+            0x1d => Self::NS1,
+            0x1e => Self::NS2_5,
+            0x1f => Self::NS10,
+            0x20 => Self::NS25,
+            0x21 => Self::NS100,
+            0x22 => Self::NS250,
+            0x23 => Self::US1,
+            0x24 => Self::US2_5,
+            0x25 => Self::US10,
+            0x26 => Self::US25,
+            0x27 => Self::US100,
+            0x28 => Self::US250,
+            0x29 => Self::MS1,
+            0x2a => Self::MS2_5,
+            0x2b => Self::MS10,
+            0x2c => Self::MS25,
+            0x2d => Self::MS100,
+            0x2e => Self::MS250,
+            0x2f => Self::S1,
+            0x30 => Self::S10,
+            0x31 => Self::SGT10,
+            0x80..=0xfd => Self::ProfileSpecific(value - 0x80),
+            0xfe => ClockAccuracy::Unknown,
+        }
+    }
+
+    /// high accuracy to low accuracy
+    pub(crate) fn cmp_numeric(&self, other: &Self) -> Ordering {
+        self.to_primitive().cmp(&other.to_primitive())
+    }
+}
+
+impl Default for ClockAccuracy {
+    fn default() -> Self {
+        Self::Unknown
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn network_protocol_values() {
+        for i in 0..u8::MAX {
+            let protocol = ClockAccuracy::from_primitive(i);
+            if !matches!(protocol, ClockAccuracy::Reserved) {
+                assert_eq!(protocol.to_primitive(), i);
+            }
+        }
+
+        assert_eq!(ClockAccuracy::ProfileSpecific(5).to_primitive(), 0x85);
+    }
+
+    #[test]
+    fn ordering() {
+        // the inaccuracy of PS1 is less than of PS10
+        let a = ClockAccuracy::PS1;
+        let b = ClockAccuracy::PS10;
+
+        assert_eq!(a.cmp_numeric(&b), Ordering::Less);
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/clock_identity.rs.html b/docs/src/statime/datastructures/common/clock_identity.rs.html new file mode 100644 index 000000000..cec2bb96a --- /dev/null +++ b/docs/src/statime/datastructures/common/clock_identity.rs.html @@ -0,0 +1,99 @@ +clock_identity.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+
use crate::datastructures::{WireFormat, WireFormatError};
+
+/// The identity of a PTP node.
+///
+/// Must have a unique value for each node in a ptp network. For notes on
+/// generating these, see IEEE1588-2019 section 7.5.2.2
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
+pub struct ClockIdentity(pub [u8; 8]);
+
+impl WireFormat for ClockIdentity {
+    fn wire_size(&self) -> usize {
+        8
+    }
+
+    fn serialize(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        buffer[0..8].copy_from_slice(&self.0);
+        Ok(())
+    }
+
+    fn deserialize(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        Ok(Self(buffer[0..8].try_into().unwrap()))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08u8],
+            ClockIdentity([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]),
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 8];
+            object_representation
+                .serialize(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data = ClockIdentity::deserialize(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/clock_quality.rs.html b/docs/src/statime/datastructures/common/clock_quality.rs.html new file mode 100644 index 000000000..c2f116c5f --- /dev/null +++ b/docs/src/statime/datastructures/common/clock_quality.rs.html @@ -0,0 +1,149 @@ +clock_quality.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+
use super::clock_accuracy::ClockAccuracy;
+use crate::datastructures::{WireFormat, WireFormatError};
+
+/// A description of the accuracy and type of a clock.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct ClockQuality {
+    /// The PTP clock class.
+    ///
+    /// Per the standard, 248 is the default, and a good option for most use
+    /// cases. For grandmaster clocks, this should be below 128 to ensure the
+    /// clock never takes time from another source. A value of 6 is a good
+    /// option for a node with an external time source.
+    ///
+    /// For other potential values, see IEEE1588-2019 section 7.6.2.5
+    pub clock_class: u8,
+
+    /// The accuracy of the clock
+    pub clock_accuracy: ClockAccuracy,
+
+    /// 2-log of the variance (in seconds^2) of the clock when not synchronized.
+    /// See IEEE1588-2019 section 7.6.3.5 for more details.
+    pub offset_scaled_log_variance: u16,
+}
+
+impl WireFormat for ClockQuality {
+    fn wire_size(&self) -> usize {
+        4
+    }
+
+    fn serialize(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        buffer[0] = self.clock_class;
+        buffer[1] = self.clock_accuracy.to_primitive();
+        buffer[2..4].copy_from_slice(&self.offset_scaled_log_variance.to_be_bytes());
+        Ok(())
+    }
+
+    fn deserialize(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        Ok(Self {
+            clock_class: buffer[0],
+            clock_accuracy: ClockAccuracy::from_primitive(buffer[1]),
+            offset_scaled_log_variance: u16::from_be_bytes(buffer[2..4].try_into().unwrap()),
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [0x7a, 0x2a, 0x12, 0x34u8],
+            ClockQuality {
+                clock_class: 122,
+                clock_accuracy: ClockAccuracy::MS2_5,
+                offset_scaled_log_variance: 0x1234,
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 4];
+            object_representation
+                .serialize(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data = ClockQuality::deserialize(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/leap_indicator.rs.html b/docs/src/statime/datastructures/common/leap_indicator.rs.html new file mode 100644 index 000000000..4434c4c7f --- /dev/null +++ b/docs/src/statime/datastructures/common/leap_indicator.rs.html @@ -0,0 +1,19 @@ +leap_indicator.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub enum LeapIndicator {
+    #[default]
+    NoLeap,
+    /// the last minute of the current UTC day contains 61 seconds.
+    Leap61,
+    /// the last minute of the current UTC day contains 59 seconds.
+    Leap59,
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/mod.rs.html b/docs/src/statime/datastructures/common/mod.rs.html new file mode 100644 index 000000000..ca1e29ab0 --- /dev/null +++ b/docs/src/statime/datastructures/common/mod.rs.html @@ -0,0 +1,43 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+
//! Common data structures that are used throughout the protocol
+
+mod clock_accuracy;
+mod clock_identity;
+mod clock_quality;
+mod leap_indicator;
+mod port_identity;
+mod time_interval;
+mod time_source;
+mod timestamp;
+mod tlv;
+
+pub use clock_accuracy::*;
+pub use clock_identity::*;
+pub use clock_quality::*;
+pub use leap_indicator::*;
+pub(crate) use port_identity::*;
+pub(crate) use time_interval::*;
+pub use time_source::*;
+pub use timestamp::*;
+pub use tlv::*;
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/port_identity.rs.html b/docs/src/statime/datastructures/common/port_identity.rs.html new file mode 100644 index 000000000..0b19931a4 --- /dev/null +++ b/docs/src/statime/datastructures/common/port_identity.rs.html @@ -0,0 +1,137 @@ +port_identity.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+
use super::clock_identity::ClockIdentity;
+use crate::datastructures::{WireFormat, WireFormatError};
+
+/// Identity of a single port of a PTP instance
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord)]
+pub(crate) struct PortIdentity {
+    /// Identity of the clock this port is part of
+    pub(crate) clock_identity: ClockIdentity,
+    /// Index of the port (1-based).
+    pub(crate) port_number: u16,
+}
+
+impl WireFormat for PortIdentity {
+    fn wire_size(&self) -> usize {
+        10
+    }
+
+    fn serialize(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        self.clock_identity.serialize(&mut buffer[0..8])?;
+        buffer[8..10].copy_from_slice(&self.port_number.to_be_bytes());
+        Ok(())
+    }
+
+    fn deserialize(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        Ok(Self {
+            clock_identity: ClockIdentity::deserialize(&buffer[0..8])?,
+            port_number: u16::from_be_bytes(buffer[8..10].try_into().unwrap()),
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [
+            (
+                [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x15, 0xb3u8],
+                PortIdentity {
+                    clock_identity: ClockIdentity([0, 1, 2, 3, 4, 5, 6, 7]),
+                    port_number: 5555,
+                },
+            ),
+            (
+                [0x40, 0x6d, 0x16, 0x36, 0xc4, 0x24, 0x0e, 0x38, 0x04, 0xd2u8],
+                PortIdentity {
+                    clock_identity: ClockIdentity([64, 109, 22, 54, 196, 36, 14, 56]),
+                    port_number: 1234,
+                },
+            ),
+        ];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 10];
+            object_representation
+                .serialize(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data = PortIdentity::deserialize(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/time_interval.rs.html b/docs/src/statime/datastructures/common/time_interval.rs.html new file mode 100644 index 000000000..c907aab62 --- /dev/null +++ b/docs/src/statime/datastructures/common/time_interval.rs.html @@ -0,0 +1,173 @@ +time_interval.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+
use core::ops::{Deref, DerefMut};
+
+use fixed::types::I48F16;
+
+use crate::{
+    datastructures::{WireFormat, WireFormatError},
+    time::Duration,
+};
+
+/// Represents time intervals in nanoseconds
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub(crate) struct TimeInterval(pub I48F16);
+
+impl Deref for TimeInterval {
+    type Target = I48F16;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl DerefMut for TimeInterval {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl WireFormat for TimeInterval {
+    fn wire_size(&self) -> usize {
+        8
+    }
+
+    fn serialize(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        buffer[0..8].copy_from_slice(&self.0.to_bits().to_be_bytes());
+        Ok(())
+    }
+
+    fn deserialize(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        Ok(Self(I48F16::from_bits(i64::from_be_bytes(
+            buffer[0..8].try_into().unwrap(),
+        ))))
+    }
+}
+
+impl From<Duration> for TimeInterval {
+    fn from(duration: Duration) -> Self {
+        let val = (duration.nanos().to_bits() >> 16) as i64;
+        TimeInterval(fixed::types::I48F16::from_bits(val))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn time_interval_wireformat() {
+        let representations = [
+            (
+                [0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00u8],
+                TimeInterval(I48F16::from_num(2.5f64)),
+            ),
+            (
+                [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01u8],
+                TimeInterval(I48F16::from_num(1.0f64 / u16::MAX as f64)),
+            ),
+            (
+                [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00u8],
+                TimeInterval(I48F16::from_num(-1.0f64)),
+            ),
+        ];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 8];
+            object_representation
+                .serialize(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data = TimeInterval::deserialize(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/time_source.rs.html b/docs/src/statime/datastructures/common/time_source.rs.html new file mode 100644 index 000000000..edc7e19eb --- /dev/null +++ b/docs/src/statime/datastructures/common/time_source.rs.html @@ -0,0 +1,147 @@ +time_source.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+
/// What the time values for a system are derived from
+///
+/// This enum encodes the root source of a system's time values. For most use
+/// cases, the default `InternalOscillator` will suffice.
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
+pub enum TimeSource {
+    AtomicClock,
+    Gnss,
+    TerrestrialRadio,
+    SerialTimeCode,
+    Ptp,
+    Ntp,
+    HandSet,
+    Other,
+    #[default]
+    InternalOscillator,
+    ProfileSpecific(u8),
+    Reserved,
+    /// Time source is unknown. This is not an official variant from the spec,
+    /// but we just need it in practise
+    Unknown(u8),
+}
+
+impl TimeSource {
+    pub(crate) fn to_primitive(self) -> u8 {
+        match self {
+            Self::AtomicClock => 0x10,
+            Self::Gnss => 0x20,
+            Self::TerrestrialRadio => 0x30,
+            Self::SerialTimeCode => 0x39,
+            Self::Ptp => 0x40,
+            Self::Ntp => 0x50,
+            Self::HandSet => 0x60,
+            Self::Other => 0x90,
+            Self::InternalOscillator => 0xa0,
+            Self::ProfileSpecific(p) => 0xf0 + p,
+            Self::Reserved => 0xff,
+            Self::Unknown(v) => v,
+        }
+    }
+
+    pub(crate) fn from_primitive(value: u8) -> Self {
+        match value {
+            0x10 => Self::AtomicClock,
+            0x20 => Self::Gnss,
+            0x30 => Self::TerrestrialRadio,
+            0x39 => Self::SerialTimeCode,
+            0x40 => Self::Ptp,
+            0x50 => Self::Ntp,
+            0x60 => Self::HandSet,
+            0x90 => Self::Other,
+            0xa0 => Self::InternalOscillator,
+            0xf0..=0xfe => Self::ProfileSpecific(value - 0xf0),
+            0xff => TimeSource::Reserved,
+            v => TimeSource::Unknown(v),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn network_protocol_values() {
+        for i in 0..u8::MAX {
+            let protocol = TimeSource::from_primitive(i);
+            assert_eq!(protocol.to_primitive(), i);
+        }
+
+        assert_eq!(TimeSource::ProfileSpecific(5).to_primitive(), 0xf5);
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/timestamp.rs.html b/docs/src/statime/datastructures/common/timestamp.rs.html new file mode 100644 index 000000000..fcf626395 --- /dev/null +++ b/docs/src/statime/datastructures/common/timestamp.rs.html @@ -0,0 +1,167 @@ +timestamp.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+
use crate::{
+    datastructures::{WireFormat, WireFormatError},
+    time::Time,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord)]
+pub struct WireTimestamp {
+    /// The seconds field of the timestamp.
+    /// 48-bit, must be less than 281474976710656
+    pub seconds: u64,
+    /// The nanoseconds field of the timestamp.
+    /// Must be less than 10^9
+    pub nanos: u32,
+}
+
+impl WireFormat for WireTimestamp {
+    fn wire_size(&self) -> usize {
+        10
+    }
+
+    fn serialize(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        buffer[0..6].copy_from_slice(&self.seconds.to_be_bytes()[2..8]);
+        buffer[6..10].copy_from_slice(&self.nanos.to_be_bytes());
+        Ok(())
+    }
+
+    fn deserialize(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        let mut seconds_buffer = [0; 8];
+        seconds_buffer[2..8].copy_from_slice(&buffer[0..6]);
+
+        Ok(Self {
+            seconds: u64::from_be_bytes(seconds_buffer),
+            nanos: u32::from_be_bytes(buffer[6..10].try_into().unwrap()),
+        })
+    }
+}
+
+impl From<Time> for WireTimestamp {
+    fn from(instant: Time) -> Self {
+        WireTimestamp {
+            seconds: instant.secs(),
+            nanos: instant.subsec_nanos(),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [
+            (
+                [0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01u8],
+                WireTimestamp {
+                    seconds: 0x0000_0000_0002,
+                    nanos: 0x0000_0001,
+                },
+            ),
+            (
+                [0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x01u8],
+                WireTimestamp {
+                    seconds: 0x1000_0000_0002,
+                    nanos: 0x1000_0001,
+                },
+            ),
+        ];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 10];
+            object_representation
+                .serialize(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data = WireTimestamp::deserialize(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/common/tlv.rs.html b/docs/src/statime/datastructures/common/tlv.rs.html new file mode 100644 index 000000000..dded44dd1 --- /dev/null +++ b/docs/src/statime/datastructures/common/tlv.rs.html @@ -0,0 +1,577 @@ +tlv.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+
use crate::datastructures::WireFormatError;
+
+#[derive(Clone, PartialEq, Eq, Default)]
+pub(crate) struct TlvSet<'a> {
+    bytes: &'a [u8],
+}
+
+impl<'a> core::fmt::Debug for TlvSet<'a> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("TlvSet")
+            .field("wire_size", &self.wire_size())
+            .field("bytes", &self.bytes)
+            .finish()
+    }
+}
+
+impl<'a> TlvSet<'a> {
+    pub(crate) fn wire_size(&self) -> usize {
+        // tlv should be an even number of octets!
+        debug_assert_eq!(self.bytes.len() % 2, 0);
+
+        self.bytes.len()
+    }
+
+    pub(crate) fn serialize(&self, buffer: &mut [u8]) -> Result<usize, WireFormatError> {
+        buffer
+            .get_mut(..self.bytes.len())
+            .ok_or(WireFormatError::BufferTooShort)?
+            .copy_from_slice(self.bytes);
+
+        Ok(self.bytes.len())
+    }
+
+    pub(crate) fn deserialize(mut buffer: &'a [u8]) -> Result<Self, WireFormatError> {
+        let original = buffer;
+        let mut total_length = 0;
+
+        while buffer.len() > 4 {
+            let _tlv_type = TlvType::from_primitive(u16::from_be_bytes([buffer[0], buffer[1]]));
+            let length = u16::from_be_bytes([buffer[2], buffer[3]]) as usize;
+
+            if length % 2 != 0 {
+                log::trace!("tlv list has trailing bytes");
+                return Err(WireFormatError::Invalid);
+            }
+
+            buffer = buffer
+                .get(4 + length..)
+                .ok_or(WireFormatError::BufferTooShort)?;
+
+            total_length += 4 + length;
+        }
+
+        if !buffer.is_empty() {
+            log::trace!("tlv list has trailing bytes");
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        Ok(Self {
+            bytes: &original[..total_length],
+        })
+    }
+
+    #[allow(unused)]
+    pub fn announce_propagate_tlv(&self) -> impl Iterator<Item = Tlv<'a>> + 'a {
+        self.tlv().filter(|tlv| tlv.tlv_type.announce_propagate())
+    }
+
+    pub(crate) fn tlv(&self) -> impl Iterator<Item = Tlv<'a>> + 'a {
+        let mut buffer = self.bytes;
+
+        core::iter::from_fn(move || {
+            if buffer.len() <= 4 {
+                debug_assert_eq!(buffer.len(), 0);
+                return None;
+            }
+
+            // we've validated the buffer; this should never fail!
+            let tlv = Tlv::deserialize(buffer).unwrap();
+
+            buffer = &buffer[tlv.wire_size()..];
+
+            Some(tlv)
+        })
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct Tlv<'a> {
+    pub tlv_type: TlvType,
+    pub value: &'a [u8],
+}
+
+impl<'a> Tlv<'a> {
+    fn wire_size(&self) -> usize {
+        4 + self.value.len()
+    }
+
+    #[allow(unused)]
+    fn serialize(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        buffer[0..][..2].copy_from_slice(&self.tlv_type.to_primitive().to_be_bytes());
+        buffer[2..][..2].copy_from_slice(&(self.value.len() as u16).to_be_bytes());
+        buffer[4..][..self.value.len()].copy_from_slice(self.value);
+
+        Ok(())
+    }
+
+    fn deserialize(buffer: &'a [u8]) -> Result<Self, WireFormatError> {
+        if buffer.len() < 4 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        let tlv_type = TlvType::from_primitive(u16::from_be_bytes([buffer[0], buffer[1]]));
+        let length = u16::from_be_bytes([buffer[2], buffer[3]]);
+
+        // Parse TLV content / value
+        if buffer.len() < 4 + length as usize {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        let value = &buffer[4..][..length as usize];
+        Ok(Self { tlv_type, value })
+    }
+}
+
+/// See 14.1.1 / Table 52
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(u8)]
+pub enum TlvType {
+    Reserved(u16),
+    Management,
+    ManagementErrorStatus,
+    OrganizationExtension,
+    RequestUnicastTransmission,
+    GrantUnicastTransmission,
+    CancelUnicastTransmission,
+    AcknowledgeCancelUnicastTransmission,
+    PathTrace,
+    AlternateTimeOffsetIndicator,
+    Legacy(u16),
+    Experimental(u16),
+    OrganizationExtensionPropagate,
+    EnhancedAccuracyMetrics,
+    OrganizationExtensionDoNotPropagate,
+    L1Sync,
+    PortCommunicationAvailability,
+    ProtocolAddress,
+    SlaveRxSyncTimingData,
+    SlaveRxSyncComputedData,
+    SlaveTxEventTimestamps,
+    CumulativeRateRatio,
+    Pad,
+    Authentication,
+}
+
+impl TlvType {
+    pub fn to_primitive(self) -> u16 {
+        match self {
+            Self::Reserved(value) => value,
+            Self::Management => 0x0001,
+            Self::ManagementErrorStatus => 0x0002,
+            Self::OrganizationExtension => 0x0003,
+            Self::RequestUnicastTransmission => 0x0004,
+            Self::GrantUnicastTransmission => 0x0005,
+            Self::CancelUnicastTransmission => 0x0006,
+            Self::AcknowledgeCancelUnicastTransmission => 0x0007,
+            Self::PathTrace => 0x0008,
+            Self::AlternateTimeOffsetIndicator => 0x0009,
+            Self::Legacy(value) => value,
+            Self::Experimental(value) => value,
+            Self::OrganizationExtensionPropagate => 0x4000,
+            Self::EnhancedAccuracyMetrics => 0x4001,
+            Self::OrganizationExtensionDoNotPropagate => 0x8000,
+            Self::L1Sync => 0x8001,
+            Self::PortCommunicationAvailability => 0x8002,
+            Self::ProtocolAddress => 0x8003,
+            Self::SlaveRxSyncTimingData => 0x8004,
+            Self::SlaveRxSyncComputedData => 0x8005,
+            Self::SlaveTxEventTimestamps => 0x8006,
+            Self::CumulativeRateRatio => 0x8007,
+            Self::Pad => 0x8008,
+            Self::Authentication => 0x8009,
+        }
+    }
+
+    pub fn from_primitive(value: u16) -> Self {
+        match value {
+            0x0000
+            | 0x000a..=0x1fff
+            | 0x2030..=0x3fff
+            | 0x4002..=0x7eff
+            | 0x800a..=0xffef
+            | 0xfff0..=0xffff => Self::Reserved(value),
+            0x2000..=0x2003 => Self::Legacy(value),
+            0x2004..=0x202f | 0x7f00..=0x7fff => Self::Experimental(value),
+            0x0001 => Self::Management,
+            0x0002 => Self::ManagementErrorStatus,
+            0x0003 => Self::OrganizationExtension,
+            0x0004 => Self::RequestUnicastTransmission,
+            0x0005 => Self::GrantUnicastTransmission,
+            0x0006 => Self::CancelUnicastTransmission,
+            0x0007 => Self::AcknowledgeCancelUnicastTransmission,
+            0x0008 => Self::PathTrace,
+            0x0009 => Self::AlternateTimeOffsetIndicator,
+            0x4000 => Self::OrganizationExtensionPropagate,
+            0x4001 => Self::EnhancedAccuracyMetrics,
+            0x8000 => Self::OrganizationExtensionDoNotPropagate,
+            0x8001 => Self::L1Sync,
+            0x8002 => Self::PortCommunicationAvailability,
+            0x8003 => Self::ProtocolAddress,
+            0x8004 => Self::SlaveRxSyncTimingData,
+            0x8005 => Self::SlaveRxSyncComputedData,
+            0x8006 => Self::SlaveTxEventTimestamps,
+            0x8007 => Self::CumulativeRateRatio,
+            0x8008 => Self::Pad,
+            0x8009 => Self::Authentication,
+        }
+    }
+
+    // True if this message should be propagated by a boundary clock if it is
+    // attached to an announce message
+    pub fn announce_propagate(self) -> bool {
+        matches!(self.to_primitive(), 0x0008 | 0x0009 | 0x4000..=0x7fff)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn serialize_management() {
+        let tlv = Tlv {
+            tlv_type: TlvType::Management,
+            value: &b"hello!"[..],
+        };
+
+        let mut buffer = [0; 256];
+        tlv.serialize(&mut buffer).unwrap();
+
+        let n = tlv.wire_size();
+        assert_eq!(n, 10);
+
+        let decoded = Tlv::deserialize(&buffer[..n]).unwrap();
+
+        assert_eq!(tlv, decoded);
+    }
+
+    #[test]
+    fn parse_announce_propagate_messages() {
+        let mut alloc = [0; 256];
+        let mut buffer = &mut alloc[..];
+
+        let tlv1 = Tlv {
+            tlv_type: TlvType::Management,
+            value: &b"hello!"[..],
+        };
+        tlv1.serialize(buffer).unwrap();
+        buffer = &mut buffer[tlv1.wire_size()..];
+        assert!(!tlv1.tlv_type.announce_propagate());
+
+        let tlv2 = Tlv {
+            tlv_type: TlvType::PathTrace,
+            value: &b"PathTrace!"[..],
+        };
+        tlv2.serialize(buffer).unwrap();
+        buffer = &mut buffer[tlv2.wire_size()..];
+        assert!(tlv2.tlv_type.announce_propagate());
+
+        let tlv3 = Tlv {
+            tlv_type: TlvType::OrganizationExtensionPropagate,
+            value: &b"OrganizationExtensionPropagate"[..],
+        };
+        tlv3.serialize(buffer).unwrap();
+        buffer = &mut buffer[tlv3.wire_size()..];
+        assert!(tlv3.tlv_type.announce_propagate());
+
+        let _ = buffer;
+
+        let buffer = &mut alloc[..tlv1.wire_size() + tlv2.wire_size() + tlv3.wire_size()];
+        let tlv_set = TlvSet::deserialize(buffer).unwrap();
+        let mut it = tlv_set.announce_propagate_tlv();
+
+        assert_eq!(it.next(), Some(tlv2));
+        assert_eq!(it.next(), Some(tlv3));
+        assert_eq!(it.next(), None);
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/datasets/current.rs.html b/docs/src/statime/datastructures/datasets/current.rs.html new file mode 100644 index 000000000..6d4b2474c --- /dev/null +++ b/docs/src/statime/datastructures/datasets/current.rs.html @@ -0,0 +1,17 @@ +current.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+
use crate::time::Duration;
+
+#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub(crate) struct CurrentDS {
+    pub(crate) steps_removed: u16,
+    pub(crate) offset_from_master: Duration,
+    pub(crate) mean_delay: Duration,
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/datasets/default.rs.html b/docs/src/statime/datastructures/datasets/default.rs.html new file mode 100644 index 000000000..130b5566a --- /dev/null +++ b/docs/src/statime/datastructures/datasets/default.rs.html @@ -0,0 +1,83 @@ +default.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+
use crate::{
+    config::InstanceConfig,
+    datastructures::{
+        common::{ClockIdentity, ClockQuality},
+        messages::SdoId,
+    },
+};
+
+/// A concrete implementation of the PTP Default dataset (IEEE1588-2019 section
+/// 8.2.1)
+///
+/// This dataset describes the properties of the PTP instance. Most
+/// instance-wide configuration options are found here, with the exception of
+/// those related to timebase, which is contained in the
+/// [TimePropertiesDS](crate::TimePropertiesDS) dataset.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub(crate) struct DefaultDS {
+    pub(crate) clock_identity: ClockIdentity,
+    pub(crate) number_ports: u16,
+    pub(crate) clock_quality: ClockQuality,
+    pub(crate) priority_1: u8,
+    pub(crate) priority_2: u8,
+    pub(crate) domain_number: u8,
+    pub(crate) slave_only: bool,
+    pub(crate) sdo_id: SdoId,
+}
+
+impl DefaultDS {
+    pub(crate) fn new(config: InstanceConfig) -> Self {
+        Self {
+            clock_identity: config.clock_identity,
+            number_ports: 0,
+            clock_quality: Default::default(),
+            priority_1: config.priority_1,
+            priority_2: config.priority_2,
+            domain_number: config.domain_number,
+            slave_only: config.slave_only,
+            sdo_id: config.sdo_id,
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/datasets/mod.rs.html b/docs/src/statime/datastructures/datasets/mod.rs.html new file mode 100644 index 000000000..0728560f5 --- /dev/null +++ b/docs/src/statime/datastructures/datasets/mod.rs.html @@ -0,0 +1,19 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+
pub(crate) use current::CurrentDS;
+pub(crate) use default::DefaultDS;
+pub(crate) use parent::ParentDS;
+pub use time_properties::TimePropertiesDS;
+
+mod current;
+mod default;
+mod parent;
+mod time_properties;
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/datasets/parent.rs.html b/docs/src/statime/datastructures/datasets/parent.rs.html new file mode 100644 index 000000000..1d15383f3 --- /dev/null +++ b/docs/src/statime/datastructures/datasets/parent.rs.html @@ -0,0 +1,67 @@ +parent.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+
use super::DefaultDS;
+use crate::datastructures::common::{ClockIdentity, ClockQuality, PortIdentity};
+
+// TODO: Discuss moving this (and TimePropertiesDS, ...) to slave?
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub(crate) struct ParentDS {
+    pub(crate) parent_port_identity: PortIdentity,
+    pub(crate) parent_stats: bool,
+    pub(crate) observed_parent_offset_scaled_log_variance: u16,
+    pub(crate) observed_parent_clock_phase_change_rate: u32,
+    pub(crate) grandmaster_identity: ClockIdentity,
+    pub(crate) grandmaster_clock_quality: ClockQuality,
+    pub(crate) grandmaster_priority_1: u8,
+    pub(crate) grandmaster_priority_2: u8,
+}
+
+impl ParentDS {
+    pub(crate) fn new(default_ds: DefaultDS) -> Self {
+        ParentDS {
+            parent_port_identity: PortIdentity {
+                clock_identity: default_ds.clock_identity,
+                port_number: 0,
+            },
+            parent_stats: false,
+            observed_parent_offset_scaled_log_variance: 0xffff,
+            observed_parent_clock_phase_change_rate: 0x7fffffff,
+            grandmaster_identity: default_ds.clock_identity,
+            grandmaster_clock_quality: default_ds.clock_quality,
+            grandmaster_priority_1: default_ds.priority_1,
+            grandmaster_priority_2: default_ds.priority_2,
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/datasets/time_properties.rs.html b/docs/src/statime/datastructures/datasets/time_properties.rs.html new file mode 100644 index 000000000..b7e87baf4 --- /dev/null +++ b/docs/src/statime/datastructures/datasets/time_properties.rs.html @@ -0,0 +1,149 @@ +time_properties.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+
use crate::datastructures::common::{LeapIndicator, TimeSource};
+
+/// A concrete implementation of the PTP Time Properties dataset (IEEE1588-2019
+/// section 8.2.4
+///
+/// This dataset describes the timescale currently in use, as well as any
+/// upcoming leap seconds on that timescale.
+#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
+pub struct TimePropertiesDS {
+    pub(crate) current_utc_offset: Option<i16>,
+    pub(crate) leap_indicator: LeapIndicator,
+    pub(crate) time_traceable: bool,
+    pub(crate) frequency_traceable: bool,
+    pub(crate) ptp_timescale: bool,
+    pub(crate) time_source: TimeSource,
+}
+
+impl TimePropertiesDS {
+    /// Create a Time Properties data set for the PTP timescale.
+    ///
+    /// This creates a dataset for the default PTP timescale, which is UTC
+    /// seconds since the PTP epoch excluding leap seconds. The traceability
+    /// properties indicate whether the current clock time and frequency can be
+    /// traced back to an internationally recognized standard in the metrology
+    /// sense of the word. When in doubt, just set these to false.
+    pub fn new_ptp_time(
+        current_utc_offset: Option<i16>,
+        leap_indicator: LeapIndicator,
+        time_traceable: bool,
+        frequency_traceable: bool,
+        time_source: TimeSource,
+    ) -> Self {
+        TimePropertiesDS {
+            current_utc_offset,
+            leap_indicator,
+            time_traceable,
+            frequency_traceable,
+            ptp_timescale: true,
+            time_source,
+        }
+    }
+
+    /// Create a Time Properties data set for an Arbitrary timescale
+    ///
+    /// The arbitrary timescale can be used when wanting to synchronize multiple
+    /// computers using PTP to a timescale that is unrelated to UTC. The
+    /// traceability properties indicate whether the current clock time and
+    /// frequency can be traced back to an internationally recognized standard
+    /// in the metrology sense of the word. When in doubt, just set these to
+    /// false.
+    pub fn new_arbitrary_time(
+        time_traceable: bool,
+        frequency_traceable: bool,
+        time_source: TimeSource,
+    ) -> Self {
+        TimePropertiesDS {
+            current_utc_offset: None,
+            leap_indicator: LeapIndicator::NoLeap,
+            time_traceable,
+            frequency_traceable,
+            ptp_timescale: false,
+            time_source,
+        }
+    }
+
+    /// Is the current timescale the ptp (utc-derived) timescale?
+    pub fn is_ptp(&self) -> bool {
+        self.ptp_timescale
+    }
+
+    pub fn leap_indicator(&self) -> LeapIndicator {
+        self.leap_indicator
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/announce.rs.html b/docs/src/statime/datastructures/messages/announce.rs.html new file mode 100644 index 000000000..50f615cc0 --- /dev/null +++ b/docs/src/statime/datastructures/messages/announce.rs.html @@ -0,0 +1,281 @@ +announce.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+
use super::Header;
+use crate::datastructures::{
+    common::{ClockIdentity, ClockQuality, LeapIndicator, TimeSource, WireTimestamp},
+    datasets::TimePropertiesDS,
+    WireFormat, WireFormatError,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct AnnounceMessage {
+    pub(crate) header: Header,
+    pub(crate) origin_timestamp: WireTimestamp,
+    pub(crate) current_utc_offset: i16,
+    pub(crate) grandmaster_priority_1: u8,
+    pub(crate) grandmaster_clock_quality: ClockQuality,
+    pub(crate) grandmaster_priority_2: u8,
+    pub(crate) grandmaster_identity: ClockIdentity,
+    pub(crate) steps_removed: u16,
+    pub(crate) time_source: TimeSource,
+}
+
+impl AnnounceMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        30
+    }
+
+    pub(crate) fn serialize_content(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        if buffer.len() < 30 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        self.origin_timestamp.serialize(&mut buffer[0..10])?;
+        buffer[10..12].copy_from_slice(&self.current_utc_offset.to_be_bytes());
+        buffer[13] = self.grandmaster_priority_1;
+        self.grandmaster_clock_quality
+            .serialize(&mut buffer[14..18])?;
+        buffer[18] = self.grandmaster_priority_2;
+        self.grandmaster_identity.serialize(&mut buffer[19..27])?;
+        buffer[27..29].copy_from_slice(&self.steps_removed.to_be_bytes());
+        buffer[29] = self.time_source.to_primitive();
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(
+        header: Header,
+        buffer: &[u8],
+    ) -> Result<Self, WireFormatError> {
+        if buffer.len() < 30 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        Ok(Self {
+            header,
+            origin_timestamp: WireTimestamp::deserialize(&buffer[0..10])?,
+            current_utc_offset: i16::from_be_bytes(buffer[10..12].try_into().unwrap()),
+            grandmaster_priority_1: buffer[13],
+            grandmaster_clock_quality: ClockQuality::deserialize(&buffer[14..18])?,
+            grandmaster_priority_2: buffer[18],
+            grandmaster_identity: ClockIdentity::deserialize(&buffer[19..27])?,
+            steps_removed: u16::from_be_bytes(buffer[27..29].try_into().unwrap()),
+            time_source: TimeSource::from_primitive(buffer[29]),
+        })
+    }
+
+    pub(crate) fn time_properties(&self) -> TimePropertiesDS {
+        let leap_indicator = if self.header.leap59 {
+            LeapIndicator::Leap59
+        } else if self.header.leap61 {
+            LeapIndicator::Leap61
+        } else {
+            LeapIndicator::NoLeap
+        };
+
+        let current_utc_offset = self
+            .header
+            .current_utc_offset_valid
+            .then_some(self.current_utc_offset);
+
+        TimePropertiesDS {
+            current_utc_offset,
+            leap_indicator,
+            time_traceable: self.header.time_tracable,
+            frequency_traceable: self.header.frequency_tracable,
+            ptp_timescale: self.header.ptp_timescale,
+            time_source: self.time_source,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::datastructures::common::ClockAccuracy;
+
+    #[test]
+    fn announce_wireformat() {
+        let representations = [(
+            [
+                0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x73, 0x46, 0x60, 0x00, 0x00, 0x00, 0x60,
+                0x00, 0x00, 0x00, 0x80, 0x63, 0xff, 0xff, 0x00, 0x09, 0xba, 0xf8, 0x21, 0x00, 0x00,
+                0x80, 0x80,
+            ],
+            AnnounceMessage {
+                header: Header::default(),
+                origin_timestamp: WireTimestamp {
+                    seconds: 1169232218,
+                    nanos: 175326816,
+                },
+                current_utc_offset: 0,
+                grandmaster_priority_1: 96,
+                grandmaster_clock_quality: ClockQuality {
+                    clock_class: 0,
+                    clock_accuracy: ClockAccuracy::Reserved,
+                    offset_scaled_log_variance: 128,
+                },
+                grandmaster_priority_2: 99,
+                grandmaster_identity: ClockIdentity([
+                    0xff, 0xff, 0x00, 0x09, 0xba, 0xf8, 0x21, 0x00,
+                ]),
+                steps_removed: 128,
+                time_source: TimeSource::Unknown(0x80),
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 30];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data =
+                AnnounceMessage::deserialize_content(Header::default(), &byte_representation)
+                    .unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/control_field.rs.html b/docs/src/statime/datastructures/messages/control_field.rs.html new file mode 100644 index 000000000..04b4c18e2 --- /dev/null +++ b/docs/src/statime/datastructures/messages/control_field.rs.html @@ -0,0 +1,75 @@ +control_field.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+
use super::MessageType;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(super) enum ControlField {
+    Sync,
+    DelayReq,
+    FollowUp,
+    DelayResp,
+    Management,
+    AllOthers,
+}
+
+impl ControlField {
+    pub fn to_primitive(self) -> u8 {
+        match self {
+            ControlField::Sync => 0x00,
+            ControlField::DelayReq => 0x01,
+            ControlField::FollowUp => 0x02,
+            ControlField::DelayResp => 0x03,
+            ControlField::Management => 0x04,
+            ControlField::AllOthers => 0x05,
+        }
+    }
+}
+
+impl From<MessageType> for ControlField {
+    fn from(message_type: MessageType) -> Self {
+        match message_type {
+            MessageType::Sync => ControlField::Sync,
+            MessageType::DelayReq => ControlField::DelayReq,
+            MessageType::FollowUp => ControlField::FollowUp,
+            MessageType::DelayResp => ControlField::DelayResp,
+            MessageType::Management => ControlField::Management,
+            _ => ControlField::AllOthers,
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/delay_req.rs.html b/docs/src/statime/datastructures/messages/delay_req.rs.html new file mode 100644 index 000000000..9140d983b --- /dev/null +++ b/docs/src/statime/datastructures/messages/delay_req.rs.html @@ -0,0 +1,115 @@ +delay_req.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+
use crate::datastructures::{common::WireTimestamp, WireFormat, WireFormatError};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct DelayReqMessage {
+    pub(crate) origin_timestamp: WireTimestamp,
+}
+
+impl DelayReqMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        10
+    }
+
+    pub(crate) fn serialize_content(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        self.origin_timestamp.serialize(&mut buffer[0..10])?;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        let slice = buffer.get(0..10).ok_or(WireFormatError::BufferTooShort)?;
+        let origin_timestamp = WireTimestamp::deserialize(slice)?;
+
+        Ok(Self { origin_timestamp })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x64, 0xfa, 0xb0],
+            DelayReqMessage {
+                origin_timestamp: WireTimestamp {
+                    seconds: 1169232218,
+                    nanos: 174389936,
+                },
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 10];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data =
+                DelayReqMessage::deserialize_content(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/delay_resp.rs.html b/docs/src/statime/datastructures/messages/delay_resp.rs.html new file mode 100644 index 000000000..f8871a2b4 --- /dev/null +++ b/docs/src/statime/datastructures/messages/delay_resp.rs.html @@ -0,0 +1,151 @@ +delay_resp.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+
use crate::datastructures::{
+    common::{PortIdentity, WireTimestamp},
+    WireFormat, WireFormatError,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct DelayRespMessage {
+    pub(crate) receive_timestamp: WireTimestamp,
+    pub(crate) requesting_port_identity: PortIdentity,
+}
+
+impl DelayRespMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        20
+    }
+
+    pub(crate) fn serialize_content(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        self.receive_timestamp.serialize(&mut buffer[0..10])?;
+        self.requesting_port_identity
+            .serialize(&mut buffer[10..20])?;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        let slice = buffer.get(0..20).ok_or(WireFormatError::BufferTooShort)?;
+        let receive_timestamp = WireTimestamp::deserialize(&slice[0..10])?;
+        let requesting_port_identity = PortIdentity::deserialize(&slice[10..20])?;
+
+        Ok(Self {
+            receive_timestamp,
+            requesting_port_identity,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::datastructures::common::{ClockIdentity, PortIdentity};
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [
+                0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x64, 0xfa, 0xb0, 0x01, 0x02, 0x03, 0x04,
+                0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+            ],
+            DelayRespMessage {
+                receive_timestamp: WireTimestamp {
+                    seconds: 1169232218,
+                    nanos: 174389936,
+                },
+                requesting_port_identity: PortIdentity {
+                    clock_identity: ClockIdentity([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]),
+                    port_number: 0x090a,
+                },
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 20];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data =
+                DelayRespMessage::deserialize_content(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/follow_up.rs.html b/docs/src/statime/datastructures/messages/follow_up.rs.html new file mode 100644 index 000000000..638439bc0 --- /dev/null +++ b/docs/src/statime/datastructures/messages/follow_up.rs.html @@ -0,0 +1,143 @@ +follow_up.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+
use crate::datastructures::{common::WireTimestamp, WireFormat, WireFormatError};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct FollowUpMessage {
+    pub(crate) precise_origin_timestamp: WireTimestamp,
+}
+
+impl FollowUpMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        10
+    }
+
+    pub(crate) fn serialize_content(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        self.precise_origin_timestamp
+            .serialize(&mut buffer[0..10])?;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        let slice = buffer.get(0..10).ok_or(WireFormatError::BufferTooShort)?;
+        let precise_origin_timestamp = WireTimestamp::deserialize(slice)?;
+
+        Ok(Self {
+            precise_origin_timestamp,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [
+            (
+                [0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x64, 0xfa, 0xb0],
+                FollowUpMessage {
+                    precise_origin_timestamp: WireTimestamp {
+                        seconds: 1169232218,
+                        nanos: 174389936,
+                    },
+                },
+            ),
+            (
+                [0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01u8],
+                FollowUpMessage {
+                    precise_origin_timestamp: WireTimestamp {
+                        seconds: 0x0000_0000_0002,
+                        nanos: 0x0000_0001,
+                    },
+                },
+            ),
+        ];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 10];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data =
+                FollowUpMessage::deserialize_content(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/header.rs.html b/docs/src/statime/datastructures/messages/header.rs.html new file mode 100644 index 000000000..0a98559f2 --- /dev/null +++ b/docs/src/statime/datastructures/messages/header.rs.html @@ -0,0 +1,693 @@ +header.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+
use super::{control_field::ControlField, MessageType};
+use crate::datastructures::{
+    common::{PortIdentity, TimeInterval},
+    WireFormat, WireFormatError,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Header {
+    pub(crate) sdo_id: SdoId,
+    pub(crate) version: PtpVersion,
+    pub(crate) domain_number: u8,
+    pub(crate) alternate_master_flag: bool,
+    pub(crate) two_step_flag: bool,
+    pub(crate) unicast_flag: bool,
+    pub(crate) ptp_profile_specific_1: bool,
+    pub(crate) ptp_profile_specific_2: bool,
+    pub(crate) leap61: bool,
+    pub(crate) leap59: bool,
+    pub(crate) current_utc_offset_valid: bool,
+    pub(crate) ptp_timescale: bool,
+    pub(crate) time_tracable: bool,
+    pub(crate) frequency_tracable: bool,
+    pub(crate) synchronization_uncertain: bool,
+    pub(crate) correction_field: TimeInterval,
+    pub(crate) source_port_identity: PortIdentity,
+    pub(crate) sequence_id: u16,
+    pub(crate) log_message_interval: i8,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct DeserializedHeader {
+    pub(crate) header: Header,
+    pub(crate) message_type: MessageType,
+    pub(crate) message_length: u16,
+}
+
+impl Header {
+    pub(super) fn new() -> Self {
+        Self {
+            sdo_id: SdoId(0),
+            version: PtpVersion { major: 2, minor: 1 },
+            domain_number: 0,
+            alternate_master_flag: false,
+            two_step_flag: false,
+            unicast_flag: false,
+            ptp_profile_specific_1: false,
+            ptp_profile_specific_2: false,
+            leap59: false,
+            leap61: false,
+            current_utc_offset_valid: false,
+            ptp_timescale: false,
+            time_tracable: false,
+            frequency_tracable: false,
+            synchronization_uncertain: false,
+            correction_field: TimeInterval::default(),
+            source_port_identity: PortIdentity::default(),
+            sequence_id: 0,
+            log_message_interval: 0,
+        }
+    }
+
+    pub(crate) fn wire_size(&self) -> usize {
+        34
+    }
+
+    pub(crate) fn serialize_header(
+        &self,
+        content_type: MessageType,
+        content_length: usize,
+        buffer: &mut [u8],
+    ) -> Result<(), WireFormatError> {
+        buffer[0] = ((self.sdo_id.high_byte()) << 4) | ((content_type as u8) & 0x0f);
+        buffer[1] = self.version.as_byte();
+        buffer[2..4].copy_from_slice(&((content_length + self.wire_size()) as u16).to_be_bytes());
+        buffer[4] = self.domain_number;
+        buffer[5] = self.sdo_id.low_byte();
+        buffer[6] = 0;
+        buffer[7] = 0;
+        buffer[6] |= self.alternate_master_flag as u8;
+        buffer[6] |= (self.two_step_flag as u8) << 1;
+        buffer[6] |= (self.unicast_flag as u8) << 2;
+        buffer[6] |= (self.ptp_profile_specific_1 as u8) << 5;
+        buffer[6] |= (self.ptp_profile_specific_2 as u8) << 6;
+        buffer[7] |= self.leap61 as u8;
+        buffer[7] |= (self.leap59 as u8) << 1;
+        buffer[7] |= (self.current_utc_offset_valid as u8) << 2;
+        buffer[7] |= (self.ptp_timescale as u8) << 3;
+        buffer[7] |= (self.time_tracable as u8) << 4;
+        buffer[7] |= (self.frequency_tracable as u8) << 5;
+        buffer[7] |= (self.synchronization_uncertain as u8) << 6;
+        self.correction_field.serialize(&mut buffer[8..16])?;
+        buffer[16..20].copy_from_slice(&[0, 0, 0, 0]);
+        self.source_port_identity.serialize(&mut buffer[20..30])?;
+        buffer[30..32].copy_from_slice(&self.sequence_id.to_be_bytes());
+        buffer[32] = ControlField::from(content_type).to_primitive();
+        buffer[33] = self.log_message_interval as u8;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_header(buffer: &[u8]) -> Result<DeserializedHeader, WireFormatError> {
+        if buffer.len() < 34 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        let version = PtpVersion::from_byte(buffer[1]);
+        let sdo_id = SdoId((((buffer[0] & 0xf0) as u16) << 4) | (buffer[5] as u16));
+
+        Ok(DeserializedHeader {
+            header: Self {
+                sdo_id,
+                version,
+                domain_number: buffer[4],
+                alternate_master_flag: (buffer[6] & (1 << 0)) > 0,
+                two_step_flag: (buffer[6] & (1 << 1)) > 0,
+                unicast_flag: (buffer[6] & (1 << 2)) > 0,
+                ptp_profile_specific_1: (buffer[6] & (1 << 5)) > 0,
+                ptp_profile_specific_2: (buffer[6] & (1 << 6)) > 0,
+                leap61: (buffer[7] & (1 << 0)) > 0,
+                leap59: (buffer[7] & (1 << 1)) > 0,
+                current_utc_offset_valid: (buffer[7] & (1 << 2)) > 0,
+                ptp_timescale: (buffer[7] & (1 << 3)) > 0,
+                time_tracable: (buffer[7] & (1 << 4)) > 0,
+                frequency_tracable: (buffer[7] & (1 << 5)) > 0,
+                synchronization_uncertain: (buffer[7] & (1 << 6)) > 0,
+                correction_field: TimeInterval::deserialize(&buffer[8..16])?,
+                source_port_identity: PortIdentity::deserialize(&buffer[20..30])?,
+                sequence_id: u16::from_be_bytes(buffer[30..32].try_into().unwrap()),
+                log_message_interval: buffer[33] as i8,
+            },
+            message_type: (buffer[0] & 0x0f).try_into()?,
+            message_length: u16::from_be_bytes(buffer[2..4].try_into().unwrap()),
+        })
+    }
+}
+
+impl Default for Header {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// A wrapper type for PTP Sdo Identifiers.
+///
+/// This is a separate type as sdo identifiers should be in the range 0-4095
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
+pub struct SdoId(u16);
+
+impl core::fmt::Display for SdoId {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl SdoId {
+    /// Create a new sdo id
+    ///
+    /// This function only returns an `SdoId` instance if the given identifier
+    /// is actually between 0 and 4095. Otherwise, `None` is returned.
+    pub fn new(sdo_id: u16) -> Option<Self> {
+        (0..=0x1000).contains(&sdo_id).then_some(Self(sdo_id))
+    }
+
+    const fn high_byte(self) -> u8 {
+        (self.0 >> 8) as u8
+    }
+
+    const fn low_byte(self) -> u8 {
+        self.0 as u8
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct PtpVersion {
+    major: u8,
+    minor: u8,
+}
+
+impl PtpVersion {
+    #[allow(unused)]
+    pub fn new(major: u8, minor: u8) -> Option<Self> {
+        if major >= 0x10 || minor >= 0x10 {
+            None
+        } else {
+            Some(Self { major, minor })
+        }
+    }
+
+    fn as_byte(&self) -> u8 {
+        self.minor << 4 | self.major
+    }
+
+    fn from_byte(byte: u8) -> Self {
+        Self {
+            major: byte & 0x0f,
+            minor: byte >> 4,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use fixed::types::I48F16;
+
+    use super::*;
+    use crate::datastructures::common::ClockIdentity;
+
+    #[test]
+    fn flagfield_wireformat() {
+        #[rustfmt::skip]
+        let representations = [
+            ([0x00, 0x00u8], Header::default()),
+            ([0x01, 0x00u8], Header { alternate_master_flag: true, ..Default::default() }),
+            ([0x02, 0x00u8], Header { two_step_flag: true, ..Default::default() }),
+            ([0x04, 0x00u8], Header { unicast_flag: true, ..Default::default() }),
+            ([0x20, 0x00u8], Header { ptp_profile_specific_1: true, ..Default::default() }),
+            ([0x40, 0x00u8], Header { ptp_profile_specific_2: true, ..Default::default() }),
+            ([0x00, 0x01u8], Header { leap61: true, ..Default::default() }),
+            ([0x00, 0x02u8], Header { leap59: true, ..Default::default() }),
+            ([0x00, 0x04u8], Header { current_utc_offset_valid: true, ..Default::default() }),
+            ([0x00, 0x08u8], Header { ptp_timescale: true, ..Default::default() }),
+            ([0x00, 0x10u8], Header { time_tracable: true, ..Default::default() }),
+            ([0x00, 0x20u8], Header { frequency_tracable: true, ..Default::default() }),
+            ([0x00, 0x40u8], Header { synchronization_uncertain: true, ..Default::default() }),
+        ];
+
+        for (i, (byte_representation, flag_representation)) in
+            representations.into_iter().enumerate()
+        {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 34];
+            flag_representation
+                .serialize_header(MessageType::Sync, 0, &mut serialization_buffer)
+                .unwrap();
+            assert_eq!(
+                serialization_buffer[6..8],
+                byte_representation,
+                "The serialized flag field is not what it's supposed to for variant {}",
+                i
+            );
+
+            // Test the deserialization output
+            serialization_buffer[6] = byte_representation[0];
+            serialization_buffer[7] = byte_representation[1];
+            let deserialized_flag_field =
+                Header::deserialize_header(&serialization_buffer).unwrap();
+            assert_eq!(
+                deserialized_flag_field.header, flag_representation,
+                "The deserialized flag field is not what it's supposed to for variant {}",
+                i
+            );
+        }
+    }
+
+    #[test]
+    fn header_wireformat() {
+        let representations = [(
+            [
+                0x59,
+                0xa1,
+                0x12,
+                0x34,
+                0xaa,
+                0xbb,
+                0b0100_0101,
+                0b0010_1010,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x01,
+                0x80,
+                0x00,
+                0,
+                0,
+                0,
+                0,
+                0,
+                1,
+                2,
+                3,
+                4,
+                5,
+                6,
+                7,
+                0x55,
+                0x55,
+                0xde,
+                0xad,
+                0x03,
+                0x16,
+            ],
+            DeserializedHeader {
+                header: Header {
+                    sdo_id: SdoId(0x5bb),
+                    version: PtpVersion {
+                        major: 0x1,
+                        minor: 0xa,
+                    },
+                    domain_number: 0xaa,
+                    alternate_master_flag: true,
+                    two_step_flag: false,
+                    unicast_flag: true,
+                    ptp_profile_specific_1: false,
+                    ptp_profile_specific_2: true,
+                    leap61: false,
+                    leap59: true,
+                    current_utc_offset_valid: false,
+                    ptp_timescale: true,
+                    time_tracable: false,
+                    frequency_tracable: true,
+                    synchronization_uncertain: false,
+                    correction_field: TimeInterval(I48F16::from_num(1.5f64)),
+                    source_port_identity: PortIdentity {
+                        clock_identity: ClockIdentity([0, 1, 2, 3, 4, 5, 6, 7]),
+                        port_number: 0x5555,
+                    },
+                    sequence_id: 0xdead,
+                    log_message_interval: 0x16,
+                },
+                message_type: MessageType::DelayResp,
+                message_length: 0x1234,
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 34];
+            object_representation
+                .header
+                .serialize_header(
+                    object_representation.message_type,
+                    object_representation.message_length as usize
+                        - object_representation.header.wire_size(),
+                    &mut serialization_buffer,
+                )
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data = Header::deserialize_header(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/management.rs.html b/docs/src/statime/datastructures/messages/management.rs.html new file mode 100644 index 000000000..1596e149b --- /dev/null +++ b/docs/src/statime/datastructures/messages/management.rs.html @@ -0,0 +1,155 @@ +management.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+
use crate::datastructures::{common::PortIdentity, WireFormat, WireFormatError};
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct ManagementMessage {
+    pub(super) target_port_identity: PortIdentity,
+    pub(super) starting_boundary_hops: u8,
+    pub(super) boundary_hops: u8,
+    pub(super) action: ManagementAction,
+}
+
+impl ManagementMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        14
+    }
+
+    pub(crate) fn serialize_content(
+        &self,
+        buffer: &mut [u8],
+    ) -> Result<(), crate::datastructures::WireFormatError> {
+        self.target_port_identity.serialize(&mut buffer[0..10])?;
+        buffer[11] = self.starting_boundary_hops;
+        buffer[12] = self.boundary_hops;
+        buffer[13] = self.action.to_primitive();
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(
+        buffer: &[u8],
+    ) -> Result<Self, crate::datastructures::WireFormatError> {
+        if buffer.len() < 14 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+        Ok(Self {
+            target_port_identity: PortIdentity::deserialize(&buffer[0..10])?,
+            starting_boundary_hops: buffer[11],
+            boundary_hops: buffer[12],
+            action: ManagementAction::from_primitive(buffer[13]),
+        })
+    }
+}
+
+/// See: 15.4.1.6
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[allow(clippy::upper_case_acronyms)]
+pub(crate) enum ManagementAction {
+    Reserved,
+    GET,
+    SET,
+    RESPONSE,
+    COMMAND,
+    ACKNOWLEDGE,
+}
+
+impl ManagementAction {
+    pub fn to_primitive(self) -> u8 {
+        match self {
+            Self::GET => 0x0,
+            Self::SET => 0x1,
+            Self::RESPONSE => 0x2,
+            Self::COMMAND => 0x3,
+            Self::ACKNOWLEDGE => 0x4,
+            Self::Reserved => 0x5,
+        }
+    }
+
+    pub fn from_primitive(value: u8) -> Self {
+        match value {
+            0x0 => Self::GET,
+            0x1 => Self::SET,
+            0x2 => Self::RESPONSE,
+            0x3 => Self::COMMAND,
+            0x4 => Self::ACKNOWLEDGE,
+            0x5..=u8::MAX => Self::Reserved,
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/mod.rs.html b/docs/src/statime/datastructures/messages/mod.rs.html new file mode 100644 index 000000000..21774a164 --- /dev/null +++ b/docs/src/statime/datastructures/messages/mod.rs.html @@ -0,0 +1,855 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+
//! Ptp network messages
+
+pub(crate) use announce::*;
+pub(crate) use delay_req::*;
+pub(crate) use delay_resp::*;
+pub(crate) use follow_up::*;
+pub use header::*;
+pub(crate) use sync::*;
+
+use self::{
+    management::ManagementMessage, p_delay_req::PDelayReqMessage, p_delay_resp::PDelayRespMessage,
+    p_delay_resp_follow_up::PDelayRespFollowUpMessage, signalling::SignalingMessage,
+};
+use super::{
+    common::{PortIdentity, TimeInterval, TlvSet, WireTimestamp},
+    datasets::DefaultDS,
+};
+use crate::{ptp_instance::PtpInstanceState, Interval, LeapIndicator, Time};
+
+mod announce;
+mod control_field;
+mod delay_req;
+mod delay_resp;
+mod follow_up;
+mod header;
+mod management;
+mod p_delay_req;
+mod p_delay_resp;
+mod p_delay_resp_follow_up;
+mod signalling;
+mod sync;
+
+pub const MAX_DATA_LEN: usize = 255;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(u8)]
+pub enum MessageType {
+    Sync = 0x0,
+    DelayReq = 0x1,
+    PDelayReq = 0x2,
+    PDelayResp = 0x3,
+    FollowUp = 0x8,
+    DelayResp = 0x9,
+    PDelayRespFollowUp = 0xa,
+    Announce = 0xb,
+    Signaling = 0xc,
+    Management = 0xd,
+}
+
+pub struct EnumConversionError(u8);
+
+impl TryFrom<u8> for MessageType {
+    type Error = EnumConversionError;
+
+    fn try_from(value: u8) -> Result<Self, Self::Error> {
+        use MessageType::*;
+
+        match value {
+            0x0 => Ok(Sync),
+            0x1 => Ok(DelayReq),
+            0x2 => Ok(PDelayReq),
+            0x3 => Ok(PDelayResp),
+            0x8 => Ok(FollowUp),
+            0x9 => Ok(DelayResp),
+            0xa => Ok(PDelayRespFollowUp),
+            0xb => Ok(Announce),
+            0xc => Ok(Signaling),
+            0xd => Ok(Management),
+            _ => Err(EnumConversionError(value)),
+        }
+    }
+}
+
+#[cfg(feature = "fuzz")]
+pub use fuzz::FuzzMessage;
+
+#[cfg(feature = "fuzz")]
+mod fuzz {
+    use super::*;
+    use crate::datastructures::{common::Tlv, WireFormatError};
+
+    #[derive(Debug, Clone, PartialEq, Eq)]
+    pub struct FuzzMessage<'a> {
+        inner: Message<'a>,
+    }
+
+    #[derive(Debug, Clone, PartialEq, Eq)]
+    pub struct FuzzTlv<'a>(Tlv<'a>);
+
+    impl<'a> FuzzMessage<'a> {
+        pub fn deserialize(buffer: &'a [u8]) -> Result<Self, impl std::error::Error> {
+            Ok::<FuzzMessage, WireFormatError>(FuzzMessage {
+                inner: Message::deserialize(buffer)?,
+            })
+        }
+
+        pub fn serialize(&self, buffer: &mut [u8]) -> Result<usize, impl std::error::Error> {
+            self.inner.serialize(buffer)
+        }
+
+        pub fn tlv(&self) -> impl Iterator<Item = FuzzTlv<'_>> + '_ {
+            self.inner.suffix.tlv().map(FuzzTlv)
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct Message<'a> {
+    pub(crate) header: Header,
+    pub(crate) body: MessageBody,
+    pub(crate) suffix: TlvSet<'a>,
+}
+
+impl<'a> Message<'a> {
+    pub(crate) fn is_event(&self) -> bool {
+        use MessageBody::*;
+        match self.body {
+            Sync(_) | DelayReq(_) | PDelayReq(_) | PDelayResp(_) => true,
+            FollowUp(_)
+            | DelayResp(_)
+            | PDelayRespFollowUp(_)
+            | Announce(_)
+            | Signaling(_)
+            | Management(_) => false,
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) enum MessageBody {
+    Sync(SyncMessage),
+    DelayReq(DelayReqMessage),
+    PDelayReq(PDelayReqMessage),
+    PDelayResp(PDelayRespMessage),
+    FollowUp(FollowUpMessage),
+    DelayResp(DelayRespMessage),
+    PDelayRespFollowUp(PDelayRespFollowUpMessage),
+    Announce(AnnounceMessage),
+    Signaling(SignalingMessage),
+    Management(ManagementMessage),
+}
+
+impl MessageBody {
+    fn wire_size(&self) -> usize {
+        match &self {
+            MessageBody::Sync(m) => m.content_size(),
+            MessageBody::DelayReq(m) => m.content_size(),
+            MessageBody::PDelayReq(m) => m.content_size(),
+            MessageBody::PDelayResp(m) => m.content_size(),
+            MessageBody::FollowUp(m) => m.content_size(),
+            MessageBody::DelayResp(m) => m.content_size(),
+            MessageBody::PDelayRespFollowUp(m) => m.content_size(),
+            MessageBody::Announce(m) => m.content_size(),
+            MessageBody::Signaling(m) => m.content_size(),
+            MessageBody::Management(m) => m.content_size(),
+        }
+    }
+
+    fn content_type(&self) -> MessageType {
+        match self {
+            MessageBody::Sync(_) => MessageType::Sync,
+            MessageBody::DelayReq(_) => MessageType::DelayReq,
+            MessageBody::PDelayReq(_) => MessageType::PDelayReq,
+            MessageBody::PDelayResp(_) => MessageType::PDelayResp,
+            MessageBody::FollowUp(_) => MessageType::FollowUp,
+            MessageBody::DelayResp(_) => MessageType::DelayResp,
+            MessageBody::PDelayRespFollowUp(_) => MessageType::PDelayRespFollowUp,
+            MessageBody::Announce(_) => MessageType::Announce,
+            MessageBody::Signaling(_) => MessageType::Signaling,
+            MessageBody::Management(_) => MessageType::Management,
+        }
+    }
+
+    pub(crate) fn serialize(&self, buffer: &mut [u8]) -> Result<usize, super::WireFormatError> {
+        match &self {
+            MessageBody::Sync(m) => m.serialize_content(buffer)?,
+            MessageBody::DelayReq(m) => m.serialize_content(buffer)?,
+            MessageBody::PDelayReq(m) => m.serialize_content(buffer)?,
+            MessageBody::PDelayResp(m) => m.serialize_content(buffer)?,
+            MessageBody::FollowUp(m) => m.serialize_content(buffer)?,
+            MessageBody::DelayResp(m) => m.serialize_content(buffer)?,
+            MessageBody::PDelayRespFollowUp(m) => m.serialize_content(buffer)?,
+            MessageBody::Announce(m) => m.serialize_content(buffer)?,
+            MessageBody::Signaling(m) => m.serialize_content(buffer)?,
+            MessageBody::Management(m) => m.serialize_content(buffer)?,
+        }
+
+        Ok(self.wire_size())
+    }
+
+    pub(crate) fn deserialize(
+        message_type: MessageType,
+        header: &Header,
+        buffer: &[u8],
+    ) -> Result<Self, super::WireFormatError> {
+        let body = match message_type {
+            MessageType::Sync => MessageBody::Sync(SyncMessage::deserialize_content(buffer)?),
+            MessageType::DelayReq => {
+                MessageBody::DelayReq(DelayReqMessage::deserialize_content(buffer)?)
+            }
+            MessageType::PDelayReq => {
+                MessageBody::PDelayReq(PDelayReqMessage::deserialize_content(buffer)?)
+            }
+            MessageType::PDelayResp => {
+                MessageBody::PDelayResp(PDelayRespMessage::deserialize_content(buffer)?)
+            }
+            MessageType::FollowUp => {
+                MessageBody::FollowUp(FollowUpMessage::deserialize_content(buffer)?)
+            }
+            MessageType::DelayResp => {
+                MessageBody::DelayResp(DelayRespMessage::deserialize_content(buffer)?)
+            }
+            MessageType::PDelayRespFollowUp => MessageBody::PDelayRespFollowUp(
+                PDelayRespFollowUpMessage::deserialize_content(buffer)?,
+            ),
+            MessageType::Announce => {
+                MessageBody::Announce(AnnounceMessage::deserialize_content(*header, buffer)?)
+            }
+            MessageType::Signaling => {
+                MessageBody::Signaling(SignalingMessage::deserialize_content(buffer)?)
+            }
+            MessageType::Management => {
+                MessageBody::Management(ManagementMessage::deserialize_content(buffer)?)
+            }
+        };
+
+        Ok(body)
+    }
+}
+
+fn base_header(default_ds: &DefaultDS, port_identity: PortIdentity, sequence_id: u16) -> Header {
+    Header {
+        sdo_id: default_ds.sdo_id,
+        domain_number: default_ds.domain_number,
+        source_port_identity: port_identity,
+        sequence_id,
+        ..Default::default()
+    }
+}
+
+impl Message<'_> {
+    pub(crate) fn sync(
+        default_ds: &DefaultDS,
+        port_identity: PortIdentity,
+        sequence_id: u16,
+    ) -> Self {
+        let header = Header {
+            two_step_flag: true,
+            ..base_header(default_ds, port_identity, sequence_id)
+        };
+
+        Message {
+            header,
+            body: MessageBody::Sync(SyncMessage {
+                origin_timestamp: Default::default(),
+            }),
+            suffix: TlvSet::default(),
+        }
+    }
+
+    pub(crate) fn follow_up(
+        default_ds: &DefaultDS,
+        port_identity: PortIdentity,
+        sequence_id: u16,
+        timestamp: Time,
+    ) -> Self {
+        let header = Header {
+            correction_field: timestamp.subnano(),
+            ..base_header(default_ds, port_identity, sequence_id)
+        };
+
+        Message {
+            header,
+            body: MessageBody::FollowUp(FollowUpMessage {
+                precise_origin_timestamp: timestamp.into(),
+            }),
+            suffix: TlvSet::default(),
+        }
+    }
+
+    pub(crate) fn announce(
+        global: &PtpInstanceState,
+        port_identity: PortIdentity,
+        sequence_id: u16,
+    ) -> Self {
+        let time_properties_ds = &global.time_properties_ds;
+
+        let header = Header {
+            leap59: time_properties_ds.leap_indicator == LeapIndicator::Leap59,
+            leap61: time_properties_ds.leap_indicator == LeapIndicator::Leap61,
+            current_utc_offset_valid: time_properties_ds.current_utc_offset.is_some(),
+            ptp_timescale: time_properties_ds.ptp_timescale,
+            time_tracable: time_properties_ds.time_traceable,
+            frequency_tracable: time_properties_ds.frequency_traceable,
+            ..base_header(&global.default_ds, port_identity, sequence_id)
+        };
+
+        let body = MessageBody::Announce(AnnounceMessage {
+            header,
+            origin_timestamp: Default::default(),
+            current_utc_offset: time_properties_ds.current_utc_offset.unwrap_or_default(),
+            grandmaster_priority_1: global.parent_ds.grandmaster_priority_1,
+            grandmaster_clock_quality: global.parent_ds.grandmaster_clock_quality,
+            grandmaster_priority_2: global.parent_ds.grandmaster_priority_2,
+            grandmaster_identity: global.parent_ds.grandmaster_identity,
+            steps_removed: global.current_ds.steps_removed,
+            time_source: time_properties_ds.time_source,
+        });
+
+        Message {
+            header,
+            body,
+            suffix: TlvSet::default(),
+        }
+    }
+
+    pub(crate) fn delay_req(
+        default_ds: &DefaultDS,
+        port_identity: PortIdentity,
+        sequence_id: u16,
+    ) -> Self {
+        let header = Header {
+            log_message_interval: 0x7f,
+            ..base_header(default_ds, port_identity, sequence_id)
+        };
+
+        Message {
+            header,
+            body: MessageBody::DelayReq(DelayReqMessage {
+                origin_timestamp: WireTimestamp::default(),
+            }),
+            suffix: TlvSet::default(),
+        }
+    }
+
+    pub(crate) fn delay_resp(
+        request_header: Header,
+        request: DelayReqMessage,
+        port_identity: PortIdentity,
+        min_delay_req_interval: Interval,
+        timestamp: Time,
+    ) -> Self {
+        // TODO is it really correct that we don't use any of the data?
+        let _ = request;
+
+        let header = Header {
+            two_step_flag: false,
+            source_port_identity: port_identity,
+            correction_field: TimeInterval(
+                request_header.correction_field.0 + timestamp.subnano().0,
+            ),
+            log_message_interval: min_delay_req_interval.as_log_2(),
+            ..request_header
+        };
+
+        let body = MessageBody::DelayResp(DelayRespMessage {
+            receive_timestamp: timestamp.into(),
+            requesting_port_identity: request_header.source_port_identity,
+        });
+
+        Message {
+            header,
+            body,
+            suffix: TlvSet::default(),
+        }
+    }
+}
+
+impl<'a> Message<'a> {
+    pub(crate) fn header(&self) -> &Header {
+        &self.header
+    }
+
+    /// The byte size on the wire of this message
+    pub(crate) fn wire_size(&self) -> usize {
+        self.header.wire_size() + self.body.wire_size() + self.suffix.wire_size()
+    }
+
+    /// Serializes the object into the PTP wire format.
+    ///
+    /// Returns the used buffer size that contains the message or an error.
+    pub(crate) fn serialize(&self, buffer: &mut [u8]) -> Result<usize, super::WireFormatError> {
+        let (header, rest) = buffer.split_at_mut(34);
+        let (body, tlv) = rest.split_at_mut(self.body.wire_size());
+
+        self.header
+            .serialize_header(
+                self.body.content_type(),
+                self.body.wire_size() + self.suffix.wire_size(),
+                header,
+            )
+            .unwrap();
+
+        self.body.serialize(body).unwrap();
+
+        self.suffix.serialize(tlv).unwrap();
+
+        Ok(self.wire_size())
+    }
+
+    /// Deserializes a message from the PTP wire format.
+    ///
+    /// Returns the message or an error.
+    pub(crate) fn deserialize(buffer: &'a [u8]) -> Result<Self, super::WireFormatError> {
+        let header_data = Header::deserialize_header(buffer)?;
+
+        // Skip the header bytes and only keep the content
+        let content_buffer = &buffer[34..];
+
+        let body = MessageBody::deserialize(
+            header_data.message_type,
+            &header_data.header,
+            content_buffer,
+        )?;
+
+        let tlv_buffer = &content_buffer
+            .get(body.wire_size()..)
+            .ok_or(super::WireFormatError::BufferTooShort)?;
+        let suffix = TlvSet::deserialize(tlv_buffer)?;
+
+        Ok(Message {
+            header: header_data.header,
+            body,
+            suffix,
+        })
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/p_delay_req.rs.html b/docs/src/statime/datastructures/messages/p_delay_req.rs.html new file mode 100644 index 000000000..687b9b51c --- /dev/null +++ b/docs/src/statime/datastructures/messages/p_delay_req.rs.html @@ -0,0 +1,135 @@ +p_delay_req.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+
use crate::datastructures::{common::WireTimestamp, WireFormat, WireFormatError};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct PDelayReqMessage {
+    pub(super) origin_timestamp: WireTimestamp,
+}
+
+impl PDelayReqMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        10
+    }
+
+    pub(crate) fn serialize_content(
+        &self,
+        buffer: &mut [u8],
+    ) -> Result<(), crate::datastructures::WireFormatError> {
+        if buffer.len() < 10 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        self.origin_timestamp.serialize(&mut buffer[0..10])?;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(
+        buffer: &[u8],
+    ) -> Result<Self, crate::datastructures::WireFormatError> {
+        let slice = buffer.get(0..10).ok_or(WireFormatError::BufferTooShort)?;
+
+        Ok(Self {
+            origin_timestamp: WireTimestamp::deserialize(slice)?,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x64, 0xfa, 0xb0],
+            PDelayReqMessage {
+                origin_timestamp: WireTimestamp {
+                    seconds: 1169232218,
+                    nanos: 174389936,
+                },
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 10];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data =
+                PDelayReqMessage::deserialize_content(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/p_delay_resp.rs.html b/docs/src/statime/datastructures/messages/p_delay_resp.rs.html new file mode 100644 index 000000000..1ce71ad9f --- /dev/null +++ b/docs/src/statime/datastructures/messages/p_delay_resp.rs.html @@ -0,0 +1,167 @@ +p_delay_resp.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+
use crate::datastructures::{
+    common::{PortIdentity, WireTimestamp},
+    WireFormat, WireFormatError,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct PDelayRespMessage {
+    pub(super) request_receive_timestamp: WireTimestamp,
+    pub(super) requesting_port_identity: PortIdentity,
+}
+
+impl PDelayRespMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        20
+    }
+
+    pub(crate) fn serialize_content(
+        &self,
+        buffer: &mut [u8],
+    ) -> Result<(), crate::datastructures::WireFormatError> {
+        if buffer.len() < 20 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+        self.request_receive_timestamp
+            .serialize(&mut buffer[0..10])?;
+        self.requesting_port_identity
+            .serialize(&mut buffer[10..20])?;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(
+        buffer: &[u8],
+    ) -> Result<Self, crate::datastructures::WireFormatError> {
+        if buffer.len() < 20 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+        Ok(Self {
+            request_receive_timestamp: WireTimestamp::deserialize(&buffer[0..10])?,
+            requesting_port_identity: PortIdentity::deserialize(&buffer[10..20])?,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::datastructures::common::{ClockIdentity, PortIdentity};
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [
+                0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x64, 0xfa, 0xb0, 0x01, 0x02, 0x03, 0x04,
+                0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+            ],
+            PDelayRespMessage {
+                request_receive_timestamp: WireTimestamp {
+                    seconds: 1169232218,
+                    nanos: 174389936,
+                },
+                requesting_port_identity: PortIdentity {
+                    clock_identity: ClockIdentity([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]),
+                    port_number: 0x090a,
+                },
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 20];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data =
+                PDelayRespMessage::deserialize_content(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/p_delay_resp_follow_up.rs.html b/docs/src/statime/datastructures/messages/p_delay_resp_follow_up.rs.html new file mode 100644 index 000000000..2d09105f6 --- /dev/null +++ b/docs/src/statime/datastructures/messages/p_delay_resp_follow_up.rs.html @@ -0,0 +1,169 @@ +p_delay_resp_follow_up.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+
use crate::datastructures::{
+    common::{PortIdentity, WireTimestamp},
+    WireFormat, WireFormatError,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct PDelayRespFollowUpMessage {
+    pub(super) response_origin_timestamp: WireTimestamp,
+    pub(super) requesting_port_identity: PortIdentity,
+}
+
+impl PDelayRespFollowUpMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        20
+    }
+
+    pub(crate) fn serialize_content(
+        &self,
+        buffer: &mut [u8],
+    ) -> Result<(), crate::datastructures::WireFormatError> {
+        if buffer.len() < 20 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        self.response_origin_timestamp
+            .serialize(&mut buffer[0..10])?;
+        self.requesting_port_identity
+            .serialize(&mut buffer[10..20])?;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(
+        buffer: &[u8],
+    ) -> Result<Self, crate::datastructures::WireFormatError> {
+        if buffer.len() < 20 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+        Ok(Self {
+            response_origin_timestamp: WireTimestamp::deserialize(&buffer[0..10])?,
+            requesting_port_identity: PortIdentity::deserialize(&buffer[10..20])?,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::datastructures::common::{ClockIdentity, PortIdentity};
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [
+                0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x64, 0xfa, 0xb0, 0x01, 0x02, 0x03, 0x04,
+                0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+            ],
+            PDelayRespFollowUpMessage {
+                response_origin_timestamp: WireTimestamp {
+                    seconds: 1169232218,
+                    nanos: 174389936,
+                },
+                requesting_port_identity: PortIdentity {
+                    clock_identity: ClockIdentity([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]),
+                    port_number: 0x090a,
+                },
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 20];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data =
+                PDelayRespFollowUpMessage::deserialize_content(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/signalling.rs.html b/docs/src/statime/datastructures/messages/signalling.rs.html new file mode 100644 index 000000000..29183d700 --- /dev/null +++ b/docs/src/statime/datastructures/messages/signalling.rs.html @@ -0,0 +1,67 @@ +signalling.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+
use crate::datastructures::{common::PortIdentity, WireFormat, WireFormatError};
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct SignalingMessage {
+    pub(super) target_port_identity: PortIdentity,
+}
+
+impl SignalingMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        10
+    }
+
+    pub(crate) fn serialize_content(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        if buffer.len() < 10 {
+            return Err(WireFormatError::BufferTooShort);
+        }
+
+        let (left, _) = buffer.split_at_mut(10);
+
+        self.target_port_identity.serialize(left)?;
+
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        let identity_bytes = buffer.get(0..10).ok_or(WireFormatError::BufferTooShort)?;
+        let target_port_identity = PortIdentity::deserialize(identity_bytes)?;
+
+        Ok(Self {
+            target_port_identity,
+        })
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/messages/sync.rs.html b/docs/src/statime/datastructures/messages/sync.rs.html new file mode 100644 index 000000000..b858bef95 --- /dev/null +++ b/docs/src/statime/datastructures/messages/sync.rs.html @@ -0,0 +1,115 @@ +sync.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+
use crate::datastructures::{common::WireTimestamp, WireFormat, WireFormatError};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct SyncMessage {
+    pub(crate) origin_timestamp: WireTimestamp,
+}
+
+impl SyncMessage {
+    pub(crate) fn content_size(&self) -> usize {
+        10
+    }
+
+    pub(crate) fn serialize_content(&self, buffer: &mut [u8]) -> Result<(), WireFormatError> {
+        self.origin_timestamp.serialize(&mut buffer[0..10])?;
+        Ok(())
+    }
+
+    pub(crate) fn deserialize_content(buffer: &[u8]) -> Result<Self, WireFormatError> {
+        match buffer.get(0..10) {
+            None => Err(WireFormatError::BufferTooShort),
+            Some(slice) => Ok(Self {
+                origin_timestamp: WireTimestamp::deserialize(slice)?,
+            }),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn timestamp_wireformat() {
+        let representations = [(
+            [0x00, 0x00, 0x45, 0xb1, 0x11, 0x5a, 0x0a, 0x64, 0xfa, 0xb0],
+            SyncMessage {
+                origin_timestamp: WireTimestamp {
+                    seconds: 1169232218,
+                    nanos: 174389936,
+                },
+            },
+        )];
+
+        for (byte_representation, object_representation) in representations {
+            // Test the serialization output
+            let mut serialization_buffer = [0; 10];
+            object_representation
+                .serialize_content(&mut serialization_buffer)
+                .unwrap();
+            assert_eq!(serialization_buffer, byte_representation);
+
+            // Test the deserialization output
+            let deserialized_data = SyncMessage::deserialize_content(&byte_representation).unwrap();
+            assert_eq!(deserialized_data, object_representation);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/datastructures/mod.rs.html b/docs/src/statime/datastructures/mod.rs.html new file mode 100644 index 000000000..c2845c128 --- /dev/null +++ b/docs/src/statime/datastructures/mod.rs.html @@ -0,0 +1,125 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
//! General datastructures as defined by the ptp spec
+
+use core::fmt::Debug;
+
+use self::messages::EnumConversionError;
+
+pub mod common;
+pub mod datasets;
+pub mod messages;
+
+#[derive(Clone, Debug)]
+pub(crate) enum WireFormatError {
+    EnumConversionError,
+    BufferTooShort,
+    CapacityError,
+    Invalid,
+}
+
+impl core::fmt::Display for WireFormatError {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        match self {
+            WireFormatError::EnumConversionError => f.write_str("enum conversion failed"),
+            WireFormatError::BufferTooShort => f.write_str("a buffer is too short"),
+            WireFormatError::CapacityError => f.write_str("a container has insufficient capacity"),
+            WireFormatError::Invalid => f.write_str("an invariant was violated"),
+        }
+    }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for WireFormatError {}
+
+#[cfg(feature = "error_in_core")]
+impl core::error::Error for WireFormatError {}
+
+impl From<arrayvec::CapacityError> for WireFormatError {
+    fn from(_: arrayvec::CapacityError) -> Self {
+        WireFormatError::CapacityError
+    }
+}
+
+impl From<EnumConversionError> for WireFormatError {
+    fn from(_: EnumConversionError) -> Self {
+        Self::EnumConversionError
+    }
+}
+
+trait WireFormat: Debug + Clone + Eq {
+    /// The byte size on the wire of this object
+    fn wire_size(&self) -> usize;
+
+    /// Serializes the object into the PTP wire format.
+    ///
+    /// Returns the used buffer size that contains the message or an error.
+    fn serialize(&self, buffer: &mut [u8]) -> Result<(), WireFormatError>;
+
+    /// Deserializes the object from the PTP wire format.
+    ///
+    /// Returns the object and the size in the buffer that it takes up or an
+    /// error.
+    fn deserialize(buffer: &[u8]) -> Result<Self, WireFormatError>;
+}
+
\ No newline at end of file diff --git a/docs/src/statime/filters/basic.rs.html b/docs/src/statime/filters/basic.rs.html new file mode 100644 index 000000000..d7d4a8ad4 --- /dev/null +++ b/docs/src/statime/filters/basic.rs.html @@ -0,0 +1,295 @@ +basic.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+
//! Implementation of [BasicFilter]
+
+use fixed::traits::LossyInto;
+
+use super::{Filter, FilterUpdate};
+use crate::{port::Measurement, time::Duration, Clock, Time};
+
+#[derive(Debug)]
+struct PrevStepData {
+    event_time: Time,
+    offset: Duration,
+    correction: Duration,
+}
+
+/// A simple averaging filter
+///
+/// This filter uses simple averaging to determine what the clock control
+/// outputs should be.
+#[derive(Debug)]
+pub struct BasicFilter {
+    last_step: Option<PrevStepData>,
+
+    offset_confidence: Duration,
+    freq_confidence: f64,
+
+    gain: f64,
+
+    cur_freq: f64,
+}
+
+impl Filter for BasicFilter {
+    type Config = f64;
+
+    fn new(gain: f64) -> Self {
+        Self {
+            last_step: None,
+            offset_confidence: Duration::from_nanos(1_000_000_000),
+            freq_confidence: 1e-4,
+            gain,
+            cur_freq: 0.0,
+        }
+    }
+
+    fn measurement<C: Clock>(&mut self, measurement: Measurement, clock: &mut C) -> FilterUpdate {
+        let mut update = FilterUpdate::default();
+
+        if let Some(delay) = measurement.delay {
+            update.mean_delay = Some(delay);
+        }
+
+        let Some(offset) = measurement.offset else {
+            // No measurement, so no further actions
+            return update;
+        };
+
+        // Reset on too-large difference
+        if offset.abs() > Duration::from_nanos(1_000_000_000) {
+            log::debug!("Offset too large, stepping {}", offset);
+            self.offset_confidence = Duration::from_nanos(1_000_000_000);
+            self.freq_confidence = 1e-4;
+
+            if let Err(error) = clock.step_clock(-offset) {
+                log::error!("Could not step clock: {:?}", error);
+            }
+            return update;
+        }
+
+        // Determine offset
+        let mut clamped_offset = offset;
+        if offset.abs() > self.offset_confidence {
+            clamped_offset = offset.clamp(-self.offset_confidence, self.offset_confidence);
+            self.offset_confidence *= 2i32;
+        } else {
+            self.offset_confidence -= (self.offset_confidence - offset.abs()) * self.gain;
+        }
+
+        // And decide it's correction
+        let correction = -clamped_offset * self.gain;
+
+        let freq_corr = if let Some(last_step) = &self.last_step {
+            // Calculate interval for us
+            let interval_local: f64 =
+                (measurement.event_time - last_step.event_time - last_step.correction)
+                    .nanos()
+                    .lossy_into();
+            // and for the master
+            let interval_master: f64 = ((measurement.event_time - offset)
+                - (last_step.event_time - last_step.offset))
+                .nanos()
+                .lossy_into();
+
+            // get relative frequency difference
+            let mut freq_diff = interval_local / interval_master;
+            if libm::fabs(freq_diff - 1.0) > self.freq_confidence {
+                freq_diff = freq_diff.clamp(1.0 - self.freq_confidence, 1.0 + self.freq_confidence);
+                self.freq_confidence *= 2.0;
+            } else {
+                self.freq_confidence -=
+                    (self.freq_confidence - libm::fabs(freq_diff - 1.0)) * self.gain;
+            }
+
+            // and decide the correction (and convert to ppm)
+            -(freq_diff - 1.0) * self.gain * 0.1 * 1e6
+        } else {
+            // No data, so first run, so initialize
+            if let Err(error) = clock.set_frequency(0.0) {
+                log::error!("Could not initialize clock frequency: {:?}", error);
+            }
+            self.cur_freq = 0.0;
+            0.0
+        };
+
+        // unwrap is ok here since we always have an offset
+        log::info!(
+            "Offset to master: {:e}ns, corrected with phase change {:e}ns and freq change {:e}ppm",
+            offset.nanos(),
+            correction.nanos(),
+            freq_corr
+        );
+
+        // Store data for next time
+        self.last_step = Some(PrevStepData {
+            event_time: measurement.event_time,
+            offset,
+            correction,
+        });
+
+        if let Err(error) = clock.step_clock(correction) {
+            log::error!("Could not step clock: {:?}", error);
+        }
+        if let Err(error) = clock.set_frequency(self.cur_freq + freq_corr) {
+            log::error!("Could not adjust clock frequency: {:?}", error);
+        } else {
+            self.cur_freq += freq_corr;
+        }
+        update
+    }
+
+    fn demobilize<C: Clock>(self, _clock: &mut C) {
+        // ignore
+    }
+
+    fn update<C: Clock>(&mut self, _clock: &mut C) -> FilterUpdate {
+        // ignore
+        Default::default()
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/filters/mod.rs.html b/docs/src/statime/filters/mod.rs.html new file mode 100644 index 000000000..3fb5797e9 --- /dev/null +++ b/docs/src/statime/filters/mod.rs.html @@ -0,0 +1,75 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+
//! Definitions and implementations for the abstracted measurement filters
+
+pub mod basic;
+
+use crate::{port::Measurement, Clock, Duration};
+
+#[derive(Debug, Clone, Default, PartialEq, Eq)]
+pub struct FilterUpdate {
+    pub next_update: Option<core::time::Duration>,
+    pub mean_delay: Option<Duration>,
+}
+
+/// A filter for post-processing time measurements.
+///
+/// Filters are responsible for dealing with the network noise, and should
+/// average out the input a bit so minor network variations are not immediately
+/// reflected in the synchronization of the clock.
+///
+/// This crate provides a simple [`BasicFilter`](basic::BasicFilter) which is
+/// suitable for most needs, but users can implement their own if desired.
+pub trait Filter {
+    type Config: Clone;
+
+    /// Create a new instance of the filter.
+    fn new(config: Self::Config) -> Self;
+
+    /// Put a new measurement in the filter.
+    /// The filter can then use this to adjust the clock
+    fn measurement<C: Clock>(&mut self, m: Measurement, clock: &mut C) -> FilterUpdate;
+
+    /// Update initiated through [FilterUpdate::next_update] timeout.
+    fn update<C: Clock>(&mut self, clock: &mut C) -> FilterUpdate;
+
+    /// Handle ending of time synchronization from the source
+    /// associated with this filter.
+    fn demobilize<C: Clock>(self, clock: &mut C);
+}
+
\ No newline at end of file diff --git a/docs/src/statime/lib.rs.html b/docs/src/statime/lib.rs.html new file mode 100644 index 000000000..e7da17c2c --- /dev/null +++ b/docs/src/statime/lib.rs.html @@ -0,0 +1,125 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
//! Statime is a library providing an implementation of PTP version 2.1
+//! (IEEE1588-2019). It provides all the building blocks to setup PTP ordinary
+//! and boundary clocks.
+//!
+//! Note: We are currently planning a major overhaul of the library. This will
+//! also result in significant changes to the public API.
+//!
+//! # Device interfaces
+//! `statime` is designed to be able to work with many different underlying
+//! platforms, including embedded targets. This does mean that it cannot use the
+//! standard library and platform specific libraries to interact with the system
+//! clock and to access the network. That needs to be provided by the user of
+//! the library.
+//!
+//! The `statime` crate defines a [`Clock`] interface that provide access to the
+//! system clock. The [`NetworkRuntime`] and [`NetworkPort`]
+//! abstractions provide the needed glue to access the network.
+//!
+//! On modern linux kernels, the `statime-linux` crate provides ready to use
+//! implementations of these interfaces. For other platforms the user will need
+//! to implement these themselves.
+//!
+//! # Clock identities
+//!
+//! All ptp clocks in a network need a unique clock identity. One way to achieve
+//! this is to use (one of) the device's mac address to generate this
+//! identifier. As this requires platform specific code to get the mac address,
+//! this library does not implement this. Rather, direct access is given to the
+//! clock identity type, and the user can create one from a mac address by
+//! storing it in the first six bytes of the clock identifier, setting the
+//! remaining bytes to 0. For more details on the exact specification of the
+//! generation procedure, see IEEE1588-2019 section 7.5.2.2.2
+
+#![no_std]
+
+#[cfg(feature = "std")]
+extern crate std;
+
+mod bmc;
+mod clock;
+mod config;
+mod datastructures;
+mod filters;
+mod port;
+mod ptp_instance;
+mod time;
+
+pub use clock::Clock;
+pub use config::{DelayMechanism, InstanceConfig, PortConfig};
+#[cfg(feature = "fuzz")]
+pub use datastructures::messages::FuzzMessage;
+pub use datastructures::{
+    common::{ClockAccuracy, ClockIdentity, ClockQuality, LeapIndicator, TimeSource},
+    datasets::TimePropertiesDS,
+    messages::{SdoId, MAX_DATA_LEN},
+};
+pub use filters::{basic::BasicFilter, Filter};
+pub use port::{
+    InBmca, Measurement, Port, PortAction, PortActionIterator, Running, TimestampContext,
+};
+pub use ptp_instance::PtpInstance;
+pub use time::{Duration, Interval, Time};
+
\ No newline at end of file diff --git a/docs/src/statime/port/measurement.rs.html b/docs/src/statime/port/measurement.rs.html new file mode 100644 index 000000000..6a153cc80 --- /dev/null +++ b/docs/src/statime/port/measurement.rs.html @@ -0,0 +1,37 @@ +measurement.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+
use crate::time::{Duration, Time};
+
+/// A single measurement as produced by a PTP port.
+/// Depending on what trigerred the measurements, not
+/// all fields will be populated
+#[derive(Default, Clone, Copy, Debug, Eq, PartialEq)]
+pub struct Measurement {
+    /// Time this measurement was made.
+    pub event_time: Time,
+    /// Offset to the remote PTP node.
+    pub offset: Option<Duration>,
+    /// Delay to the remote PTP node.
+    pub delay: Option<Duration>,
+    /// Raw offset calculated from a sync message
+    pub raw_sync_offset: Option<Duration>,
+    /// Raw offset calculated from a delay message
+    pub raw_delay_offset: Option<Duration>,
+}
+
\ No newline at end of file diff --git a/docs/src/statime/port/mod.rs.html b/docs/src/statime/port/mod.rs.html new file mode 100644 index 000000000..8f79b74b6 --- /dev/null +++ b/docs/src/statime/port/mod.rs.html @@ -0,0 +1,1627 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+
use core::ops::Deref;
+
+use arrayvec::ArrayVec;
+use atomic_refcell::{AtomicRef, AtomicRefCell};
+pub use measurement::Measurement;
+use rand::Rng;
+use state::{MasterState, PortState};
+
+use self::state::SlaveState;
+use crate::{
+    bmc::{
+        acceptable_master::AcceptableMasterList,
+        bmca::{BestAnnounceMessage, Bmca, RecommendedState},
+    },
+    clock::Clock,
+    config::PortConfig,
+    datastructures::{
+        common::{LeapIndicator, PortIdentity, TimeSource},
+        datasets::{CurrentDS, DefaultDS, ParentDS, TimePropertiesDS},
+        messages::{Message, MessageBody},
+    },
+    filters::{Filter, FilterUpdate},
+    ptp_instance::PtpInstanceState,
+    time::Duration,
+    Time, MAX_DATA_LEN,
+};
+
+// Needs to be here because of use rules
+macro_rules! actions {
+    [] => {
+        {
+            crate::port::PortActionIterator::from(::arrayvec::ArrayVec::new())
+        }
+    };
+    [$action:expr] => {
+        {
+            let mut list = ::arrayvec::ArrayVec::new();
+            list.push($action);
+            PortActionIterator::from(list)
+        }
+    };
+    [$action1:expr, $action2:expr] => {
+        {
+            let mut list = ::arrayvec::ArrayVec::new();
+            list.push($action1);
+            list.push($action2);
+            PortActionIterator::from(list)
+        }
+    };
+}
+
+mod measurement;
+mod sequence_id;
+pub(crate) mod state;
+
+/// A single port of the PTP instance
+///
+/// One of these needs to be created per port of the PTP instance.
+#[derive(Debug)]
+pub struct Port<L, A, R, C, F: Filter> {
+    config: PortConfig<()>,
+    filter_config: F::Config,
+    clock: C,
+    // PortDS port_identity
+    pub(crate) port_identity: PortIdentity,
+    // Corresponds with PortDS port_state and enabled
+    port_state: PortState<F>,
+    bmca: Bmca<A>,
+    packet_buffer: [u8; MAX_DATA_LEN],
+    lifecycle: L,
+    rng: R,
+}
+
+#[derive(Debug)]
+pub struct Running<'a> {
+    state_refcell: &'a AtomicRefCell<PtpInstanceState>,
+    state: AtomicRef<'a, PtpInstanceState>,
+}
+
+#[derive(Debug)]
+pub struct InBmca<'a> {
+    pending_action: PortActionIterator<'static>,
+    local_best: Option<BestAnnounceMessage>,
+    state_refcell: &'a AtomicRefCell<PtpInstanceState>,
+}
+
+// Making this non-copy and non-clone ensures a single handle_send_timestamp
+// per SendTimeCritical
+#[derive(Debug)]
+pub struct TimestampContext {
+    inner: TimestampContextInner,
+}
+
+#[derive(Debug)]
+enum TimestampContextInner {
+    Sync { id: u16 },
+    DelayReq { id: u16 },
+}
+
+#[derive(Debug)]
+pub enum PortAction<'a> {
+    SendTimeCritical {
+        context: TimestampContext,
+        data: &'a [u8],
+    },
+    SendGeneral {
+        data: &'a [u8],
+    },
+    ResetAnnounceTimer {
+        duration: core::time::Duration,
+    },
+    ResetSyncTimer {
+        duration: core::time::Duration,
+    },
+    ResetDelayRequestTimer {
+        duration: core::time::Duration,
+    },
+    ResetAnnounceReceiptTimer {
+        duration: core::time::Duration,
+    },
+    ResetFilterUpdateTimer {
+        duration: core::time::Duration,
+    },
+}
+
+const MAX_ACTIONS: usize = 2;
+
+/// Guarantees to end user: Any set of actions will only ever contain a single
+/// time critical send
+#[derive(Debug)]
+#[must_use]
+pub struct PortActionIterator<'a> {
+    internal: <ArrayVec<PortAction<'a>, MAX_ACTIONS> as IntoIterator>::IntoIter,
+}
+
+impl<'a> PortActionIterator<'a> {
+    pub fn empty() -> Self {
+        Self {
+            internal: ArrayVec::new().into_iter(),
+        }
+    }
+    fn from(list: ArrayVec<PortAction<'a>, MAX_ACTIONS>) -> Self {
+        Self {
+            internal: list.into_iter(),
+        }
+    }
+    fn from_filter(update: FilterUpdate) -> Self {
+        if let Some(duration) = update.next_update {
+            actions![PortAction::ResetFilterUpdateTimer { duration }]
+        } else {
+            actions![]
+        }
+    }
+}
+
+impl<'a> Iterator for PortActionIterator<'a> {
+    type Item = PortAction<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.internal.next()
+    }
+}
+
+impl<'a, A, C: Clock, F: Filter, R: Rng> Port<Running<'a>, A, R, C, F> {
+    // Send timestamp for last timecritical message became available
+    pub fn handle_send_timestamp(
+        &mut self,
+        context: TimestampContext,
+        timestamp: Time,
+    ) -> PortActionIterator<'_> {
+        let actions = self.port_state.handle_timestamp(
+            context,
+            timestamp,
+            self.port_identity,
+            &self.lifecycle.state.default_ds,
+            &mut self.clock,
+            &mut self.packet_buffer,
+        );
+
+        actions
+    }
+
+    // Handle the announce timer going of
+    pub fn handle_announce_timer(&mut self) -> PortActionIterator<'_> {
+        self.port_state.send_announce(
+            self.lifecycle.state.deref(),
+            &self.config,
+            self.port_identity,
+            &mut self.packet_buffer,
+        )
+    }
+
+    // Handle the sync timer going of
+    pub fn handle_sync_timer(&mut self) -> PortActionIterator<'_> {
+        self.port_state.send_sync(
+            &self.config,
+            self.port_identity,
+            &self.lifecycle.state.default_ds,
+            &mut self.packet_buffer,
+        )
+    }
+
+    // Handle the sync timer going of
+    pub fn handle_delay_request_timer(&mut self) -> PortActionIterator<'_> {
+        self.port_state.send_delay_request(
+            &mut self.rng,
+            &self.config,
+            self.port_identity,
+            &self.lifecycle.state.default_ds,
+            &mut self.packet_buffer,
+        )
+    }
+
+    // Handle the announce receipt timer going off
+    pub fn handle_announce_receipt_timer(&mut self) -> PortActionIterator<'_> {
+        // we didn't hear announce messages from other masters, so become master
+        // ourselves
+        match self.port_state {
+            PortState::Master(_) => (),
+            _ => self.set_forced_port_state(PortState::Master(MasterState::new())),
+        }
+
+        // Immediately start sending syncs and announces
+        actions![
+            PortAction::ResetAnnounceTimer {
+                duration: core::time::Duration::from_secs(0)
+            },
+            PortAction::ResetSyncTimer {
+                duration: core::time::Duration::from_secs(0)
+            }
+        ]
+    }
+
+    pub fn handle_filter_update_timer(&mut self) -> PortActionIterator {
+        self.port_state.handle_filter_update(&mut self.clock)
+    }
+
+    // Start a BMCA cycle and ensure this happens instantly from the perspective of
+    // the port
+    pub fn start_bmca(self) -> Port<InBmca<'a>, A, R, C, F> {
+        Port {
+            port_state: self.port_state,
+            config: self.config,
+            filter_config: self.filter_config,
+            clock: self.clock,
+            port_identity: self.port_identity,
+            bmca: self.bmca,
+            rng: self.rng,
+            packet_buffer: [0; MAX_DATA_LEN],
+            lifecycle: InBmca {
+                pending_action: actions![],
+                local_best: None,
+                state_refcell: self.lifecycle.state_refcell,
+            },
+        }
+    }
+}
+
+impl<'a, A: AcceptableMasterList, C: Clock, F: Filter, R: Rng> Port<Running<'a>, A, R, C, F> {
+    // Handle a message over the timecritical channel
+    pub fn handle_timecritical_receive(
+        &mut self,
+        data: &[u8],
+        timestamp: Time,
+    ) -> PortActionIterator {
+        let message = match Message::deserialize(data) {
+            Ok(message) => message,
+            Err(error) => {
+                log::warn!("Could not parse packet: {:?}", error);
+                return actions![];
+            }
+        };
+
+        // Only process messages from the same domain
+        if message.header().sdo_id != self.lifecycle.state.default_ds.sdo_id
+            || message.header().domain_number != self.lifecycle.state.default_ds.domain_number
+        {
+            return actions![];
+        }
+
+        if message.is_event() {
+            self.port_state.handle_event_receive(
+                message,
+                timestamp,
+                self.config.min_delay_req_interval(),
+                self.port_identity,
+                &mut self.clock,
+                &mut self.packet_buffer,
+            )
+        } else {
+            self.handle_general_internal(message)
+        }
+    }
+
+    // Handle a general ptp message
+    pub fn handle_general_receive(&mut self, data: &[u8]) -> PortActionIterator {
+        let message = match Message::deserialize(data) {
+            Ok(message) => message,
+            Err(error) => {
+                log::warn!("Could not parse packet: {:?}", error);
+                return actions![];
+            }
+        };
+
+        // Only process messages from the same domain
+        if message.header().sdo_id != self.lifecycle.state.default_ds.sdo_id
+            || message.header().domain_number != self.lifecycle.state.default_ds.domain_number
+        {
+            return actions![];
+        }
+
+        self.handle_general_internal(message)
+    }
+
+    fn handle_general_internal(&mut self, message: Message<'_>) -> PortActionIterator<'_> {
+        match message.body {
+            MessageBody::Announce(announce) => {
+                self.bmca
+                    .register_announce_message(&message.header, &announce);
+                actions![PortAction::ResetAnnounceReceiptTimer {
+                    duration: self.config.announce_duration(&mut self.rng),
+                }]
+            }
+            _ => {
+                self.port_state
+                    .handle_general_receive(message, self.port_identity, &mut self.clock)
+            }
+        }
+    }
+}
+
+impl<'a, A, C, F: Filter, R> Port<InBmca<'a>, A, R, C, F> {
+    // End a BMCA cycle and make the port available again
+    pub fn end_bmca(self) -> (Port<Running<'a>, A, R, C, F>, PortActionIterator<'static>) {
+        (
+            Port {
+                port_state: self.port_state,
+                config: self.config,
+                filter_config: self.filter_config,
+                clock: self.clock,
+                port_identity: self.port_identity,
+                bmca: self.bmca,
+                rng: self.rng,
+                packet_buffer: [0; MAX_DATA_LEN],
+                lifecycle: Running {
+                    state_refcell: self.lifecycle.state_refcell,
+                    state: self.lifecycle.state_refcell.borrow(),
+                },
+            },
+            self.lifecycle.pending_action,
+        )
+    }
+}
+
+impl<L, A, R, C: Clock, F: Filter> Port<L, A, R, C, F> {
+    fn set_forced_port_state(&mut self, mut state: PortState<F>) {
+        log::info!(
+            "new state for port {}: {} -> {}",
+            self.port_identity.port_number,
+            self.port_state,
+            state
+        );
+        core::mem::swap(&mut self.port_state, &mut state);
+        state.demobilize_filter(&mut self.clock);
+    }
+}
+
+impl<L, A, R, C, F: Filter> Port<L, A, R, C, F> {
+    pub fn is_steering(&self) -> bool {
+        matches!(self.port_state, PortState::Slave(_))
+    }
+
+    pub(crate) fn state(&self) -> &PortState<F> {
+        &self.port_state
+    }
+
+    pub(crate) fn number(&self) -> u16 {
+        self.port_identity.port_number
+    }
+}
+
+impl<'a, A: AcceptableMasterList, C: Clock, F: Filter, R: Rng> Port<InBmca<'a>, A, R, C, F> {
+    pub(crate) fn calculate_best_local_announce_message(&mut self) {
+        self.lifecycle.local_best = self.bmca.take_best_port_announce_message()
+    }
+}
+
+impl<'a, A, C: Clock, F: Filter, R: Rng> Port<InBmca<'a>, A, R, C, F> {
+    pub(crate) fn step_announce_age(&mut self, step: Duration) {
+        self.bmca.step_age(step);
+    }
+
+    pub(crate) fn best_local_announce_message(&self) -> Option<BestAnnounceMessage> {
+        // Announce messages received on a masterOnly PTP Port shall not be considered
+        // in the operation of the best master clock algorithm or in the update
+        // of data sets.
+        if self.config.master_only {
+            None
+        } else {
+            self.lifecycle.local_best
+        }
+    }
+
+    pub(crate) fn set_recommended_state(
+        &mut self,
+        recommended_state: RecommendedState,
+        time_properties_ds: &mut TimePropertiesDS,
+        current_ds: &mut CurrentDS,
+        parent_ds: &mut ParentDS,
+        default_ds: &DefaultDS,
+    ) {
+        self.set_recommended_port_state(&recommended_state, default_ds);
+
+        match recommended_state {
+            RecommendedState::M1(defaultds) | RecommendedState::M2(defaultds) => {
+                // a slave-only PTP port should never end up in the master state
+                debug_assert!(!default_ds.slave_only);
+
+                current_ds.steps_removed = 0;
+                current_ds.offset_from_master = Duration::ZERO;
+                current_ds.mean_delay = Duration::ZERO;
+
+                parent_ds.parent_port_identity.clock_identity = defaultds.clock_identity;
+                parent_ds.parent_port_identity.port_number = 0;
+                parent_ds.grandmaster_identity = defaultds.clock_identity;
+                parent_ds.grandmaster_clock_quality = defaultds.clock_quality;
+                parent_ds.grandmaster_priority_1 = defaultds.priority_1;
+                parent_ds.grandmaster_priority_2 = defaultds.priority_2;
+
+                time_properties_ds.leap_indicator = LeapIndicator::NoLeap;
+                time_properties_ds.current_utc_offset = None;
+                time_properties_ds.ptp_timescale = true;
+                time_properties_ds.time_traceable = false;
+                time_properties_ds.frequency_traceable = false;
+                time_properties_ds.time_source = TimeSource::InternalOscillator;
+            }
+            RecommendedState::M3(_) | RecommendedState::P1(_) | RecommendedState::P2(_) => {}
+            RecommendedState::S1(announce_message) => {
+                // a master-only PTP port should never end up in the slave state
+                debug_assert!(!self.config.master_only);
+
+                current_ds.steps_removed = announce_message.steps_removed + 1;
+
+                parent_ds.parent_port_identity = announce_message.header.source_port_identity;
+                parent_ds.grandmaster_identity = announce_message.grandmaster_identity;
+                parent_ds.grandmaster_clock_quality = announce_message.grandmaster_clock_quality;
+                parent_ds.grandmaster_priority_1 = announce_message.grandmaster_priority_1;
+                parent_ds.grandmaster_priority_2 = announce_message.grandmaster_priority_2;
+
+                *time_properties_ds = announce_message.time_properties();
+
+                if let Err(error) = self.clock.set_properties(time_properties_ds) {
+                    log::error!("Could not update clock: {:?}", error);
+                }
+            }
+        }
+
+        // TODO: Discuss if we should change the clock's own time properties, or keep
+        // the master's time properties separately
+        if let RecommendedState::S1(announce_message) = &recommended_state {
+            // Update time properties
+            *time_properties_ds = announce_message.time_properties();
+        }
+    }
+
+    fn set_recommended_port_state(
+        &mut self,
+        recommended_state: &RecommendedState,
+        default_ds: &DefaultDS,
+    ) {
+        match recommended_state {
+            // TODO set things like steps_removed once they are added
+            // TODO make sure states are complete
+            RecommendedState::S1(announce_message) => {
+                // a master-only PTP port should never end up in the slave state
+                debug_assert!(!self.config.master_only);
+
+                let remote_master = announce_message.header.source_port_identity;
+
+                let update_state = match &self.port_state {
+                    PortState::Listening | PortState::Master(_) | PortState::Passive => true,
+                    PortState::Slave(old_state) => old_state.remote_master() != remote_master,
+                };
+
+                if update_state {
+                    let state = PortState::Slave(SlaveState::new(
+                        remote_master,
+                        self.filter_config.clone(),
+                    ));
+                    self.set_forced_port_state(state);
+
+                    let duration = self.config.announce_duration(&mut self.rng);
+                    let reset_announce = PortAction::ResetAnnounceReceiptTimer { duration };
+                    let reset_delay = PortAction::ResetDelayRequestTimer {
+                        duration: core::time::Duration::ZERO,
+                    };
+                    self.lifecycle.pending_action = actions![reset_announce, reset_delay];
+                }
+            }
+            RecommendedState::M1(_) | RecommendedState::M2(_) | RecommendedState::M3(_) => {
+                if default_ds.slave_only {
+                    match self.port_state {
+                        PortState::Listening => { /* do nothing */ }
+                        PortState::Slave(_) | PortState::Passive => {
+                            self.set_forced_port_state(PortState::Listening);
+
+                            // consistent with Port<InBmca>::new()
+                            let duration = self.config.announce_duration(&mut self.rng);
+                            let reset_announce = PortAction::ResetAnnounceReceiptTimer { duration };
+                            self.lifecycle.pending_action = actions![reset_announce];
+                        }
+                        PortState::Master(_) => {
+                            let msg = "slave-only PTP port should not be in master state";
+                            debug_assert!(!default_ds.slave_only, "{msg}");
+                            log::error!("{msg}");
+                        }
+                    }
+                } else {
+                    match self.port_state {
+                        PortState::Listening | PortState::Slave(_) | PortState::Passive => {
+                            self.set_forced_port_state(PortState::Master(MasterState::new()));
+
+                            // Immediately start sending announces and syncs
+                            let duration = core::time::Duration::from_secs(0);
+                            self.lifecycle.pending_action = actions![
+                                PortAction::ResetAnnounceTimer { duration },
+                                PortAction::ResetSyncTimer { duration }
+                            ];
+                        }
+                        PortState::Master(_) => { /* do nothing */ }
+                    }
+                }
+            }
+            RecommendedState::P1(_) | RecommendedState::P2(_) => match self.port_state {
+                PortState::Listening | PortState::Slave(_) | PortState::Master(_) => {
+                    self.set_forced_port_state(PortState::Passive)
+                }
+                PortState::Passive => {}
+            },
+        }
+    }
+}
+
+impl<'a, A, C, F: Filter, R: Rng> Port<InBmca<'a>, A, R, C, F> {
+    /// Create a new port from a port dataset on a given interface.
+    pub(crate) fn new(
+        state_refcell: &'a AtomicRefCell<PtpInstanceState>,
+        config: PortConfig<A>,
+        filter_config: F::Config,
+        clock: C,
+        port_identity: PortIdentity,
+        mut rng: R,
+    ) -> Self {
+        let duration = config.announce_duration(&mut rng);
+        let bmca = Bmca::new(
+            config.acceptable_master_list,
+            config.announce_interval.as_duration().into(),
+            port_identity,
+        );
+
+        Port {
+            config: PortConfig {
+                acceptable_master_list: (),
+                delay_mechanism: config.delay_mechanism,
+                announce_interval: config.announce_interval,
+                announce_receipt_timeout: config.announce_receipt_timeout,
+                sync_interval: config.sync_interval,
+                master_only: config.master_only,
+                delay_asymmetry: config.delay_asymmetry,
+            },
+            filter_config,
+            clock,
+            port_identity,
+            port_state: PortState::Listening,
+            bmca,
+            rng,
+            packet_buffer: [0; MAX_DATA_LEN],
+            lifecycle: InBmca {
+                pending_action: actions![PortAction::ResetAnnounceReceiptTimer { duration }],
+                local_best: None,
+                state_refcell,
+            },
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{
+        datastructures::messages::{AnnounceMessage, Header, PtpVersion},
+        BasicFilter, DelayMechanism, InstanceConfig, Interval,
+    };
+
+    struct TestClock;
+
+    impl Clock for TestClock {
+        type Error = ();
+
+        fn set_frequency(&mut self, _freq: f64) -> Result<Time, Self::Error> {
+            Ok(Time::default())
+        }
+
+        fn now(&self) -> Time {
+            panic!("Shouldn't be called");
+        }
+
+        fn set_properties(
+            &mut self,
+            _time_properties_ds: &crate::TimePropertiesDS,
+        ) -> Result<(), Self::Error> {
+            Ok(())
+        }
+
+        fn step_clock(&mut self, _offset: Duration) -> Result<Time, Self::Error> {
+            Ok(Time::default())
+        }
+    }
+
+    fn default_announce_message_header() -> Header {
+        Header {
+            sdo_id: Default::default(),
+            version: PtpVersion::new(2, 1).unwrap(),
+            domain_number: Default::default(),
+            alternate_master_flag: false,
+            two_step_flag: false,
+            unicast_flag: false,
+            ptp_profile_specific_1: false,
+            ptp_profile_specific_2: false,
+            leap61: false,
+            leap59: false,
+            current_utc_offset_valid: false,
+            ptp_timescale: false,
+            time_tracable: false,
+            frequency_tracable: false,
+            synchronization_uncertain: false,
+            correction_field: Default::default(),
+            source_port_identity: Default::default(),
+            sequence_id: Default::default(),
+            log_message_interval: Default::default(),
+        }
+    }
+
+    fn default_announce_message() -> AnnounceMessage {
+        AnnounceMessage {
+            header: default_announce_message_header(),
+            origin_timestamp: Default::default(),
+            current_utc_offset: Default::default(),
+            grandmaster_priority_1: Default::default(),
+            grandmaster_clock_quality: Default::default(),
+            grandmaster_priority_2: Default::default(),
+            grandmaster_identity: Default::default(),
+            steps_removed: Default::default(),
+            time_source: Default::default(),
+        }
+    }
+
+    #[test]
+    fn test_announce_receive() {
+        let default_ds = DefaultDS::new(InstanceConfig {
+            clock_identity: Default::default(),
+            priority_1: 255,
+            priority_2: 255,
+            domain_number: 0,
+            slave_only: false,
+            sdo_id: Default::default(),
+        });
+
+        let parent_ds = ParentDS::new(default_ds);
+
+        let state = AtomicRefCell::new(PtpInstanceState {
+            default_ds,
+            current_ds: Default::default(),
+            parent_ds,
+            time_properties_ds: Default::default(),
+        });
+
+        let port = Port::<_, _, _, _, BasicFilter>::new(
+            &state,
+            PortConfig {
+                acceptable_master_list: (),
+                delay_mechanism: DelayMechanism::E2E {
+                    interval: Interval::from_log_2(1),
+                },
+                announce_interval: Interval::from_log_2(1),
+                announce_receipt_timeout: 3,
+                sync_interval: Interval::from_log_2(0),
+                master_only: false,
+                delay_asymmetry: Duration::ZERO,
+            },
+            0.25,
+            TestClock,
+            Default::default(),
+            rand::rngs::mock::StepRng::new(2, 1),
+        );
+
+        let (mut port, _) = port.end_bmca();
+
+        let mut announce = default_announce_message();
+        announce.header.source_port_identity.clock_identity.0 = [1, 2, 3, 4, 5, 6, 7, 8];
+        let announce_message = Message {
+            header: announce.header,
+            body: MessageBody::Announce(announce),
+            suffix: Default::default(),
+        };
+        let mut packet = [0; MAX_DATA_LEN];
+        let packet_len = announce_message.serialize(&mut packet).unwrap();
+        let packet = &packet[..packet_len];
+
+        let mut actions = port.handle_general_receive(packet);
+        let Some(PortAction::ResetAnnounceReceiptTimer { .. }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let mut actions = port.handle_general_receive(packet);
+        let Some(PortAction::ResetAnnounceReceiptTimer { .. }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let mut actions = port.handle_general_receive(packet);
+        let Some(PortAction::ResetAnnounceReceiptTimer { .. }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let mut port = port.start_bmca();
+        port.calculate_best_local_announce_message();
+        assert!(port.best_local_announce_message().is_some());
+    }
+
+    #[test]
+    fn test_announce_receive_via_timecritical() {
+        let default_ds = DefaultDS::new(InstanceConfig {
+            clock_identity: Default::default(),
+            priority_1: 255,
+            priority_2: 255,
+            domain_number: 0,
+            slave_only: false,
+            sdo_id: Default::default(),
+        });
+
+        let parent_ds = ParentDS::new(default_ds);
+
+        let state = AtomicRefCell::new(PtpInstanceState {
+            default_ds,
+            current_ds: Default::default(),
+            parent_ds,
+            time_properties_ds: Default::default(),
+        });
+
+        let port = Port::<_, _, _, _, BasicFilter>::new(
+            &state,
+            PortConfig {
+                acceptable_master_list: (),
+                delay_mechanism: DelayMechanism::E2E {
+                    interval: Interval::from_log_2(1),
+                },
+                announce_interval: Interval::from_log_2(1),
+                announce_receipt_timeout: 3,
+                sync_interval: Interval::from_log_2(0),
+                master_only: false,
+                delay_asymmetry: Duration::ZERO,
+            },
+            0.25,
+            TestClock,
+            Default::default(),
+            rand::rngs::mock::StepRng::new(2, 1),
+        );
+
+        let (mut port, _) = port.end_bmca();
+
+        let mut announce = default_announce_message();
+        announce.header.source_port_identity.clock_identity.0 = [1, 2, 3, 4, 5, 6, 7, 8];
+        let announce_message = Message {
+            header: announce.header,
+            body: MessageBody::Announce(announce),
+            suffix: Default::default(),
+        };
+        let mut packet = [0; MAX_DATA_LEN];
+        let packet_len = announce_message.serialize(&mut packet).unwrap();
+        let packet = &packet[..packet_len];
+
+        let mut actions = port.handle_timecritical_receive(packet, Time::from_micros(1));
+        let Some(PortAction::ResetAnnounceReceiptTimer { .. }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let mut actions = port.handle_timecritical_receive(packet, Time::from_micros(2));
+        let Some(PortAction::ResetAnnounceReceiptTimer { .. }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let mut actions = port.handle_timecritical_receive(packet, Time::from_micros(3));
+        let Some(PortAction::ResetAnnounceReceiptTimer { .. }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let mut port = port.start_bmca();
+        port.calculate_best_local_announce_message();
+        assert!(port.best_local_announce_message().is_some());
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/port/sequence_id.rs.html b/docs/src/statime/port/sequence_id.rs.html new file mode 100644 index 000000000..70ed80cc1 --- /dev/null +++ b/docs/src/statime/port/sequence_id.rs.html @@ -0,0 +1,33 @@ +sequence_id.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+
#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub(crate) struct SequenceIdGenerator {
+    current: u16,
+}
+
+impl SequenceIdGenerator {
+    pub(crate) fn new() -> Self {
+        SequenceIdGenerator { current: 0 }
+    }
+
+    pub(crate) fn generate(&mut self) -> u16 {
+        let id = self.current;
+        self.current = self.current.wrapping_add(1);
+        id
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/port/state/master.rs.html b/docs/src/statime/port/state/master.rs.html new file mode 100644 index 000000000..f41de812d --- /dev/null +++ b/docs/src/statime/port/state/master.rs.html @@ -0,0 +1,1099 @@ +master.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+
use core::fmt::Debug;
+
+use crate::{
+    datastructures::{
+        common::PortIdentity,
+        datasets::DefaultDS,
+        messages::{DelayReqMessage, Header, Message, MessageBody},
+    },
+    port::{
+        sequence_id::SequenceIdGenerator, PortAction, PortActionIterator, TimestampContext,
+        TimestampContextInner,
+    },
+    ptp_instance::PtpInstanceState,
+    time::{Interval, Time},
+    PortConfig,
+};
+
+#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub(crate) struct MasterState {
+    pub(in crate::port) announce_seq_ids: SequenceIdGenerator,
+    pub(in crate::port) sync_seq_ids: SequenceIdGenerator,
+}
+
+impl MasterState {
+    pub(crate) fn new() -> Self {
+        MasterState {
+            announce_seq_ids: SequenceIdGenerator::new(),
+            sync_seq_ids: SequenceIdGenerator::new(),
+        }
+    }
+
+    pub(crate) fn handle_timestamp<'a>(
+        &mut self,
+        context: TimestampContext,
+        timestamp: Time,
+        port_identity: PortIdentity,
+        default_ds: &DefaultDS,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        match context.inner {
+            TimestampContextInner::Sync { id } => {
+                self.handle_sync_timestamp(id, timestamp, port_identity, default_ds, buffer)
+            }
+            _ => {
+                log::error!("Unexpected send timestamp");
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn handle_sync_timestamp<'a>(
+        &mut self,
+        id: u16,
+        timestamp: Time,
+        port_identity: PortIdentity,
+        default_ds: &DefaultDS,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        let packet_length =
+            match Message::follow_up(default_ds, port_identity, id, timestamp).serialize(buffer) {
+                Ok(length) => length,
+                Err(error) => {
+                    log::error!(
+                        "Statime bug: Could not serialize sync follow up {:?}",
+                        error
+                    );
+                    return actions![];
+                }
+            };
+
+        actions![PortAction::SendGeneral {
+            data: &buffer[..packet_length],
+        }]
+    }
+
+    pub(crate) fn send_sync<'a>(
+        &mut self,
+        config: &PortConfig<()>,
+        port_identity: PortIdentity,
+        default_ds: &DefaultDS,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        log::trace!("sending sync message");
+
+        let seq_id = self.sync_seq_ids.generate();
+        let packet_length = match Message::sync(default_ds, port_identity, seq_id).serialize(buffer)
+        {
+            Ok(message) => message,
+            Err(error) => {
+                log::error!("Statime bug: Could not serialize sync: {:?}", error);
+                return actions![];
+            }
+        };
+
+        actions![
+            PortAction::ResetSyncTimer {
+                duration: config.sync_interval.as_core_duration(),
+            },
+            PortAction::SendTimeCritical {
+                context: TimestampContext {
+                    inner: TimestampContextInner::Sync { id: seq_id },
+                },
+                data: &buffer[..packet_length],
+            }
+        ]
+    }
+
+    pub(crate) fn send_announce<'a>(
+        &mut self,
+        global: &PtpInstanceState,
+        config: &PortConfig<()>,
+        port_identity: PortIdentity,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        log::trace!("sending announce message");
+
+        let packet_length =
+            match Message::announce(global, port_identity, self.announce_seq_ids.generate())
+                .serialize(buffer)
+            {
+                Ok(length) => length,
+                Err(error) => {
+                    log::error!(
+                        "Statime bug: Could not serialize announce message {:?}",
+                        error
+                    );
+                    return actions![];
+                }
+            };
+
+        actions![
+            PortAction::ResetAnnounceTimer {
+                duration: config.announce_interval.as_core_duration(),
+            },
+            PortAction::SendGeneral {
+                data: &buffer[..packet_length]
+            }
+        ]
+    }
+
+    pub(crate) fn handle_event_receive<'a>(
+        &mut self,
+        message: Message,
+        timestamp: Time,
+        min_delay_req_interval: Interval,
+        port_identity: PortIdentity,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        let header = message.header;
+
+        if header.source_port_identity == port_identity {
+            return actions![];
+        }
+
+        match message.body {
+            MessageBody::DelayReq(message) => self.handle_delay_req(
+                header,
+                message,
+                timestamp,
+                min_delay_req_interval,
+                port_identity,
+                buffer,
+            ),
+            _ => {
+                log::warn!("Unexpected message {:?}", message);
+                actions![]
+            }
+        }
+    }
+
+    fn handle_delay_req<'a>(
+        &mut self,
+        header: Header,
+        message: DelayReqMessage,
+        timestamp: Time,
+        min_delay_req_interval: Interval,
+        port_identity: PortIdentity,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        log::debug!("Received DelayReq");
+        let delay_resp_message = Message::delay_resp(
+            header,
+            message,
+            port_identity,
+            min_delay_req_interval,
+            timestamp,
+        );
+
+        let packet_length = match delay_resp_message.serialize(buffer) {
+            Ok(length) => length,
+            Err(error) => {
+                log::error!("Could not serialize delay response: {:?}", error);
+                return actions![];
+            }
+        };
+
+        actions![PortAction::SendGeneral {
+            data: &buffer[..packet_length],
+        }]
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use fixed::types::{I48F16, U96F32};
+
+    use super::*;
+    use crate::{
+        config::InstanceConfig,
+        datastructures::{
+            common::{ClockIdentity, TimeInterval, TlvSet},
+            datasets::{CurrentDS, ParentDS},
+            messages::{Header, SdoId},
+        },
+        time::Interval,
+        Duration, TimePropertiesDS, MAX_DATA_LEN,
+    };
+
+    #[test]
+    fn test_delay_response() {
+        let mut state = MasterState::new();
+
+        let mut buffer = [0u8; MAX_DATA_LEN];
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header: Header {
+                    sequence_id: 5123,
+                    source_port_identity: PortIdentity {
+                        port_number: 83,
+                        ..Default::default()
+                    },
+                    correction_field: TimeInterval(I48F16::from_bits(400)),
+                    ..Default::default()
+                },
+                body: MessageBody::DelayReq(DelayReqMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_fixed_nanos(U96F32::from_bits((200000 << 32) + (500 << 16))),
+            Interval::from_log_2(2),
+            PortIdentity::default(),
+            &mut buffer,
+        );
+
+        let Some(PortAction::SendGeneral { data }) = action.next() else {
+            panic!("Unexpected resulting action");
+        };
+        assert!(action.next().is_none());
+        drop(action);
+
+        let msg = Message::deserialize(data).unwrap();
+        let msg_header = msg.header;
+
+        let msg = match msg.body {
+            MessageBody::DelayResp(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        assert_eq!(
+            msg.requesting_port_identity,
+            PortIdentity {
+                port_number: 83,
+                ..Default::default()
+            }
+        );
+        assert_eq!(msg_header.sequence_id, 5123);
+        assert_eq!(msg.receive_timestamp, Time::from_micros(200).into());
+        assert_eq!(msg_header.log_message_interval, 2);
+        assert_eq!(
+            msg_header.correction_field,
+            TimeInterval(I48F16::from_bits(900))
+        );
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header: Header {
+                    sequence_id: 879,
+                    source_port_identity: PortIdentity {
+                        port_number: 12,
+                        ..Default::default()
+                    },
+                    correction_field: TimeInterval(I48F16::from_bits(200)),
+                    ..Default::default()
+                },
+                body: MessageBody::DelayReq(DelayReqMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_fixed_nanos(U96F32::from_bits((220000 << 32) + (300 << 16))),
+            Interval::from_log_2(5),
+            PortIdentity::default(),
+            &mut buffer,
+        );
+
+        let Some(PortAction::SendGeneral { data }) = action.next() else {
+            panic!("Unexpected resulting action");
+        };
+        assert!(action.next().is_none());
+
+        let msg = Message::deserialize(data).unwrap();
+        let msg_header = msg.header;
+
+        let msg = match msg.body {
+            MessageBody::DelayResp(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        assert_eq!(
+            msg.requesting_port_identity,
+            PortIdentity {
+                port_number: 12,
+                ..Default::default()
+            }
+        );
+        assert_eq!(msg_header.sequence_id, 879);
+        assert_eq!(msg.receive_timestamp, Time::from_micros(220).into());
+        assert_eq!(msg_header.log_message_interval, 5);
+        assert_eq!(
+            msg_header.correction_field,
+            TimeInterval(I48F16::from_bits(500))
+        );
+    }
+
+    #[test]
+    fn test_announce() {
+        let mut buffer = [0u8; MAX_DATA_LEN];
+
+        let default_ds = DefaultDS::new(InstanceConfig {
+            clock_identity: ClockIdentity::default(),
+            priority_1: 15,
+            priority_2: 128,
+            domain_number: 0,
+            slave_only: false,
+            sdo_id: SdoId::default(),
+        });
+        let mut parent_ds = ParentDS::new(default_ds);
+        parent_ds.grandmaster_priority_1 = 15;
+        let current_ds = CurrentDS::default();
+        let time_properties_ds = TimePropertiesDS::default();
+        let global = PtpInstanceState {
+            default_ds,
+            current_ds,
+            parent_ds,
+            time_properties_ds,
+        };
+
+        let config = PortConfig {
+            acceptable_master_list: (),
+            delay_mechanism: crate::DelayMechanism::E2E {
+                interval: Interval::TWO_SECONDS,
+            },
+            announce_interval: Interval::TWO_SECONDS,
+            announce_receipt_timeout: 2,
+            sync_interval: Interval::ONE_SECOND,
+            master_only: false,
+            delay_asymmetry: Duration::ZERO,
+        };
+        let mut state = MasterState::new();
+
+        let mut actions =
+            state.send_announce(&global, &config, PortIdentity::default(), &mut buffer);
+
+        assert!(matches!(
+            actions.next(),
+            Some(PortAction::ResetAnnounceTimer { .. })
+        ));
+        let Some(PortAction::SendGeneral { data }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let msg = Message::deserialize(data).unwrap();
+        let msg_header = msg.header;
+
+        let msg = match msg.body {
+            MessageBody::Announce(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        assert_eq!(msg.grandmaster_priority_1, 15);
+
+        let mut actions =
+            state.send_announce(&global, &config, PortIdentity::default(), &mut buffer);
+
+        assert!(matches!(
+            actions.next(),
+            Some(PortAction::ResetAnnounceTimer { .. })
+        ));
+        let Some(PortAction::SendGeneral { data }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+
+        let msg2 = Message::deserialize(data).unwrap();
+        let msg2_header = msg2.header;
+
+        let msg2 = match msg2.body {
+            MessageBody::Announce(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        assert_eq!(msg2.grandmaster_priority_1, 15);
+        assert_ne!(msg2_header.sequence_id, msg_header.sequence_id);
+    }
+
+    #[test]
+    fn test_sync() {
+        let mut buffer = [0u8; MAX_DATA_LEN];
+        let config = PortConfig {
+            acceptable_master_list: (),
+            delay_mechanism: crate::DelayMechanism::E2E {
+                interval: Interval::TWO_SECONDS,
+            },
+            announce_interval: Interval::TWO_SECONDS,
+            announce_receipt_timeout: 2,
+            sync_interval: Interval::ONE_SECOND,
+            master_only: false,
+            delay_asymmetry: crate::Duration::ZERO,
+        };
+
+        let mut state = MasterState::new();
+        let defaultds = DefaultDS::new(InstanceConfig {
+            clock_identity: ClockIdentity::default(),
+            priority_1: 15,
+            priority_2: 128,
+            domain_number: 0,
+            slave_only: false,
+            sdo_id: SdoId::default(),
+        });
+
+        let mut actions =
+            state.send_sync(&config, PortIdentity::default(), &defaultds, &mut buffer);
+
+        assert!(matches!(
+            actions.next(),
+            Some(PortAction::ResetSyncTimer { .. })
+        ));
+        let Some(PortAction::SendTimeCritical { context, data }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let sync = Message::deserialize(data).unwrap();
+        let sync_header = sync.header;
+
+        let _sync = match sync.body {
+            MessageBody::Sync(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        let mut actions = state.handle_timestamp(
+            context,
+            Time::from_fixed_nanos(U96F32::from_bits((601300 << 32) + (230 << 16))),
+            PortIdentity::default(),
+            &defaultds,
+            &mut buffer,
+        );
+
+        let Some(PortAction::SendGeneral { data }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let follow = Message::deserialize(data).unwrap();
+        let follow_header = follow.header;
+
+        let follow = match follow.body {
+            MessageBody::FollowUp(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        assert_eq!(sync_header.sequence_id, follow_header.sequence_id);
+        assert_eq!(
+            sync_header.correction_field,
+            TimeInterval(I48F16::from_bits(0))
+        );
+        assert_eq!(
+            follow.precise_origin_timestamp,
+            Time::from_fixed_nanos(601300).into()
+        );
+        assert_eq!(
+            follow_header.correction_field,
+            TimeInterval(I48F16::from_bits(230))
+        );
+
+        let mut actions =
+            state.send_sync(&config, PortIdentity::default(), &defaultds, &mut buffer);
+
+        assert!(matches!(
+            actions.next(),
+            Some(PortAction::ResetSyncTimer { .. })
+        ));
+        let Some(PortAction::SendTimeCritical { context, data }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+        drop(actions);
+
+        let sync2 = Message::deserialize(data).unwrap();
+        let sync2_header = sync2.header;
+
+        let _sync2 = match sync2.body {
+            MessageBody::Sync(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        let mut actions = state.handle_timestamp(
+            context,
+            Time::from_fixed_nanos(U96F32::from_bits((1000601300 << 32) + (543 << 16))),
+            PortIdentity::default(),
+            &defaultds,
+            &mut buffer,
+        );
+
+        let Some(PortAction::SendGeneral { data }) = actions.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(actions.next().is_none());
+
+        let follow2 = Message::deserialize(data).unwrap();
+        let follow2_header = follow2.header;
+
+        let follow2 = match follow2.body {
+            MessageBody::FollowUp(msg) => msg,
+            _ => panic!("Unexpected message type"),
+        };
+
+        assert_ne!(sync_header.sequence_id, sync2_header.sequence_id);
+        assert_eq!(sync2_header.sequence_id, follow2_header.sequence_id);
+        assert_eq!(
+            sync2_header.correction_field,
+            TimeInterval(I48F16::from_bits(0))
+        );
+        assert_eq!(
+            follow2.precise_origin_timestamp,
+            Time::from_fixed_nanos(1000601300).into()
+        );
+        assert_eq!(
+            follow2_header.correction_field,
+            TimeInterval(I48F16::from_bits(543))
+        );
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/port/state/mod.rs.html b/docs/src/statime/port/state/mod.rs.html new file mode 100644 index 000000000..3228c3289 --- /dev/null +++ b/docs/src/statime/port/state/mod.rs.html @@ -0,0 +1,335 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+
use core::fmt::{Display, Formatter};
+
+use rand::Rng;
+
+use super::{PortActionIterator, TimestampContext};
+use crate::{
+    datastructures::{common::PortIdentity, datasets::DefaultDS, messages::Message},
+    ptp_instance::PtpInstanceState,
+    time::{Interval, Time},
+    Clock, Filter, PortConfig,
+};
+
+mod master;
+mod slave;
+
+pub(crate) use master::MasterState;
+pub(crate) use slave::SlaveState;
+
+#[derive(Debug, Default)]
+pub(crate) enum PortState<F> {
+    #[default]
+    Listening,
+    Master(MasterState),
+    Passive,
+    Slave(SlaveState<F>),
+}
+
+impl<F: Filter> PortState<F> {
+    pub(crate) fn handle_timestamp<'a, C: Clock>(
+        &mut self,
+        context: TimestampContext,
+        timestamp: Time,
+        port_identity: PortIdentity,
+        default_ds: &DefaultDS,
+        clock: &mut C,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        match self {
+            PortState::Slave(slave) => slave.handle_timestamp(context, timestamp, clock),
+            PortState::Master(master) => {
+                master.handle_timestamp(context, timestamp, port_identity, default_ds, buffer)
+            }
+            PortState::Listening | PortState::Passive => actions![],
+        }
+    }
+
+    pub(crate) fn handle_event_receive<'a, C: Clock>(
+        &mut self,
+        message: Message,
+        timestamp: Time,
+        min_delay_req_interval: Interval,
+        port_identity: PortIdentity,
+        clock: &mut C,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        match self {
+            PortState::Master(master) => master.handle_event_receive(
+                message,
+                timestamp,
+                min_delay_req_interval,
+                port_identity,
+                buffer,
+            ),
+            PortState::Slave(slave) => slave.handle_event_receive(message, timestamp, clock),
+            PortState::Listening | PortState::Passive => actions![],
+        }
+    }
+
+    pub(crate) fn handle_general_receive<C: Clock>(
+        &mut self,
+        message: Message,
+        port_identity: PortIdentity,
+        clock: &mut C,
+    ) -> PortActionIterator {
+        match self {
+            PortState::Master(_) => {
+                if message.header().source_port_identity != port_identity {
+                    log::warn!("Unexpected message {:?}", message);
+                }
+                actions![]
+            }
+            PortState::Slave(slave) => slave.handle_general_receive(message, port_identity, clock),
+            PortState::Listening | PortState::Passive => {
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn handle_filter_update<C: Clock>(&mut self, clock: &mut C) -> PortActionIterator {
+        match self {
+            PortState::Slave(slave) => slave.handle_filter_update(clock),
+            PortState::Master(_) | PortState::Listening | PortState::Passive => {
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn demobilize_filter<C: Clock>(self, clock: &mut C) {
+        match self {
+            PortState::Slave(slave) => slave.demobilize_filter(clock),
+            PortState::Master(_) | PortState::Listening | PortState::Passive => {}
+        }
+    }
+}
+
+impl<F> PortState<F> {
+    pub(crate) fn send_sync<'a>(
+        &mut self,
+        config: &PortConfig<()>,
+        port_identity: PortIdentity,
+        default_ds: &DefaultDS,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        match self {
+            PortState::Master(master) => {
+                master.send_sync(config, port_identity, default_ds, buffer)
+            }
+            PortState::Slave(_) | PortState::Listening | PortState::Passive => {
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn send_delay_request<'a>(
+        &mut self,
+        rng: &mut impl Rng,
+        port_config: &PortConfig<()>,
+        port_identity: PortIdentity,
+        default_ds: &DefaultDS,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        match self {
+            PortState::Slave(slave) => {
+                slave.send_delay_request(rng, port_config, port_identity, default_ds, buffer)
+            }
+            PortState::Master(_) | PortState::Listening | PortState::Passive => {
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn send_announce<'a>(
+        &mut self,
+        global: &PtpInstanceState,
+        config: &PortConfig<()>,
+        port_identity: PortIdentity,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        match self {
+            PortState::Master(master) => {
+                master.send_announce(global, config, port_identity, buffer)
+            }
+            PortState::Slave(_) | PortState::Listening | PortState::Passive => actions![],
+        }
+    }
+}
+
+impl<F> Display for PortState<F> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        match self {
+            PortState::Listening => write!(f, "Listening"),
+            PortState::Master(_) => write!(f, "Master"),
+            PortState::Passive => write!(f, "Passive"),
+            PortState::Slave(_) => write!(f, "Slave"),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/port/state/slave.rs.html b/docs/src/statime/port/state/slave.rs.html new file mode 100644 index 000000000..7e021758d --- /dev/null +++ b/docs/src/statime/port/state/slave.rs.html @@ -0,0 +1,2403 @@ +slave.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+
use rand::Rng;
+
+use crate::{
+    datastructures::{
+        common::PortIdentity,
+        datasets::DefaultDS,
+        messages::{DelayRespMessage, FollowUpMessage, Header, Message, MessageBody, SyncMessage},
+    },
+    port::{
+        sequence_id::SequenceIdGenerator, Measurement, PortAction, PortActionIterator,
+        TimestampContext, TimestampContextInner,
+    },
+    time::{Duration, Time},
+    Clock, DelayMechanism, Filter, PortConfig,
+};
+
+#[derive(Debug)]
+pub(crate) struct SlaveState<F> {
+    remote_master: PortIdentity,
+
+    sync_state: SyncState,
+    delay_state: DelayState,
+
+    mean_delay: Option<Duration>,
+    last_raw_sync_offset: Option<Duration>,
+
+    delay_req_ids: SequenceIdGenerator,
+
+    filter: F,
+}
+
+impl<F> SlaveState<F> {
+    pub(crate) fn remote_master(&self) -> PortIdentity {
+        self.remote_master
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum SyncState {
+    Empty,
+    Measuring {
+        id: u16,
+        send_time: Option<Time>,
+        recv_time: Option<Time>,
+    },
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum DelayState {
+    Empty,
+    Measuring {
+        id: u16,
+        send_time: Option<Time>,
+        recv_time: Option<Time>,
+    },
+}
+
+impl<F: Filter> SlaveState<F> {
+    pub(crate) fn new(remote_master: PortIdentity, filter_config: F::Config) -> Self {
+        SlaveState {
+            remote_master,
+            sync_state: SyncState::Empty,
+            delay_state: DelayState::Empty,
+            mean_delay: None,
+            last_raw_sync_offset: None,
+            delay_req_ids: SequenceIdGenerator::new(),
+            filter: F::new(filter_config),
+        }
+    }
+
+    fn handle_time_measurement<'a, C: Clock>(&mut self, clock: &mut C) -> PortActionIterator<'a> {
+        if let Some(measurement) = self.extract_measurement() {
+            // If the received message allowed the (slave) state to calculate its offset
+            // from the master, update the local clock
+            let filter_updates = self.filter.measurement(measurement, clock);
+            if let Some(mean_delay) = filter_updates.mean_delay {
+                self.mean_delay = Some(mean_delay);
+            }
+            PortActionIterator::from_filter(filter_updates)
+        } else {
+            actions![]
+        }
+    }
+
+    pub(crate) fn handle_timestamp<'a, C: Clock>(
+        &mut self,
+        context: TimestampContext,
+        timestamp: Time,
+        clock: &mut C,
+    ) -> PortActionIterator<'a> {
+        match context.inner {
+            crate::port::TimestampContextInner::DelayReq { id } => {
+                // handle our send timestamp on a delay request message
+                self.handle_delay_timestamp(id, timestamp, clock)
+            }
+            _ => {
+                log::error!("Unexpected timestamp");
+                actions![]
+            }
+        }
+    }
+
+    fn handle_delay_timestamp<'a, C: Clock>(
+        &mut self,
+        timestamp_id: u16,
+        timestamp: Time,
+        clock: &mut C,
+    ) -> PortActionIterator<'a> {
+        match self.delay_state {
+            DelayState::Measuring {
+                id,
+                send_time: Some(_),
+                ..
+            } if id == timestamp_id => {
+                log::error!("Double send timestamp for delay request");
+                actions![]
+            }
+            DelayState::Measuring {
+                id,
+                ref mut send_time,
+                ..
+            } if id == timestamp_id => {
+                *send_time = Some(timestamp);
+                self.handle_time_measurement(clock)
+            }
+            _ => {
+                log::warn!("Late timestamp for delay request ignored");
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn handle_event_receive<'a, C: Clock>(
+        &mut self,
+        message: Message,
+        timestamp: Time,
+        clock: &mut C,
+    ) -> PortActionIterator<'a> {
+        // Ignore everything not from master
+        let header = &message.header;
+
+        if header.source_port_identity != self.remote_master {
+            return actions![];
+        }
+
+        match message.body {
+            MessageBody::Sync(sync) => self.handle_sync(header, sync, timestamp, clock),
+            _ => {
+                log::warn!("Unexpected message {:?}", message);
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn handle_general_receive<C: Clock>(
+        &mut self,
+        message: Message,
+        port_identity: PortIdentity,
+        clock: &mut C,
+    ) -> PortActionIterator {
+        let header = &message.header;
+
+        // Ignore everything not from master
+        if header.source_port_identity != self.remote_master {
+            return actions![];
+        }
+
+        match message.body {
+            MessageBody::FollowUp(message) => self.handle_follow_up(header, message, clock),
+            MessageBody::DelayResp(message) => {
+                self.handle_delay_resp(header, message, port_identity, clock)
+            }
+            _ => {
+                log::warn!("Unexpected message {:?}", message);
+                actions![]
+            }
+        }
+    }
+
+    pub(crate) fn handle_filter_update<'a, C: Clock>(
+        &mut self,
+        clock: &mut C,
+    ) -> PortActionIterator<'a> {
+        PortActionIterator::from_filter(self.filter.update(clock))
+    }
+
+    pub(crate) fn demobilize_filter<C: Clock>(self, clock: &mut C) {
+        self.filter.demobilize(clock);
+    }
+
+    fn handle_sync<'a, C: Clock>(
+        &mut self,
+        header: &Header,
+        message: SyncMessage,
+        recv_time: Time,
+        clock: &mut C,
+    ) -> PortActionIterator<'a> {
+        log::debug!("Received sync {:?}", header.sequence_id);
+
+        // substracting correction from recv time is equivalent to adding it to send
+        // time
+        let corrected_recv_time = recv_time - Duration::from(header.correction_field);
+
+        if header.two_step_flag {
+            match self.sync_state {
+                SyncState::Measuring {
+                    id,
+                    recv_time: Some(_),
+                    ..
+                } if id == header.sequence_id => {
+                    log::warn!("Duplicate sync message");
+                    // Ignore the sync message
+                    actions![]
+                }
+                SyncState::Measuring {
+                    id,
+                    ref mut recv_time,
+                    ..
+                } if id == header.sequence_id => {
+                    *recv_time = Some(corrected_recv_time);
+                    self.handle_time_measurement(clock)
+                }
+                _ => {
+                    self.sync_state = SyncState::Measuring {
+                        id: header.sequence_id,
+                        send_time: None,
+                        recv_time: Some(corrected_recv_time),
+                    };
+                    actions![]
+                }
+            }
+        } else {
+            match self.sync_state {
+                SyncState::Measuring { id, .. } if id == header.sequence_id => {
+                    log::warn!("Duplicate sync message");
+                    // Ignore the sync message
+                    actions![]
+                }
+                _ => {
+                    self.sync_state = SyncState::Measuring {
+                        id: header.sequence_id,
+                        send_time: Some(Time::from(message.origin_timestamp)),
+                        recv_time: Some(corrected_recv_time),
+                    };
+                    self.handle_time_measurement(clock)
+                }
+            }
+        }
+    }
+
+    fn handle_follow_up<C: Clock>(
+        &mut self,
+        header: &Header,
+        message: FollowUpMessage,
+        clock: &mut C,
+    ) -> PortActionIterator {
+        log::debug!("Received FollowUp {:?}", header.sequence_id);
+
+        let packet_send_time =
+            Time::from(message.precise_origin_timestamp) + Duration::from(header.correction_field);
+
+        match self.sync_state {
+            SyncState::Measuring {
+                id,
+                send_time: Some(_),
+                ..
+            } if id == header.sequence_id => {
+                log::warn!("Duplicate FollowUp message");
+                // Ignore the followup
+                actions![]
+            }
+            SyncState::Measuring {
+                id,
+                ref mut send_time,
+                ..
+            } if id == header.sequence_id => {
+                *send_time = Some(packet_send_time);
+                self.handle_time_measurement(clock)
+            }
+            _ => {
+                self.sync_state = SyncState::Measuring {
+                    id: header.sequence_id,
+                    send_time: Some(packet_send_time),
+                    recv_time: None,
+                };
+                self.handle_time_measurement(clock)
+            }
+        }
+    }
+
+    fn handle_delay_resp<C: Clock>(
+        &mut self,
+        header: &Header,
+        message: DelayRespMessage,
+        port_identity: PortIdentity,
+        clock: &mut C,
+    ) -> PortActionIterator {
+        log::debug!("Received DelayResp");
+        if port_identity != message.requesting_port_identity {
+            return actions![];
+        }
+
+        match self.delay_state {
+            DelayState::Measuring {
+                id,
+                recv_time: Some(_),
+                ..
+            } if id == header.sequence_id => {
+                log::warn!("Duplicate DelayResp message");
+                // Ignore the Delay response
+                actions![]
+            }
+            DelayState::Measuring {
+                id,
+                ref mut recv_time,
+                ..
+            } if id == header.sequence_id => {
+                *recv_time = Some(
+                    Time::from(message.receive_timestamp) - Duration::from(header.correction_field),
+                );
+                self.handle_time_measurement(clock)
+            }
+            _ => {
+                log::warn!("Unexpected DelayResp message");
+                // Ignore the Delay response
+                actions![]
+            }
+        }
+    }
+}
+
+impl<F> SlaveState<F> {
+    pub(crate) fn send_delay_request<'a>(
+        &mut self,
+        rng: &mut impl Rng,
+        port_config: &PortConfig<()>,
+        port_identity: PortIdentity,
+        default_ds: &DefaultDS,
+        buffer: &'a mut [u8],
+    ) -> PortActionIterator<'a> {
+        log::debug!("Starting new delay measurement");
+
+        let delay_id = self.delay_req_ids.generate();
+        let delay_req = Message::delay_req(default_ds, port_identity, delay_id);
+
+        let message_length = match delay_req.serialize(buffer) {
+            Ok(length) => length,
+            Err(error) => {
+                log::error!("Could not serialize delay request: {:?}", error);
+                return actions![];
+            }
+        };
+
+        self.delay_state = DelayState::Measuring {
+            id: delay_id,
+            send_time: None,
+            recv_time: None,
+        };
+
+        let random = rng.sample::<f64, _>(rand::distributions::Open01);
+        let log_min_delay_req_interval = match port_config.delay_mechanism {
+            // the interval corresponds to the PortDS logMinDelayReqInterval
+            DelayMechanism::E2E { interval } => interval,
+        };
+        let factor = random * 2.0f64;
+        let duration = log_min_delay_req_interval
+            .as_core_duration()
+            .mul_f64(factor);
+
+        actions![
+            PortAction::ResetDelayRequestTimer { duration },
+            PortAction::SendTimeCritical {
+                context: TimestampContext {
+                    inner: TimestampContextInner::DelayReq { id: delay_id },
+                },
+                data: &buffer[..message_length],
+            }
+        ]
+    }
+
+    fn extract_measurement(&mut self) -> Option<Measurement> {
+        let mut result = Measurement::default();
+
+        if let SyncState::Measuring {
+            send_time: Some(send_time),
+            recv_time: Some(recv_time),
+            ..
+        } = self.sync_state
+        {
+            let raw_sync_offset = recv_time - send_time;
+            result.event_time = recv_time;
+            result.raw_sync_offset = Some(raw_sync_offset);
+
+            if let Some(mean_delay) = self.mean_delay {
+                result.offset = Some(raw_sync_offset - mean_delay);
+            }
+
+            self.last_raw_sync_offset = Some(raw_sync_offset);
+            self.sync_state = SyncState::Empty;
+        } else if let DelayState::Measuring {
+            send_time: Some(send_time),
+            recv_time: Some(recv_time),
+            ..
+        } = self.delay_state
+        {
+            let raw_delay_offset = send_time - recv_time;
+            result.event_time = send_time;
+            result.raw_delay_offset = Some(raw_delay_offset);
+
+            if let Some(raw_sync_offset) = self.last_raw_sync_offset {
+                result.delay = Some((raw_sync_offset - raw_delay_offset) / 2);
+            }
+
+            self.delay_state = DelayState::Empty;
+        } else {
+            // No measurement
+            return None;
+        }
+
+        log::info!("Measurement: {:?}", result);
+
+        Some(result)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{
+        config::InstanceConfig,
+        datastructures::{
+            common::{ClockIdentity, TimeInterval, TlvSet},
+            messages::{Header, SdoId},
+        },
+        filters::FilterUpdate,
+        Interval, MAX_DATA_LEN,
+    };
+
+    struct TestFilter {
+        last_measurement: Option<Measurement>,
+    }
+
+    impl Filter for TestFilter {
+        type Config = ();
+
+        fn new(_config: Self::Config) -> Self {
+            Self {
+                last_measurement: None,
+            }
+        }
+
+        fn measurement<C: Clock>(&mut self, m: Measurement, _clock: &mut C) -> FilterUpdate {
+            self.last_measurement = Some(m);
+            if let Some(delay) = m.delay {
+                FilterUpdate {
+                    next_update: None,
+                    mean_delay: Some(delay),
+                }
+            } else {
+                Default::default()
+            }
+        }
+
+        fn demobilize<C: Clock>(self, _clock: &mut C) {
+            Default::default()
+        }
+
+        fn update<C: Clock>(&mut self, _clock: &mut C) -> FilterUpdate {
+            Default::default()
+        }
+    }
+
+    struct TestClock;
+
+    impl Clock for TestClock {
+        type Error = ();
+
+        fn set_frequency(&mut self, _freq: f64) -> Result<Time, Self::Error> {
+            Ok(Time::default())
+        }
+
+        fn now(&self) -> Time {
+            panic!("Shouldn't be called");
+        }
+
+        fn set_properties(
+            &mut self,
+            _time_properties_ds: &crate::TimePropertiesDS,
+        ) -> Result<(), Self::Error> {
+            Ok(())
+        }
+
+        fn step_clock(&mut self, _offset: Duration) -> Result<Time, Self::Error> {
+            Ok(Time::default())
+        }
+    }
+
+    #[test]
+    fn test_sync_without_delay_msg() {
+        let mut state = SlaveState::<TestFilter>::new(Default::default(), ());
+        state.mean_delay = Some(Duration::from_micros(100));
+
+        let header = Header {
+            two_step_flag: false,
+            correction_field: TimeInterval(1000.into()),
+            ..Default::default()
+        };
+
+        let body = MessageBody::Sync(SyncMessage {
+            origin_timestamp: Time::from_micros(0).into(),
+        });
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header,
+                body,
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(50),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(49),
+                offset: Some(Duration::from_micros(-51)),
+                delay: None,
+                raw_sync_offset: Some(Duration::from_micros(49)),
+                raw_delay_offset: None,
+            })
+        );
+
+        let header = Header {
+            two_step_flag: true,
+            sequence_id: 15,
+            correction_field: TimeInterval(1000.into()),
+            ..Default::default()
+        };
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header,
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(1050),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let header = Header {
+            sequence_id: 15,
+            correction_field: TimeInterval(2000.into()),
+            ..Default::default()
+        };
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header,
+                body: MessageBody::FollowUp(FollowUpMessage {
+                    precise_origin_timestamp: Time::from_micros(1000).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(1049),
+                offset: Some(Duration::from_micros(-53)),
+                delay: None,
+                raw_sync_offset: Some(Duration::from_micros(47)),
+                raw_delay_offset: None,
+            })
+        );
+    }
+
+    #[test]
+    fn test_sync_with_delay() {
+        let mut state = SlaveState::<TestFilter>::new(Default::default(), ());
+
+        let mut buffer = [0u8; MAX_DATA_LEN];
+        let default_ds = DefaultDS::new(InstanceConfig {
+            clock_identity: ClockIdentity::default(),
+            priority_1: 15,
+            priority_2: 128,
+            domain_number: 0,
+            slave_only: false,
+            sdo_id: SdoId::default(),
+        });
+
+        // mock rng and port config
+        let mut rng = rand::rngs::mock::StepRng::new(2, 1);
+        let port_identity = Default::default();
+        let port_config = PortConfig {
+            acceptable_master_list: (),
+            delay_mechanism: DelayMechanism::E2E {
+                interval: Interval::ONE_SECOND,
+            },
+            announce_interval: Interval::ONE_SECOND,
+            announce_receipt_timeout: Default::default(),
+            sync_interval: Interval::ONE_SECOND,
+            master_only: Default::default(),
+            delay_asymmetry: Default::default(),
+        };
+
+        let header = Header {
+            two_step_flag: false,
+            correction_field: TimeInterval(1000.into()),
+            ..Default::default()
+        };
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header,
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(50),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(49),
+                offset: None,
+                delay: None,
+                raw_sync_offset: Some(Duration::from_micros(49)),
+                raw_delay_offset: None,
+            })
+        );
+
+        let mut action = state.send_delay_request(
+            &mut rng,
+            &port_config,
+            port_identity,
+            &default_ds,
+            &mut buffer,
+        );
+
+        let Some(PortAction::ResetDelayRequestTimer { .. }) = action.next() else {
+            panic!("Unexpected action");
+        };
+
+        let Some(PortAction::SendTimeCritical { context, data }) = action.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(action.next().is_none());
+        drop(action);
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let req = Message::deserialize(data).unwrap();
+        let req_header = req.header;
+
+        let _req = match req.body {
+            MessageBody::DelayReq(msg) => msg,
+            _ => panic!("Incorrect message type"),
+        };
+
+        let mut action = state.handle_timestamp(context, Time::from_micros(100), &mut TestClock);
+        assert!(action.next().is_none());
+        drop(action);
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let header = Header {
+            correction_field: TimeInterval(2000.into()),
+            sequence_id: req_header.sequence_id,
+            ..Default::default()
+        };
+
+        let body = MessageBody::DelayResp(DelayRespMessage {
+            receive_timestamp: Time::from_micros(253).into(),
+            requesting_port_identity: req_header.source_port_identity,
+        });
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header,
+                body,
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.mean_delay, Some(Duration::from_micros(100)));
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(100),
+                offset: None,
+                delay: Some(Duration::from_micros(100)),
+                raw_sync_offset: None,
+                raw_delay_offset: Some(Duration::from_micros(-151)),
+            })
+        );
+
+        state.mean_delay = None;
+
+        let header = Header {
+            two_step_flag: true,
+            correction_field: TimeInterval(1000.into()),
+            ..Default::default()
+        };
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header,
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(1050),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.send_delay_request(
+            &mut rng,
+            &port_config,
+            port_identity,
+            &default_ds,
+            &mut buffer,
+        );
+
+        let Some(PortAction::ResetDelayRequestTimer { .. }) = action.next() else {
+            panic!("Unexpected action");
+        };
+
+        let Some(PortAction::SendTimeCritical { context, data }) = action.next() else {
+            panic!("Unexpected action");
+        };
+        assert!(action.next().is_none());
+        drop(action);
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let req = Message::deserialize(data).unwrap();
+        let req_header = req.header;
+
+        let _req = match req.body {
+            MessageBody::DelayReq(msg) => msg,
+            _ => panic!("Incorrect message type"),
+        };
+
+        let mut action = state.handle_timestamp(context, Time::from_micros(1100), &mut TestClock);
+        assert!(action.next().is_none());
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    correction_field: TimeInterval(2000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::FollowUp(FollowUpMessage {
+                    precise_origin_timestamp: Time::from_micros(1000).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(1049),
+                offset: None,
+                delay: None,
+                raw_sync_offset: Some(Duration::from_micros(47)),
+                raw_delay_offset: None,
+            })
+        );
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    correction_field: TimeInterval(2000.into()),
+                    sequence_id: req_header.sequence_id,
+                    ..Default::default()
+                },
+                body: MessageBody::DelayResp(DelayRespMessage {
+                    receive_timestamp: Time::from_micros(1255).into(),
+                    requesting_port_identity: req_header.source_port_identity,
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.mean_delay, Some(Duration::from_micros(100)));
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(1100),
+                offset: None,
+                delay: Some(Duration::from_micros(100)),
+                raw_sync_offset: None,
+                raw_delay_offset: Some(Duration::from_micros(-153)),
+            })
+        );
+    }
+
+    #[test]
+    fn test_follow_up_before_sync() {
+        let mut state = SlaveState::<TestFilter>::new(Default::default(), ());
+        state.mean_delay = Some(Duration::from_micros(100));
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    sequence_id: 15,
+                    correction_field: TimeInterval(2000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::FollowUp(FollowUpMessage {
+                    precise_origin_timestamp: Time::from_micros(10).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header: Header {
+                    two_step_flag: true,
+                    sequence_id: 15,
+                    correction_field: TimeInterval(1000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(50),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(49),
+                offset: Some(Duration::from_micros(-63)),
+                delay: None,
+                raw_sync_offset: Some(Duration::from_micros(37)),
+                raw_delay_offset: None,
+            })
+        );
+    }
+
+    #[test]
+    fn test_old_followup_during() {
+        let mut state = SlaveState::<TestFilter>::new(Default::default(), ());
+        state.mean_delay = Some(Duration::from_micros(100));
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header: Header {
+                    two_step_flag: true,
+                    sequence_id: 15,
+                    correction_field: TimeInterval(1000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(50),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    sequence_id: 14,
+                    correction_field: TimeInterval(2000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::FollowUp(FollowUpMessage {
+                    precise_origin_timestamp: Time::from_micros(10).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    sequence_id: 15,
+                    correction_field: TimeInterval(2000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::FollowUp(FollowUpMessage {
+                    precise_origin_timestamp: Time::from_micros(10).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.filter.last_measurement.take(), None);
+    }
+
+    #[test]
+    fn test_reset_after_missing_followup() {
+        let mut state = SlaveState::<TestFilter>::new(Default::default(), ());
+        state.mean_delay = Some(Duration::from_micros(100));
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header: Header {
+                    two_step_flag: true,
+                    sequence_id: 14,
+                    correction_field: TimeInterval(1000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(50),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header: Header {
+                    two_step_flag: true,
+                    sequence_id: 15,
+                    correction_field: TimeInterval(1000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(1050),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    sequence_id: 15,
+                    correction_field: TimeInterval(2000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::FollowUp(FollowUpMessage {
+                    precise_origin_timestamp: Time::from_micros(1000).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(1049),
+                offset: Some(Duration::from_micros(-53)),
+                delay: None,
+                raw_sync_offset: Some(Duration::from_micros(47)),
+                raw_delay_offset: None,
+            })
+        );
+    }
+
+    #[test]
+    fn test_ignore_unrelated_delayresp() {
+        let mut state = SlaveState::<TestFilter>::new(Default::default(), ());
+        let mut buffer = [0u8; MAX_DATA_LEN];
+
+        let default_ds = DefaultDS::new(InstanceConfig {
+            clock_identity: ClockIdentity::default(),
+            priority_1: 15,
+            priority_2: 128,
+            domain_number: 0,
+            slave_only: false,
+            sdo_id: SdoId::default(),
+        });
+
+        // mock rng and port config
+        let mut rng = rand::rngs::mock::StepRng::new(2, 1);
+        let port_identity = Default::default();
+        let port_config = PortConfig {
+            acceptable_master_list: (),
+            delay_mechanism: DelayMechanism::E2E {
+                interval: Interval::ONE_SECOND,
+            },
+            announce_interval: Interval::ONE_SECOND,
+            announce_receipt_timeout: Default::default(),
+            sync_interval: Interval::ONE_SECOND,
+            master_only: Default::default(),
+            delay_asymmetry: Default::default(),
+        };
+
+        let mut action = state.handle_event_receive(
+            Message {
+                header: Header {
+                    two_step_flag: false,
+                    correction_field: TimeInterval(1000.into()),
+                    ..Default::default()
+                },
+                body: MessageBody::Sync(SyncMessage {
+                    origin_timestamp: Time::from_micros(0).into(),
+                }),
+                suffix: TlvSet::default(),
+            },
+            Time::from_micros(50),
+            &mut TestClock,
+        );
+
+        // DelayReq is sent independently
+        assert!(action.next().is_none());
+        drop(action);
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(49),
+                offset: None,
+                delay: None,
+                raw_sync_offset: Some(Duration::from_micros(49)),
+                raw_delay_offset: None,
+            })
+        );
+
+        let mut action = state.send_delay_request(
+            &mut rng,
+            &port_config,
+            port_identity,
+            &default_ds,
+            &mut buffer,
+        );
+
+        let Some(PortAction::ResetDelayRequestTimer { .. }) = action.next() else {
+            panic!("Unexpected action");
+        };
+
+        let Some(PortAction::SendTimeCritical { context, data }) = action.next() else {
+            panic!("Unexpected action");
+        };
+
+        let mut action = state.handle_timestamp(context, Time::from_micros(100), &mut TestClock);
+
+        assert!(action.next().is_none());
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let req = Message::deserialize(data).unwrap();
+        let req_header = req.header;
+
+        let _req = match req.body {
+            MessageBody::DelayReq(msg) => msg,
+            _ => panic!("Incorrect message type"),
+        };
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    correction_field: TimeInterval(2000.into()),
+                    sequence_id: req_header.sequence_id,
+                    ..Default::default()
+                },
+                body: MessageBody::DelayResp(DelayRespMessage {
+                    receive_timestamp: Time::from_micros(353).into(),
+                    requesting_port_identity: PortIdentity {
+                        port_number: 83,
+                        ..Default::default()
+                    },
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    correction_field: TimeInterval(2000.into()),
+                    sequence_id: req_header.sequence_id.wrapping_sub(1),
+                    ..Default::default()
+                },
+                body: MessageBody::DelayResp(DelayRespMessage {
+                    receive_timestamp: Time::from_micros(353).into(),
+                    requesting_port_identity: req_header.source_port_identity,
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.filter.last_measurement.take(), None);
+
+        let mut action = state.handle_general_receive(
+            Message {
+                header: Header {
+                    correction_field: TimeInterval(2000.into()),
+                    sequence_id: req_header.sequence_id,
+                    ..Default::default()
+                },
+                body: MessageBody::DelayResp(DelayRespMessage {
+                    receive_timestamp: Time::from_micros(253).into(),
+                    requesting_port_identity: req_header.source_port_identity,
+                }),
+                suffix: TlvSet::default(),
+            },
+            PortIdentity::default(),
+            &mut TestClock,
+        );
+
+        assert!(action.next().is_none());
+        drop(action);
+
+        assert_eq!(state.mean_delay, Some(Duration::from_micros(100)));
+        assert_eq!(
+            state.filter.last_measurement.take(),
+            Some(Measurement {
+                event_time: Time::from_micros(100),
+                offset: None,
+                delay: Some(Duration::from_micros(100)),
+                raw_sync_offset: None,
+                raw_delay_offset: Some(Duration::from_micros(-151)),
+            })
+        );
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/ptp_instance.rs.html b/docs/src/statime/ptp_instance.rs.html new file mode 100644 index 000000000..2f7a34115 --- /dev/null +++ b/docs/src/statime/ptp_instance.rs.html @@ -0,0 +1,403 @@ +ptp_instance.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+
use core::{
+    marker::PhantomData,
+    sync::atomic::{AtomicI8, Ordering},
+};
+
+use atomic_refcell::AtomicRefCell;
+use rand::Rng;
+
+use crate::{
+    bmc::{acceptable_master::AcceptableMasterList, bmca::Bmca},
+    clock::Clock,
+    config::InstanceConfig,
+    datastructures::{
+        common::PortIdentity,
+        datasets::{CurrentDS, DefaultDS, ParentDS, TimePropertiesDS},
+    },
+    port::{InBmca, Port},
+    Filter, PortConfig,
+};
+
+/// A PTP node.
+///
+/// This object handles the complete running of the PTP protocol once created.
+/// It provides all the logic for both ordinary and boundary clock mode.
+///
+/// # Example
+/// Assuming we already have a network runtime and clock runtime, an ordinary
+/// clock can be run by first creating all the datasets, then creating the port,
+/// then finally setting up the instance and starting it:
+///
+/// ```ignore
+/// let default_ds = DefaultDS::new_ordinary_clock(
+///     clock_identity,
+///     128,
+///     128,
+///     0,
+///     false,
+///     SdoId::new(0).unwrap(),
+/// );
+/// let time_properties_ds =
+/// TimePropertiesDS::new_arbitrary_time(false, false, TimeSource::InternalOscillator);
+/// let port_ds = PortDS::new(
+///     PortIdentity {
+///         clock_identity,
+///         port_number: 1,
+///     },
+///     1,
+///     1,
+///     3,
+///     0,
+///     DelayMechanism::E2E,
+///     1,
+/// );
+/// let port = Port::new(port_ds, &mut network_runtime, interface_name).await;
+/// let mut instance = PtpInstance::new_ordinary_clock(
+///     default_ds,
+///     time_properties_ds,
+///     port,
+///     local_clock,
+///     BasicFilter::new(0.25),
+/// );
+///
+/// instance.run(&TimerImpl).await;
+/// ```
+pub struct PtpInstance<F> {
+    state: AtomicRefCell<PtpInstanceState>,
+    log_bmca_interval: AtomicI8,
+    _filter: PhantomData<F>,
+}
+
+#[derive(Debug)]
+pub(crate) struct PtpInstanceState {
+    pub(crate) default_ds: DefaultDS,
+    pub(crate) current_ds: CurrentDS,
+    pub(crate) parent_ds: ParentDS,
+    pub(crate) time_properties_ds: TimePropertiesDS,
+}
+
+impl PtpInstanceState {
+    fn bmca<A: AcceptableMasterList, C: Clock, F: Filter, R: Rng>(
+        &mut self,
+        ports: &mut [&mut Port<InBmca<'_>, A, R, C, F>],
+        bmca_interval: crate::Duration,
+    ) {
+        debug_assert_eq!(self.default_ds.number_ports as usize, ports.len());
+
+        for port in ports.iter_mut() {
+            port.calculate_best_local_announce_message()
+        }
+
+        let ebest = Bmca::<()>::find_best_announce_message(
+            ports
+                .iter()
+                .filter_map(|port| port.best_local_announce_message()),
+        );
+
+        for port in ports.iter_mut() {
+            let recommended_state = Bmca::<()>::calculate_recommended_state(
+                &self.default_ds,
+                ebest,
+                port.best_local_announce_message(), // erbest
+                port.state(),
+            );
+
+            log::debug!(
+                "Recommended state port {}: {recommended_state:?}",
+                port.number(),
+            );
+
+            if let Some(recommended_state) = recommended_state {
+                port.set_recommended_state(
+                    recommended_state,
+                    &mut self.time_properties_ds,
+                    &mut self.current_ds,
+                    &mut self.parent_ds,
+                    &self.default_ds,
+                );
+            }
+        }
+
+        // And update announce message ages
+        for port in ports.iter_mut() {
+            port.step_announce_age(bmca_interval);
+        }
+    }
+}
+
+impl<F> PtpInstance<F> {
+    pub fn new(config: InstanceConfig, time_properties_ds: TimePropertiesDS) -> Self {
+        let default_ds = DefaultDS::new(config);
+        Self {
+            state: AtomicRefCell::new(PtpInstanceState {
+                default_ds,
+                current_ds: Default::default(),
+                parent_ds: ParentDS::new(default_ds),
+                time_properties_ds,
+            }),
+            log_bmca_interval: AtomicI8::new(i8::MAX),
+            _filter: PhantomData,
+        }
+    }
+}
+
+impl<F: Filter> PtpInstance<F> {
+    /// Add and initialize this port
+    ///
+    /// We start in the BMCA state because that is convenient
+    ///
+    /// When providing the port with a different clock than the instance clock,
+    /// the caller is responsible for propagating any property changes to this
+    /// clock, and for synchronizing this clock with the instance clock as
+    /// appropriate based on the ports state.
+    pub fn add_port<A, C, R: Rng>(
+        &self,
+        config: PortConfig<A>,
+        filter_config: F::Config,
+        clock: C,
+        rng: R,
+    ) -> Port<InBmca<'_>, A, R, C, F> {
+        self.log_bmca_interval
+            .fetch_min(config.announce_interval.as_log_2(), Ordering::Relaxed);
+        let mut state = self.state.borrow_mut();
+        let port_identity = PortIdentity {
+            clock_identity: state.default_ds.clock_identity,
+            port_number: state.default_ds.number_ports,
+        };
+        state.default_ds.number_ports += 1;
+        Port::new(
+            &self.state,
+            config,
+            filter_config,
+            clock,
+            port_identity,
+            rng,
+        )
+    }
+
+    pub fn bmca<A: AcceptableMasterList, C: Clock, R: Rng>(
+        &self,
+        ports: &mut [&mut Port<InBmca<'_>, A, R, C, F>],
+    ) {
+        self.state.borrow_mut().bmca(
+            ports,
+            crate::Duration::from_seconds(
+                #[cfg(feature = "std")]
+                2f64.powi(self.log_bmca_interval.load(Ordering::Relaxed) as i32),
+                #[cfg(not(feature = "std"))]
+                libm::pow(2f64, self.log_bmca_interval.load(Ordering::Relaxed) as f64),
+            ),
+        )
+    }
+
+    pub fn bmca_interval(&self) -> core::time::Duration {
+        core::time::Duration::from_secs_f64(
+            #[cfg(feature = "std")]
+            2f64.powi(self.log_bmca_interval.load(Ordering::Relaxed) as i32),
+            #[cfg(not(feature = "std"))]
+            libm::pow(2f64, self.log_bmca_interval.load(Ordering::Relaxed) as f64),
+        )
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/time/duration.rs.html b/docs/src/statime/time/duration.rs.html new file mode 100644 index 000000000..a4bc4c7cd --- /dev/null +++ b/docs/src/statime/time/duration.rs.html @@ -0,0 +1,521 @@ +duration.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+
//! Implementation of the [Duration] type
+
+use core::{
+    fmt::Display,
+    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
+};
+
+use az::Az;
+use fixed::{
+    traits::{LossyInto, ToFixed},
+    types::I96F32,
+};
+
+use super::Interval;
+use crate::datastructures::common::TimeInterval;
+
+/// A duration is a span of time that can also be negative.
+///
+/// For example, the difference between two instants is a duration.
+/// And an instant plus a duration is another instant.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
+pub struct Duration {
+    /// Time in nanos
+    inner: I96F32,
+}
+
+impl Duration {
+    pub const ZERO: Duration = Duration {
+        inner: I96F32::ZERO,
+    };
+
+    /// Create an instance with the given amount of seconds
+    pub fn from_seconds(secs: f64) -> Self {
+        let inner = secs.az::<I96F32>() * 1_000_000_000.to_fixed::<I96F32>();
+        Self { inner }
+    }
+
+    /// Create an instance with the given amount of seconds
+    pub fn from_secs(secs: i64) -> Self {
+        let inner = secs.to_fixed::<I96F32>() * 1_000_000_000.to_fixed::<I96F32>();
+        Self { inner }
+    }
+
+    /// Create an instance with the given amount of milliseconds
+    pub fn from_millis(millis: i64) -> Self {
+        let inner = millis.to_fixed::<I96F32>() * 1_000_000.to_fixed::<I96F32>();
+        Self { inner }
+    }
+    /// Create an instance with the given amount of microseconds
+    pub fn from_micros(micros: i64) -> Self {
+        let inner = micros.to_fixed::<I96F32>() * 1_000.to_fixed::<I96F32>();
+        Self { inner }
+    }
+    /// Create an instance with the given amount of nanoseconds
+    pub fn from_nanos(nanos: i64) -> Self {
+        let inner = nanos.to_fixed::<I96F32>();
+        Self { inner }
+    }
+
+    /// Create an instance with the given amount of nanoseconds, using a fixed
+    /// point number so the subnanoseconds can be specified as well
+    pub fn from_fixed_nanos<F: ToFixed>(nanos: F) -> Self {
+        Self {
+            inner: nanos.to_fixed(),
+        }
+    }
+
+    /// Get the total amount of nanoseconds
+    pub fn nanos(&self) -> I96F32 {
+        self.inner
+    }
+
+    pub fn nanos_rounded(&self) -> i128 {
+        self.nanos().lossy_into()
+    }
+
+    /// Get the total amount of nanoseconds, losing some precision
+    pub fn nanos_lossy(&self) -> f64 {
+        self.nanos().lossy_into()
+    }
+
+    /// Get the total amount of seconds
+    pub fn secs(&self) -> i64 {
+        (self.inner / 1_000_000_000.to_fixed::<I96F32>()).to_num()
+    }
+
+    /// Get the total amount of seconds
+    pub fn seconds(&self) -> f64 {
+        self.inner.az::<f64>() / 1e9
+    }
+
+    /// Converts a log interval (as defined by the PTP spec) to a duration
+    pub fn from_log_interval(log_interval: i8) -> Self {
+        let seconds = libm::pow(2.0f64, log_interval as f64);
+        let nanos = seconds * 1_000_000_000.0;
+        Self::from_fixed_nanos(nanos)
+    }
+
+    /// Converts a interval (as defined by the PTP spec) to a duration
+    pub fn from_interval(interval: Interval) -> Self {
+        let seconds = interval.seconds();
+        let nanos = seconds * 1_000_000_000.0;
+        Self::from_fixed_nanos(nanos)
+    }
+
+    /// Takes the absolute (non-negative) value of the duration
+    pub fn abs(self) -> Duration {
+        Duration::from_fixed_nanos(self.nanos().abs())
+    }
+}
+
+impl From<TimeInterval> for Duration {
+    fn from(interval: TimeInterval) -> Self {
+        Self::from_fixed_nanos(interval.0)
+    }
+}
+
+impl From<Duration> for core::time::Duration {
+    fn from(value: Duration) -> Self {
+        core::time::Duration::from_nanos(value.nanos().saturating_to_num())
+    }
+}
+
+impl Neg for Duration {
+    type Output = Duration;
+
+    fn neg(self) -> Self::Output {
+        Self::from_fixed_nanos(-self.nanos())
+    }
+}
+
+impl Add for Duration {
+    type Output = Duration;
+
+    fn add(self, rhs: Duration) -> Self::Output {
+        Duration {
+            inner: self.nanos() + rhs.nanos(),
+        }
+    }
+}
+
+impl AddAssign for Duration {
+    fn add_assign(&mut self, rhs: Duration) {
+        *self = *self + rhs;
+    }
+}
+
+impl Sub for Duration {
+    type Output = Duration;
+
+    fn sub(self, rhs: Duration) -> Self::Output {
+        self + -rhs
+    }
+}
+
+impl SubAssign for Duration {
+    fn sub_assign(&mut self, rhs: Duration) {
+        *self = *self - rhs;
+    }
+}
+
+impl<TF: ToFixed> Mul<TF> for Duration {
+    type Output = Duration;
+
+    fn mul(self, rhs: TF) -> Self::Output {
+        Duration::from_fixed_nanos(self.nanos() * rhs.to_fixed::<I96F32>())
+    }
+}
+
+impl<TF: ToFixed> MulAssign<TF> for Duration {
+    fn mul_assign(&mut self, rhs: TF) {
+        *self = *self * rhs
+    }
+}
+
+impl<TF: ToFixed> Div<TF> for Duration {
+    type Output = Duration;
+
+    fn div(self, rhs: TF) -> Self::Output {
+        Duration::from_fixed_nanos(self.nanos() / rhs.to_fixed::<I96F32>())
+    }
+}
+
+impl<TF: ToFixed> DivAssign<TF> for Duration {
+    fn div_assign(&mut self, rhs: TF) {
+        *self = *self / rhs
+    }
+}
+
+impl Rem for Duration {
+    type Output = Duration;
+
+    fn rem(self, rhs: Self) -> Self::Output {
+        Duration::from_fixed_nanos(self.nanos() % rhs.nanos())
+    }
+}
+
+impl RemAssign for Duration {
+    fn rem_assign(&mut self, rhs: Self) {
+        *self = *self % rhs
+    }
+}
+
+impl Display for Duration {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{}", self.inner)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn values() {
+        assert_eq!(
+            Duration::from_secs(10).nanos(),
+            10_000_000_000u64.to_fixed::<I96F32>()
+        );
+        assert_eq!(
+            Duration::from_secs(-10).nanos(),
+            -(10_000_000_000u64.to_fixed::<I96F32>())
+        );
+        assert_eq!(
+            Duration::from_millis(10).nanos(),
+            10_000_000u64.to_fixed::<I96F32>()
+        );
+        assert_eq!(
+            Duration::from_micros(10).nanos(),
+            10_000u64.to_fixed::<I96F32>()
+        );
+        assert_eq!(Duration::from_nanos(10).nanos(), 10u64.to_fixed::<I96F32>());
+        assert_eq!(
+            Duration::from_fixed_nanos(10.123f64).nanos(),
+            10.123f64.to_fixed::<I96F32>()
+        );
+        assert_eq!(Duration::from_secs(10).secs(), 10);
+        assert_eq!(Duration::from_millis(10).secs(), 0);
+        assert_eq!(Duration::from_millis(1001).secs(), 1);
+    }
+
+    #[test]
+    fn log_interval() {
+        assert_eq!(Duration::from_log_interval(0), Duration::from_secs(1));
+        assert_eq!(Duration::from_log_interval(-1), Duration::from_millis(500));
+        assert_eq!(Duration::from_log_interval(1), Duration::from_secs(2));
+    }
+
+    #[test]
+    fn interval() {
+        assert_eq!(
+            Duration::from_fixed_nanos(2.25f64),
+            Duration::from(TimeInterval(2.25f64.to_fixed()))
+        );
+        assert_eq!(
+            TimeInterval(2.25f64.to_fixed()),
+            Duration::from_fixed_nanos(2.25f64).into()
+        );
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/time/instant.rs.html b/docs/src/statime/time/instant.rs.html new file mode 100644 index 000000000..04d06226e --- /dev/null +++ b/docs/src/statime/time/instant.rs.html @@ -0,0 +1,331 @@ +instant.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+
//! Implementation of the [Time] type
+
+use core::{
+    fmt::Display,
+    ops::{Add, AddAssign, Sub, SubAssign},
+};
+
+use fixed::{
+    traits::{LosslessTryInto, LossyInto, ToFixed},
+    types::{U112F16, U96F32},
+};
+
+use super::duration::Duration;
+use crate::datastructures::common::WireTimestamp;
+
+/// Time represents a specific moment in time.
+///
+/// The starting 0 point depends on the timescale being used by PTP, but
+/// for most uses will be the unix epoch.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
+pub struct Time {
+    /// Time in nanos since start of timescale
+    inner: U96F32,
+}
+
+impl Time {
+    /// Create an instance with the given amount of seconds from the origin
+    pub fn from_secs(secs: u64) -> Self {
+        let inner = secs.to_fixed::<U96F32>() * 1_000_000_000.to_fixed::<U96F32>();
+        Self { inner }
+    }
+    /// Create an instance with the given amount of milliseconds from the origin
+    pub fn from_millis(millis: u64) -> Self {
+        let inner = millis.to_fixed::<U96F32>() * 1_000_000.to_fixed::<U96F32>();
+        Self { inner }
+    }
+    /// Create an instance with the given amount of microseconds from the origin
+    pub fn from_micros(micros: u64) -> Self {
+        let inner = micros.to_fixed::<U96F32>() * 1_000.to_fixed::<U96F32>();
+        Self { inner }
+    }
+    /// Create an instance with the given amount of nanoseconds from the origin
+    pub fn from_nanos(nanos: u64) -> Self {
+        let inner = nanos.to_fixed::<U96F32>();
+        Self { inner }
+    }
+    /// Create an instance with the given amount of nanoseconds from the origin,
+    /// using a fixed point number so the subnanoseconds can be specified as
+    /// well
+    pub fn from_fixed_nanos<F: ToFixed>(nanos: F) -> Self {
+        Self {
+            inner: nanos.to_fixed(),
+        }
+    }
+
+    pub fn from_nanos_subnanos(nanos: u64, subnanos: u32) -> Self {
+        let bits = (nanos as u128) << 32 | (subnanos as u128);
+        let inner = U96F32::from_bits(bits);
+        Self { inner }
+    }
+
+    /// Get the total amount of nanoseconds since the origin
+    pub fn nanos(&self) -> U96F32 {
+        self.inner
+    }
+    /// Get all the nanoseconds that are under a second
+    pub fn subsec_nanos(&self) -> u32 {
+        (self.inner % 1_000_000_000.to_fixed::<U96F32>()).to_num()
+    }
+    /// Get the total amount of seconds since the origin
+    pub fn secs(&self) -> u64 {
+        (self.inner / 1_000_000_000.to_fixed::<U96F32>()).to_num()
+    }
+    // Get the subnanosecond amount
+    pub(crate) fn subnano(&self) -> crate::datastructures::common::TimeInterval {
+        let inter: U112F16 = self.inner.frac().lossy_into();
+        // unwrap is ok since always less than 1.
+        crate::datastructures::common::TimeInterval(inter.lossless_try_into().unwrap())
+    }
+}
+
+impl From<WireTimestamp> for Time {
+    fn from(ts: WireTimestamp) -> Self {
+        Self::from_fixed_nanos(ts.seconds as i128 * 1_000_000_000i128 + ts.nanos as i128)
+    }
+}
+
+impl Add<Duration> for Time {
+    type Output = Time;
+
+    fn add(self, rhs: Duration) -> Self::Output {
+        if rhs.nanos().is_negative() {
+            Time {
+                inner: self.nanos() - rhs.nanos().unsigned_abs(),
+            }
+        } else {
+            Time {
+                inner: self.nanos() + rhs.nanos().unsigned_abs(),
+            }
+        }
+    }
+}
+
+impl AddAssign<Duration> for Time {
+    fn add_assign(&mut self, rhs: Duration) {
+        *self = *self + rhs;
+    }
+}
+
+impl Sub<Duration> for Time {
+    type Output = Time;
+
+    fn sub(self, rhs: Duration) -> Self::Output {
+        self + -rhs
+    }
+}
+
+impl SubAssign<Duration> for Time {
+    fn sub_assign(&mut self, rhs: Duration) {
+        *self = *self - rhs;
+    }
+}
+
+impl Sub<Time> for Time {
+    type Output = Duration;
+
+    fn sub(self, rhs: Time) -> Self::Output {
+        Duration::from_fixed_nanos(self.inner) - Duration::from_fixed_nanos(rhs.inner)
+    }
+}
+
+impl Display for Time {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{}", self.inner)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn values() {
+        assert_eq!(
+            Time::from_secs(10).nanos(),
+            10_000_000_000u64.to_fixed::<U96F32>()
+        );
+        assert_eq!(
+            Time::from_millis(10).nanos(),
+            10_000_000u64.to_fixed::<U96F32>()
+        );
+        assert_eq!(
+            Time::from_micros(10).nanos(),
+            10_000u64.to_fixed::<U96F32>()
+        );
+        assert_eq!(Time::from_nanos(10).nanos(), 10u64.to_fixed::<U96F32>());
+        assert_eq!(
+            Time::from_fixed_nanos(10.123f64).nanos(),
+            10.123f64.to_fixed::<U96F32>()
+        );
+        assert_eq!(Time::from_secs(10).secs(), 10);
+        assert_eq!(Time::from_millis(10).secs(), 0);
+        assert_eq!(Time::from_millis(1001).secs(), 1);
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/time/interval.rs.html b/docs/src/statime/time/interval.rs.html new file mode 100644 index 000000000..5ca555e86 --- /dev/null +++ b/docs/src/statime/time/interval.rs.html @@ -0,0 +1,125 @@ +interval.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct Interval(i8);
+
+impl core::fmt::Debug for Interval {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("Interval")
+            .field("seconds", &self.as_f64())
+            .field("log_base_2", &self.0)
+            .finish()
+    }
+}
+
+impl Interval {
+    pub const ONE_SECOND: Self = Self(0);
+    pub const TWO_SECONDS: Self = Self(1);
+
+    pub const fn from_log_2(log_2: i8) -> Self {
+        Self(log_2)
+    }
+
+    pub fn seconds(self) -> f64 {
+        self.as_f64()
+    }
+
+    pub fn as_duration(self) -> super::Duration {
+        super::Duration::from_interval(self)
+    }
+
+    pub fn as_core_duration(self) -> core::time::Duration {
+        core::time::Duration::from_secs_f64(self.seconds())
+    }
+
+    #[cfg(not(feature = "std"))]
+    pub fn as_f64(self) -> f64 {
+        libm::pow(2.0f64, self.0 as f64)
+    }
+
+    #[cfg(feature = "std")]
+    pub fn as_f64(self) -> f64 {
+        2.0f64.powi(self.0 as i32)
+    }
+
+    pub fn as_log_2(self) -> i8 {
+        self.0
+    }
+}
+
+impl From<i8> for Interval {
+    fn from(value: i8) -> Self {
+        Self::from_log_2(value)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn two() {
+        assert_eq!(Interval::TWO_SECONDS.as_f64(), 2.0f64)
+    }
+}
+
\ No newline at end of file diff --git a/docs/src/statime/time/mod.rs.html b/docs/src/statime/time/mod.rs.html new file mode 100644 index 000000000..0060fde14 --- /dev/null +++ b/docs/src/statime/time/mod.rs.html @@ -0,0 +1,19 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+
//! Time definitions
+
+mod duration;
+mod instant;
+mod interval;
+
+pub use duration::Duration;
+pub use instant::Time;
+pub use interval::Interval;
+
\ No newline at end of file diff --git a/docs/src/statime_linux/clock/mod.rs.html b/docs/src/statime_linux/clock/mod.rs.html new file mode 100644 index 000000000..b4895251c --- /dev/null +++ b/docs/src/statime_linux/clock/mod.rs.html @@ -0,0 +1,239 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+
//! Implementation of the abstract clock for the linux platform
+
+use std::path::Path;
+
+use clock_steering::{unix::UnixClock, TimeOffset};
+use statime::{Clock, Duration, Time, TimePropertiesDS};
+
+#[derive(Debug, Clone)]
+pub struct LinuxClock {
+    pub clock: clock_steering::unix::UnixClock,
+}
+
+impl LinuxClock {
+    pub const CLOCK_REALTIME: Self = Self {
+        clock: UnixClock::CLOCK_REALTIME,
+    };
+
+    pub fn open(path: impl AsRef<Path>) -> std::io::Result<Self> {
+        let clock = UnixClock::open(path)?;
+
+        Ok(Self { clock })
+    }
+}
+
+impl clock_steering::Clock for LinuxClock {
+    type Error = clock_steering::unix::Error;
+
+    fn now(&self) -> Result<clock_steering::Timestamp, Self::Error> {
+        self.clock.now()
+    }
+
+    fn resolution(&self) -> Result<clock_steering::Timestamp, Self::Error> {
+        self.clock.resolution()
+    }
+
+    fn set_frequency(&self, frequency: f64) -> Result<clock_steering::Timestamp, Self::Error> {
+        self.clock.set_frequency(frequency)
+    }
+
+    fn step_clock(&self, offset: TimeOffset) -> Result<clock_steering::Timestamp, Self::Error> {
+        self.clock.step_clock(offset)
+    }
+
+    fn set_leap_seconds(
+        &self,
+        leap_status: clock_steering::LeapIndicator,
+    ) -> Result<(), Self::Error> {
+        self.clock.set_leap_seconds(leap_status)
+    }
+
+    fn error_estimate_update(
+        &self,
+        estimated_error: std::time::Duration,
+        maximum_error: std::time::Duration,
+    ) -> Result<(), Self::Error> {
+        self.clock
+            .error_estimate_update(estimated_error, maximum_error)
+    }
+}
+
+fn time_from_timestamp(timestamp: clock_steering::Timestamp, fallback: Time) -> Time {
+    let Ok(seconds): Result<u64, _> = timestamp.seconds.try_into() else {
+        return fallback;
+    };
+
+    let nanos = seconds * 1_000_000_000 + timestamp.nanos as u64;
+    Time::from_nanos_subnanos(nanos, 0)
+}
+
+impl Clock for LinuxClock {
+    type Error = clock_steering::unix::Error;
+
+    fn now(&self) -> Time {
+        use clock_steering::Clock;
+
+        let timestamp = self.clock.now().unwrap();
+        time_from_timestamp(timestamp, Time::from_fixed_nanos(0))
+    }
+
+    fn set_frequency(&mut self, freq: f64) -> Result<Time, Self::Error> {
+        use clock_steering::Clock;
+        log::trace!("Setting clock frequency to {:e}ppm", freq);
+        let timestamp = self.clock.set_frequency(freq)?;
+        Ok(time_from_timestamp(timestamp, statime::Clock::now(self)))
+    }
+
+    fn step_clock(&mut self, time_offset: Duration) -> Result<Time, Self::Error> {
+        use clock_steering::Clock;
+
+        // Since we want nanos to be in [0,1_000_000_000), we need
+        // euclidean division and remainder.
+        let offset_nanos: i128 = time_offset.nanos_rounded();
+        let offset = TimeOffset {
+            seconds: offset_nanos
+                .div_euclid(1_000_000_000)
+                .try_into()
+                .expect("Unexpected jump larger than 2^64 seconds"),
+            nanos: offset_nanos.rem_euclid(1_000_000_000) as _, // Result will always fit in u32
+        };
+
+        log::trace!(
+            "Stepping clock {:e}ns",
+            (offset.seconds as f64) * 1e9 + (offset.nanos as f64)
+        );
+
+        let timestamp = self.clock.step_clock(offset)?;
+        Ok(time_from_timestamp(timestamp, statime::Clock::now(self)))
+    }
+
+    fn set_properties(&mut self, _time_properties: &TimePropertiesDS) -> Result<(), Self::Error> {
+        // For now just ignore these
+
+        Ok(())
+    }
+}
+
+pub fn libc_timespec_into_instant(spec: libc::timespec) -> Time {
+    Time::from_fixed_nanos(spec.tv_sec as i128 * 1_000_000_000i128 + spec.tv_nsec as i128)
+}
+
\ No newline at end of file diff --git a/docs/src/statime_linux/config/mod.rs.html b/docs/src/statime_linux/config/mod.rs.html new file mode 100644 index 000000000..e622c0f72 --- /dev/null +++ b/docs/src/statime_linux/config/mod.rs.html @@ -0,0 +1,253 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+
use std::{fs::read_to_string, os::unix::fs::PermissionsExt, path::Path};
+
+use log::warn;
+use serde::{Deserialize, Deserializer};
+use statime::{ClockIdentity, DelayMechanism, Duration, Interval};
+use timestamped_socket::interface::InterfaceName;
+
+#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+pub struct Config {
+    pub loglevel: String,
+    pub sdo_id: u16,
+    pub domain: u8,
+    pub priority1: u8,
+    pub priority2: u8,
+    #[serde(rename = "port")]
+    pub ports: Vec<PortConfig>,
+}
+
+#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
+pub struct PortConfig {
+    pub interface: InterfaceName,
+    #[serde(default, deserialize_with = "deserialize_acceptable_master_list")]
+    pub acceptable_master_list: Option<Vec<ClockIdentity>>,
+    #[serde(default)]
+    pub hardware_clock: Option<String>,
+    #[serde(default)]
+    pub network_mode: NetworkMode,
+    pub announce_interval: i8,
+    pub sync_interval: i8,
+    pub announce_receipt_timeout: u8,
+    #[serde(default)]
+    pub master_only: bool,
+    pub delay_asymetry: i64,
+    pub delay_mechanism: i8,
+}
+
+fn deserialize_acceptable_master_list<'de, D>(
+    deserializer: D,
+) -> Result<Option<Vec<ClockIdentity>>, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    use hex::FromHex;
+    use serde::de::Error;
+
+    let raw: Vec<&str> = Deserialize::deserialize(deserializer)?;
+    let mut result = Vec::with_capacity(raw.len());
+
+    for identity in raw {
+        result.push(ClockIdentity(<[u8; 8]>::from_hex(identity).map_err(
+            |e| D::Error::custom(format!("Invalid clock identifier: {}", e)),
+        )?));
+    }
+
+    Ok(Some(result))
+}
+
+impl From<PortConfig> for statime::PortConfig<Option<Vec<ClockIdentity>>> {
+    fn from(pc: PortConfig) -> Self {
+        Self {
+            acceptable_master_list: pc.acceptable_master_list,
+            announce_interval: Interval::from_log_2(pc.announce_interval),
+            sync_interval: Interval::from_log_2(pc.sync_interval),
+            announce_receipt_timeout: pc.announce_receipt_timeout,
+            master_only: pc.master_only,
+            delay_asymmetry: Duration::from_nanos(pc.delay_asymetry),
+            delay_mechanism: DelayMechanism::E2E {
+                interval: Interval::from_log_2(pc.delay_mechanism),
+            },
+        }
+    }
+}
+
+#[derive(Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)]
+#[serde(rename_all = "lowercase")]
+pub enum NetworkMode {
+    #[default]
+    Ipv4,
+    Ipv6,
+}
+
+impl Config {
+    /// Parse config from file
+    pub fn from_file(file: &Path) -> Result<Config, ConfigError> {
+        let meta = std::fs::metadata(file).unwrap();
+        let perm = meta.permissions();
+
+        if perm.mode() as libc::mode_t & libc::S_IWOTH != 0 {
+            warn!("Unrestricted config file permissions: Others can write.");
+        }
+
+        let contents = read_to_string(file).map_err(ConfigError::Io)?;
+        let config: Config = toml::de::from_str(&contents).map_err(ConfigError::Toml)?;
+        config.warn_when_unreasonable();
+        Ok(config)
+    }
+
+    /// Warns about unreasonable config values
+    pub fn warn_when_unreasonable(&self) {
+        if self.ports.is_empty() {
+            warn!("No ports configured.");
+        }
+
+        if self.ports.len() > 16 {
+            warn!("Too many ports are configured.");
+        }
+    }
+}
+
+#[derive(Debug)]
+pub enum ConfigError {
+    Io(std::io::Error),
+    Toml(toml::de::Error),
+}
+
+impl std::fmt::Display for ConfigError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            ConfigError::Io(e) => writeln!(f, "io error while reading config: {e}"),
+            ConfigError::Toml(e) => writeln!(f, "config toml parsing error: {e}"),
+        }
+    }
+}
+
+impl std::error::Error for ConfigError {}
+
\ No newline at end of file diff --git a/docs/src/statime_linux/lib.rs.html b/docs/src/statime_linux/lib.rs.html new file mode 100644 index 000000000..4a3a7b7ad --- /dev/null +++ b/docs/src/statime_linux/lib.rs.html @@ -0,0 +1,11 @@ +lib.rs - source
1
+2
+3
+4
+5
+
extern crate core;
+
+pub mod clock;
+pub mod config;
+pub mod socket;
+
\ No newline at end of file diff --git a/docs/src/statime_linux/socket.rs.html b/docs/src/statime_linux/socket.rs.html new file mode 100644 index 000000000..970c50feb --- /dev/null +++ b/docs/src/statime_linux/socket.rs.html @@ -0,0 +1,181 @@ +socket.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+
#![forbid(unsafe_code)]
+
+//! Event and General sockets for linux systems
+
+use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
+
+use statime::Time;
+use timestamped_socket::{
+    interface::InterfaceName,
+    socket::{open_interface_udp4, open_interface_udp6, InterfaceTimestampMode, Open, Socket},
+};
+
+const IPV6_PRIMARY_MULTICAST: Ipv6Addr = Ipv6Addr::new(0xff, 0x0e, 0, 0, 0, 0, 0x01, 0x81);
+const IPV6_PDELAY_MULTICAST: Ipv6Addr = Ipv6Addr::new(0xff, 0x02, 0, 0, 0, 0, 0, 0x6b);
+
+const IPV4_PRIMARY_MULTICAST: Ipv4Addr = Ipv4Addr::new(224, 0, 1, 129);
+const IPV4_PDELAY_MULTICAST: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 107);
+
+const EVENT_PORT: u16 = 319;
+const GENERAL_PORT: u16 = 320;
+
+pub trait PtpTargetAddress {
+    const PRIMARY_EVENT: Self;
+    const PRIMARY_GENERAL: Self;
+    const PDELAY_EVENT: Self;
+    const PDELAY_GENERAL: Self;
+}
+
+impl PtpTargetAddress for SocketAddrV4 {
+    const PRIMARY_EVENT: Self = SocketAddrV4::new(IPV4_PRIMARY_MULTICAST, EVENT_PORT);
+    const PRIMARY_GENERAL: Self = SocketAddrV4::new(IPV4_PRIMARY_MULTICAST, GENERAL_PORT);
+    const PDELAY_EVENT: Self = SocketAddrV4::new(IPV4_PDELAY_MULTICAST, EVENT_PORT);
+    const PDELAY_GENERAL: Self = SocketAddrV4::new(IPV4_PDELAY_MULTICAST, GENERAL_PORT);
+}
+
+impl PtpTargetAddress for SocketAddrV6 {
+    const PRIMARY_EVENT: Self = SocketAddrV6::new(IPV6_PRIMARY_MULTICAST, EVENT_PORT, 0, 0);
+    const PRIMARY_GENERAL: Self = SocketAddrV6::new(IPV6_PRIMARY_MULTICAST, GENERAL_PORT, 0, 0);
+    const PDELAY_EVENT: Self = SocketAddrV6::new(IPV6_PDELAY_MULTICAST, EVENT_PORT, 0, 0);
+    const PDELAY_GENERAL: Self = SocketAddrV6::new(IPV6_PDELAY_MULTICAST, GENERAL_PORT, 0, 0);
+}
+
+pub fn open_ipv4_event_socket(
+    interface: InterfaceName,
+    timestamping: InterfaceTimestampMode,
+) -> std::io::Result<Socket<SocketAddrV4, Open>> {
+    let socket = open_interface_udp4(interface, EVENT_PORT, timestamping)?;
+    socket.join_multicast(SocketAddrV4::new(IPV4_PRIMARY_MULTICAST, 0), interface)?;
+    socket.join_multicast(SocketAddrV4::new(IPV4_PDELAY_MULTICAST, 0), interface)?;
+    Ok(socket)
+}
+
+pub fn open_ipv4_general_socket(
+    interface: InterfaceName,
+) -> std::io::Result<Socket<SocketAddrV4, Open>> {
+    let socket = open_interface_udp4(interface, GENERAL_PORT, InterfaceTimestampMode::None)?;
+    socket.join_multicast(SocketAddrV4::new(IPV4_PRIMARY_MULTICAST, 0), interface)?;
+    socket.join_multicast(SocketAddrV4::new(IPV4_PDELAY_MULTICAST, 0), interface)?;
+    Ok(socket)
+}
+
+pub fn open_ipv6_event_socket(
+    interface: InterfaceName,
+    timestamping: InterfaceTimestampMode,
+) -> std::io::Result<Socket<SocketAddrV6, Open>> {
+    let socket = open_interface_udp6(interface, EVENT_PORT, timestamping)?;
+    socket.join_multicast(
+        SocketAddrV6::new(IPV6_PRIMARY_MULTICAST, 0, 0, 0),
+        interface,
+    )?;
+    socket.join_multicast(SocketAddrV6::new(IPV6_PDELAY_MULTICAST, 0, 0, 0), interface)?;
+    Ok(socket)
+}
+
+pub fn open_ipv6_general_socket(
+    interface: InterfaceName,
+) -> std::io::Result<Socket<SocketAddrV6, Open>> {
+    let socket = open_interface_udp6(interface, GENERAL_PORT, InterfaceTimestampMode::None)?;
+    // Port, flowinfo and scope doesn't matter for join multicast
+    socket.join_multicast(
+        SocketAddrV6::new(IPV6_PRIMARY_MULTICAST, 0, 0, 0),
+        interface,
+    )?;
+    socket.join_multicast(SocketAddrV6::new(IPV6_PDELAY_MULTICAST, 0, 0, 0), interface)?;
+    Ok(socket)
+}
+
+pub fn timestamp_to_time(ts: timestamped_socket::socket::Timestamp) -> Time {
+    Time::from_fixed_nanos(ts.seconds as i128 * 1_000_000_000i128 + ts.nanos as i128)
+}
+
\ No newline at end of file diff --git a/docs/static.files/COPYRIGHT-23e9bde6c69aea69.txt b/docs/static.files/COPYRIGHT-23e9bde6c69aea69.txt new file mode 100644 index 000000000..1447df792 --- /dev/null +++ b/docs/static.files/COPYRIGHT-23e9bde6c69aea69.txt @@ -0,0 +1,50 @@ +# REUSE-IgnoreStart + +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. + +# REUSE-IgnoreEnd diff --git a/docs/static.files/FiraSans-LICENSE-db4b642586e02d97.txt b/docs/static.files/FiraSans-LICENSE-db4b642586e02d97.txt new file mode 100644 index 000000000..d7e9c149b --- /dev/null +++ b/docs/static.files/FiraSans-LICENSE-db4b642586e02d97.txt @@ -0,0 +1,98 @@ +// REUSE-IgnoreStart + +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/docs/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 b/docs/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 new file mode 100644 index 000000000..7a1e5fc54 Binary files /dev/null and b/docs/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 differ diff --git a/docs/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 b/docs/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 new file mode 100644 index 000000000..e766e06cc Binary files /dev/null and b/docs/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 differ diff --git a/docs/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt b/docs/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/docs/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/docs/static.files/LICENSE-MIT-65090b722b3f6c56.txt b/docs/static.files/LICENSE-MIT-65090b722b3f6c56.txt new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/docs/static.files/LICENSE-MIT-65090b722b3f6c56.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/docs/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 b/docs/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 new file mode 100644 index 000000000..1866ad4bc Binary files /dev/null and b/docs/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 differ diff --git a/docs/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt b/docs/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt new file mode 100644 index 000000000..4b3edc29e --- /dev/null +++ b/docs/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt @@ -0,0 +1,103 @@ +// REUSE-IgnoreStart + +Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/), + +with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, +NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, +Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, +NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic, +Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/docs/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 b/docs/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 new file mode 100644 index 000000000..462c34efc Binary files /dev/null and b/docs/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 differ diff --git a/docs/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt b/docs/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt new file mode 100644 index 000000000..0d2941e14 --- /dev/null +++ b/docs/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt @@ -0,0 +1,97 @@ +// REUSE-IgnoreStart + +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/docs/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 b/docs/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 new file mode 100644 index 000000000..10b558e0b Binary files /dev/null and b/docs/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 differ diff --git a/docs/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 b/docs/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 new file mode 100644 index 000000000..5ec64eef0 Binary files /dev/null and b/docs/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 differ diff --git a/docs/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 b/docs/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 new file mode 100644 index 000000000..181a07f63 Binary files /dev/null and b/docs/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 differ diff --git a/docs/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 b/docs/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 new file mode 100644 index 000000000..2ae08a7be Binary files /dev/null and b/docs/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 differ diff --git a/docs/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md b/docs/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md new file mode 100644 index 000000000..175fa4f47 --- /dev/null +++ b/docs/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md @@ -0,0 +1,98 @@ + + +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. +Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + + diff --git a/docs/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 b/docs/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 new file mode 100644 index 000000000..0263fc304 Binary files /dev/null and b/docs/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 differ diff --git a/docs/static.files/clipboard-7571035ce49a181d.svg b/docs/static.files/clipboard-7571035ce49a181d.svg new file mode 100644 index 000000000..8adbd9963 --- /dev/null +++ b/docs/static.files/clipboard-7571035ce49a181d.svg @@ -0,0 +1 @@ + diff --git a/docs/static.files/favicon-16x16-8b506e7a72182f1c.png b/docs/static.files/favicon-16x16-8b506e7a72182f1c.png new file mode 100644 index 000000000..ea4b45cae Binary files /dev/null and b/docs/static.files/favicon-16x16-8b506e7a72182f1c.png differ diff --git a/docs/static.files/favicon-2c020d218678b618.svg b/docs/static.files/favicon-2c020d218678b618.svg new file mode 100644 index 000000000..8b34b5119 --- /dev/null +++ b/docs/static.files/favicon-2c020d218678b618.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/docs/static.files/favicon-32x32-422f7d1d52889060.png b/docs/static.files/favicon-32x32-422f7d1d52889060.png new file mode 100644 index 000000000..69b8613ce Binary files /dev/null and b/docs/static.files/favicon-32x32-422f7d1d52889060.png differ diff --git a/docs/static.files/main-c5bd66d33317d69f.js b/docs/static.files/main-c5bd66d33317d69f.js new file mode 100644 index 000000000..43133d66e --- /dev/null +++ b/docs/static.files/main-c5bd66d33317d69f.js @@ -0,0 +1,12 @@ +"use strict";window.RUSTDOC_TOOLTIP_HOVER_MS=300;window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS=450;function resourcePath(basename,extension){return getVar("root-path")+basename+getVar("resource-suffix")+extension}function hideMain(){addClass(document.getElementById(MAIN_ID),"hidden")}function showMain(){removeClass(document.getElementById(MAIN_ID),"hidden")}function elemIsInParent(elem,parent){while(elem&&elem!==document.body){if(elem===parent){return true}elem=elem.parentElement}return false}function blurHandler(event,parentElem,hideCallback){if(!elemIsInParent(document.activeElement,parentElem)&&!elemIsInParent(event.relatedTarget,parentElem)){hideCallback()}}window.rootPath=getVar("root-path");window.currentCrate=getVar("current-crate");function setMobileTopbar(){const mobileTopbar=document.querySelector(".mobile-topbar");const locationTitle=document.querySelector(".sidebar h2.location");if(mobileTopbar&&locationTitle){const mobileTitle=document.createElement("h2");mobileTitle.innerHTML=locationTitle.innerHTML;mobileTopbar.appendChild(mobileTitle)}}function getVirtualKey(ev){if("key"in ev&&typeof ev.key!=="undefined"){return ev.key}const c=ev.charCode||ev.keyCode;if(c===27){return"Escape"}return String.fromCharCode(c)}const MAIN_ID="main-content";const SETTINGS_BUTTON_ID="settings-menu";const ALTERNATIVE_DISPLAY_ID="alternative-display";const NOT_DISPLAYED_ID="not-displayed";const HELP_BUTTON_ID="help-button";function getSettingsButton(){return document.getElementById(SETTINGS_BUTTON_ID)}function getHelpButton(){return document.getElementById(HELP_BUTTON_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function insertAfter(newNode,referenceNode){referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)}function getOrCreateSection(id,classes){let el=document.getElementById(id);if(!el){el=document.createElement("section");el.id=id;el.className=classes;insertAfter(el,document.getElementById(MAIN_ID))}return el}function getAlternativeDisplayElem(){return getOrCreateSection(ALTERNATIVE_DISPLAY_ID,"content hidden")}function getNotDisplayedElem(){return getOrCreateSection(NOT_DISPLAYED_ID,"hidden")}function switchDisplayedElement(elemToDisplay){const el=getAlternativeDisplayElem();if(el.children.length>0){getNotDisplayedElem().appendChild(el.firstElementChild)}if(elemToDisplay===null){addClass(el,"hidden");showMain();return}el.appendChild(elemToDisplay);hideMain();removeClass(el,"hidden")}function browserSupportsHistoryApi(){return window.history&&typeof window.history.pushState==="function"}function preLoadCss(cssUrl){const link=document.createElement("link");link.href=cssUrl;link.rel="preload";link.as="style";document.getElementsByTagName("head")[0].appendChild(link)}(function(){const isHelpPage=window.location.pathname.endsWith("/help.html");function loadScript(url){const script=document.createElement("script");script.src=url;document.head.append(script)}getSettingsButton().onclick=event=>{if(event.ctrlKey||event.altKey||event.metaKey){return}window.hideAllModals(false);addClass(getSettingsButton(),"rotate");event.preventDefault();loadScript(getVar("static-root-path")+getVar("settings-js"));setTimeout(()=>{const themes=getVar("themes").split(",");for(const theme of themes){if(theme!==""){preLoadCss(getVar("root-path")+theme+".css")}}},0)};window.searchState={loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:()=>{let el=document.getElementById("search");if(!el){el=document.createElement("section");el.id="search";getNotDisplayedElem().appendChild(el)}return el},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:()=>{if(searchState.timeout!==null){clearTimeout(searchState.timeout);searchState.timeout=null}},isDisplayed:()=>searchState.outputElement().parentElement.id===ALTERNATIVE_DISPLAY_ID,focus:()=>{searchState.input.focus()},defocus:()=>{searchState.input.blur()},showResults:search=>{if(search===null||typeof search==="undefined"){search=searchState.outputElement()}switchDisplayedElement(search);searchState.mouseMovedAfterSearch=false;document.title=searchState.title},removeQueryParameters:()=>{document.title=searchState.titleBeforeSearch;if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.hash)}},hideResults:()=>{switchDisplayedElement(null);searchState.removeQueryParameters()},getQueryStringParams:()=>{const params={};window.location.search.substring(1).split("&").map(s=>{const pair=s.split("=");params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params},setup:()=>{const search_input=searchState.input;if(!searchState.input){return}let searchLoaded=false;function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(getVar("static-root-path")+getVar("search-js"));loadScript(resourcePath("search-index",".js"))}}search_input.addEventListener("focus",()=>{search_input.origPlaceholder=search_input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});if(search_input.value!==""){loadSearch()}const params=searchState.getQueryStringParams();if(params.search!==undefined){searchState.setLoadingSearch();loadSearch()}},setLoadingSearch:()=>{const search=searchState.outputElement();search.innerHTML="

"+searchState.loadingText+"

";searchState.showResults(search)},};const toggleAllDocsId="toggle-all-docs";let savedHash="";function handleHashes(ev){if(ev!==null&&searchState.isDisplayed()&&ev.newURL){switchDisplayedElement(null);const hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.search+"#"+hash)}const elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}const pageId=window.location.hash.replace(/^#/,"");if(savedHash!==pageId){savedHash=pageId;if(pageId!==""){expandSection(pageId)}}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentNode}}function expandSection(id){openParentDetails(document.getElementById(id))}function handleEscape(ev){searchState.clearInputTimeout();searchState.hideResults();ev.preventDefault();searchState.defocus();window.hideAllModals(true)}function handleShortcut(ev){const disableShortcuts=getSettingValue("disable-shortcuts")==="true";if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){return}if(document.activeElement.tagName==="INPUT"&&document.activeElement.type!=="checkbox"&&document.activeElement.type!=="radio"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":ev.preventDefault();searchState.focus();break;case"+":ev.preventDefault();expandAllDocs();break;case"-":ev.preventDefault();collapseAllDocs();break;case"?":showHelp();break;default:break}}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);function addSidebarItems(){if(!window.SIDEBAR_ITEMS){return}const sidebar=document.getElementsByClassName("sidebar-elems")[0];function block(shortty,id,longty){const filtered=window.SIDEBAR_ITEMS[shortty];if(!filtered){return}const h3=document.createElement("h3");h3.innerHTML=`${longty}`;const ul=document.createElement("ul");ul.className="block "+shortty;for(const name of filtered){let path;if(shortty==="mod"){path=name+"/index.html"}else{path=shortty+"."+name+".html"}const current_page=document.location.href.split("/").pop();const link=document.createElement("a");link.href=path;if(path===current_page){link.className="current"}link.textContent=name;const li=document.createElement("li");li.appendChild(link);ul.appendChild(li)}sidebar.appendChild(h3);sidebar.appendChild(ul)}if(sidebar){block("primitive","primitives","Primitive Types");block("mod","modules","Modules");block("macro","macros","Macros");block("struct","structs","Structs");block("enum","enums","Enums");block("union","unions","Unions");block("constant","constants","Constants");block("static","static","Statics");block("trait","traits","Traits");block("fn","functions","Functions");block("type","types","Type Aliases");block("foreigntype","foreign-types","Foreign Types");block("keyword","keywords","Keywords");block("traitalias","trait-aliases","Trait Aliases")}}window.register_implementors=imp=>{const implementors=document.getElementById("implementors-list");const synthetic_implementors=document.getElementById("synthetic-implementors-list");const inlined_types=new Set();const TEXT_IDX=0;const SYNTHETIC_IDX=1;const TYPES_IDX=2;if(synthetic_implementors){onEachLazy(synthetic_implementors.getElementsByClassName("impl"),el=>{const aliases=el.getAttribute("data-aliases");if(!aliases){return}aliases.split(",").forEach(alias=>{inlined_types.add(alias)})})}let currentNbImpls=implementors.getElementsByClassName("impl").length;const traitName=document.querySelector(".main-heading h1 > .trait").textContent;const baseIdName="impl-"+traitName+"-";const libs=Object.getOwnPropertyNames(imp);const script=document.querySelector("script[data-ignore-extern-crates]");const ignoreExternCrates=new Set((script?script.getAttribute("data-ignore-extern-crates"):"").split(","));for(const lib of libs){if(lib===window.currentCrate||ignoreExternCrates.has(lib)){continue}const structs=imp[lib];struct_loop:for(const struct of structs){const list=struct[SYNTHETIC_IDX]?synthetic_implementors:implementors;if(struct[SYNTHETIC_IDX]){for(const struct_type of struct[TYPES_IDX]){if(inlined_types.has(struct_type)){continue struct_loop}inlined_types.add(struct_type)}}const code=document.createElement("h3");code.innerHTML=struct[TEXT_IDX];addClass(code,"code-header");onEachLazy(code.getElementsByTagName("a"),elem=>{const href=elem.getAttribute("href");if(href&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});const currentId=baseIdName+currentNbImpls;const anchor=document.createElement("a");anchor.href="#"+currentId;addClass(anchor,"anchor");const display=document.createElement("div");display.id=currentId;addClass(display,"impl");display.appendChild(anchor);display.appendChild(code);list.appendChild(display);currentNbImpls+=1}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}function addSidebarCrates(){if(!window.ALL_CRATES){return}const sidebarElems=document.getElementsByClassName("sidebar-elems")[0];if(!sidebarElems){return}const h3=document.createElement("h3");h3.innerHTML="Crates";const ul=document.createElement("ul");ul.className="block crate";for(const crate of window.ALL_CRATES){const link=document.createElement("a");link.href=window.rootPath+crate+"/index.html";if(window.rootPath!=="./"&&crate===window.currentCrate){link.className="current"}link.textContent=crate;const li=document.createElement("li");li.appendChild(link);ul.appendChild(li)}sidebarElems.appendChild(h3);sidebarElems.appendChild(ul)}function expandAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);removeClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hasClass(e,"type-contents-toggle")&&!hasClass(e,"more-examples-toggle")){e.open=true}});innerToggle.title="collapse all docs";innerToggle.children[0].innerText="\u2212"}function collapseAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);addClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(e.parentNode.id!=="implementations-list"||(!hasClass(e,"implementors-toggle")&&!hasClass(e,"type-contents-toggle"))){e.open=false}});innerToggle.title="expand all docs";innerToggle.children[0].innerText="+"}function toggleAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);if(!innerToggle){return}if(hasClass(innerToggle,"will-expand")){expandAllDocs()}else{collapseAllDocs()}}(function(){const toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}const hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";const hideImplementations=getSettingValue("auto-hide-trait-implementations")==="true";const hideLargeItemContents=getSettingValue("auto-hide-large-items")!=="false";function setImplementorsTogglesOpen(id,open){const list=document.getElementById(id);if(list!==null){onEachLazy(list.getElementsByClassName("implementors-toggle"),e=>{e.open=open})}}if(hideImplementations){setImplementorsTogglesOpen("trait-implementations-list",false);setImplementorsTogglesOpen("blanket-implementations-list",false)}onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hideLargeItemContents&&hasClass(e,"type-contents-toggle")){e.open=true}if(hideMethodDocs&&hasClass(e,"method-toggle")){e.open=false}})}());window.rustdoc_add_line_numbers_to_examples=()=>{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");if(line_numbers.length>0){return}const count=x.textContent.split("\n").length;const elems=[];for(let i=0;i{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");for(const node of line_numbers){parent.removeChild(node)}})};if(getSettingValue("line-numbers")==="true"){window.rustdoc_add_line_numbers_to_examples()}function showSidebar(){window.hideAllModals(false);const sidebar=document.getElementsByClassName("sidebar")[0];addClass(sidebar,"shown")}function hideSidebar(){const sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"shown")}window.addEventListener("resize",()=>{if(window.CURRENT_TOOLTIP_ELEMENT){const base=window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;const force_visible=base.TOOLTIP_FORCE_VISIBLE;hideTooltip(false);if(force_visible){showTooltip(base);base.TOOLTIP_FORCE_VISIBLE=true}}});const mainElem=document.getElementById(MAIN_ID);if(mainElem){mainElem.addEventListener("click",hideSidebar)}onEachLazy(document.querySelectorAll("a[href^='#']"),el=>{el.addEventListener("click",()=>{expandSection(el.hash.slice(1));hideSidebar()})});onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"),el=>{el.addEventListener("click",e=>{if(e.target.tagName!=="SUMMARY"&&e.target.tagName!=="A"){e.preventDefault()}})});function showTooltip(e){const notable_ty=e.getAttribute("data-notable-ty");if(!window.NOTABLE_TRAITS&¬able_ty){const data=document.getElementById("notable-traits-data");if(data){window.NOTABLE_TRAITS=JSON.parse(data.innerText)}else{throw new Error("showTooltip() called with notable without any notable traits!")}}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE===e){clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);return}window.hideAllModals(false);const wrapper=document.createElement("div");if(notable_ty){wrapper.innerHTML="
"+window.NOTABLE_TRAITS[notable_ty]+"
"}else{if(e.getAttribute("title")!==null){e.setAttribute("data-title",e.getAttribute("title"));e.removeAttribute("title")}if(e.getAttribute("data-title")!==null){const titleContent=document.createElement("div");titleContent.className="content";titleContent.appendChild(document.createTextNode(e.getAttribute("data-title")));wrapper.appendChild(titleContent)}}wrapper.className="tooltip popover";const focusCatcher=document.createElement("div");focusCatcher.setAttribute("tabindex","0");focusCatcher.onfocus=hideTooltip;wrapper.appendChild(focusCatcher);const pos=e.getBoundingClientRect();wrapper.style.top=(pos.top+window.scrollY+pos.height)+"px";wrapper.style.left=0;wrapper.style.right="auto";wrapper.style.visibility="hidden";const body=document.getElementsByTagName("body")[0];body.appendChild(wrapper);const wrapperPos=wrapper.getBoundingClientRect();const finalPos=pos.left+window.scrollX-wrapperPos.width+24;if(finalPos>0){wrapper.style.left=finalPos+"px"}else{wrapper.style.setProperty("--popover-arrow-offset",(wrapperPos.right-pos.right+4)+"px")}wrapper.style.visibility="";window.CURRENT_TOOLTIP_ELEMENT=wrapper;window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE=e;clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);wrapper.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}clearTooltipHoverTimeout(e)};wrapper.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&!elemIsInParent(ev.relatedTarget,e)){setTooltipHoverTimeout(e,false);addClass(wrapper,"fade-out")}}}function setTooltipHoverTimeout(element,show){clearTooltipHoverTimeout(element);if(!show&&!window.CURRENT_TOOLTIP_ELEMENT){return}if(show&&window.CURRENT_TOOLTIP_ELEMENT){return}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE!==element){return}element.TOOLTIP_HOVER_TIMEOUT=setTimeout(()=>{if(show){showTooltip(element)}else if(!element.TOOLTIP_FORCE_VISIBLE){hideTooltip(false)}},show?window.RUSTDOC_TOOLTIP_HOVER_MS:window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS)}function clearTooltipHoverTimeout(element){if(element.TOOLTIP_HOVER_TIMEOUT!==undefined){removeClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out");clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);delete element.TOOLTIP_HOVER_TIMEOUT}}function tooltipBlurHandler(event){if(window.CURRENT_TOOLTIP_ELEMENT&&!elemIsInParent(document.activeElement,window.CURRENT_TOOLTIP_ELEMENT)&&!elemIsInParent(event.relatedTarget,window.CURRENT_TOOLTIP_ELEMENT)&&!elemIsInParent(document.activeElement,window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE)&&!elemIsInParent(event.relatedTarget,window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE)){setTimeout(()=>hideTooltip(false),0)}}function hideTooltip(focus){if(window.CURRENT_TOOLTIP_ELEMENT){if(window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE){if(focus){window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus()}window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE=false}const body=document.getElementsByTagName("body")[0];body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);window.CURRENT_TOOLTIP_ELEMENT=null}}onEachLazy(document.getElementsByClassName("tooltip"),e=>{e.onclick=()=>{e.TOOLTIP_FORCE_VISIBLE=e.TOOLTIP_FORCE_VISIBLE?false:true;if(window.CURRENT_TOOLTIP_ELEMENT&&!e.TOOLTIP_FORCE_VISIBLE){hideTooltip(true)}else{showTooltip(e);window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex","0");window.CURRENT_TOOLTIP_ELEMENT.focus();window.CURRENT_TOOLTIP_ELEMENT.onblur=tooltipBlurHandler}return false};e.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointermove=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&!elemIsInParent(ev.relatedTarget,window.CURRENT_TOOLTIP_ELEMENT)){setTooltipHoverTimeout(e,false);addClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out")}}});const sidebar_menu_toggle=document.getElementsByClassName("sidebar-menu-toggle")[0];if(sidebar_menu_toggle){sidebar_menu_toggle.addEventListener("click",()=>{const sidebar=document.getElementsByClassName("sidebar")[0];if(!hasClass(sidebar,"shown")){showSidebar()}else{hideSidebar()}})}function helpBlurHandler(event){blurHandler(event,getHelpButton(),window.hidePopoverMenus)}function buildHelpMenu(){const book_info=document.createElement("span");const channel=getVar("channel");book_info.className="top";book_info.innerHTML=`You can find more information in \ +the rustdoc book.`;const shortcuts=[["?","Show this help dialog"],["S","Focus the search field"],["↑","Move up in search results"],["↓","Move down in search results"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(x=>"
"+x[0].split(" ").map((y,index)=>((index&1)===0?""+y+"":" "+y+" ")).join("")+"
"+x[1]+"
").join("");const div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";const infos=[`For a full list of all search features, take a look here.`,"Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + -> vec or String, enum:Cow -> bool)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"","Look for functions that accept or return \ + slices and \ + arrays by writing \ + square brackets (e.g., -> [u8] or [] -> Option)","Look for items inside another one by searching for a path: vec::Vec",].map(x=>"

"+x+"

").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;const rustdoc_version=document.createElement("span");rustdoc_version.className="bottom";const rustdoc_version_code=document.createElement("code");rustdoc_version_code.innerText="rustdoc "+getVar("rustdoc-version");rustdoc_version.appendChild(rustdoc_version_code);const container=document.createElement("div");if(!isHelpPage){container.className="popover"}container.id="help";container.style.display="none";const side_by_side=document.createElement("div");side_by_side.className="side-by-side";side_by_side.appendChild(div_shortcuts);side_by_side.appendChild(div_infos);container.appendChild(book_info);container.appendChild(side_by_side);container.appendChild(rustdoc_version);if(isHelpPage){const help_section=document.createElement("section");help_section.appendChild(container);document.getElementById("main-content").appendChild(help_section);container.style.display="block"}else{const help_button=getHelpButton();help_button.appendChild(container);container.onblur=helpBlurHandler;help_button.onblur=helpBlurHandler;help_button.children[0].onblur=helpBlurHandler}return container}window.hideAllModals=switchFocus=>{hideSidebar();window.hidePopoverMenus();hideTooltip(switchFocus)};window.hidePopoverMenus=()=>{onEachLazy(document.querySelectorAll(".search-form .popover"),elem=>{elem.style.display="none"})};function getHelpMenu(buildNeeded){let menu=getHelpButton().querySelector(".popover");if(!menu&&buildNeeded){menu=buildHelpMenu()}return menu}function showHelp(){getHelpButton().querySelector("a").focus();const menu=getHelpMenu(true);if(menu.style.display==="none"){window.hideAllModals();menu.style.display=""}}if(isHelpPage){showHelp();document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault()})}else{document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault();const menu=getHelpMenu(true);const shouldShowHelp=menu.style.display==="none";if(shouldShowHelp){showHelp()}else{window.hidePopoverMenus()}})}setMobileTopbar();addSidebarItems();addSidebarCrates();onHashChange(null);window.addEventListener("hashchange",onHashChange);searchState.setup()}());(function(){let reset_button_timeout=null;const but=document.getElementById("copy-path");if(!but){return}but.onclick=()=>{const parent=but.parentElement;const path=[];onEach(parent.childNodes,child=>{if(child.tagName==="A"){path.push(child.textContent)}});const el=document.createElement("textarea");el.value=path.join("::");el.setAttribute("readonly","");el.style.position="absolute";el.style.left="-9999px";document.body.appendChild(el);el.select();document.execCommand("copy");document.body.removeChild(el);but.children[0].style.display="none";let tmp;if(but.childNodes.length<2){tmp=document.createTextNode("✓");but.appendChild(tmp)}else{onEachLazy(but.childNodes,e=>{if(e.nodeType===Node.TEXT_NODE){tmp=e;return true}});tmp.textContent="✓"}if(reset_button_timeout!==null){window.clearTimeout(reset_button_timeout)}function reset_button(){tmp.textContent="";reset_button_timeout=null;but.children[0].style.display=""}reset_button_timeout=window.setTimeout(reset_button,1000)}}()) \ No newline at end of file diff --git a/docs/static.files/normalize-76eba96aa4d2e634.css b/docs/static.files/normalize-76eba96aa4d2e634.css new file mode 100644 index 000000000..469959f13 --- /dev/null +++ b/docs/static.files/normalize-76eba96aa4d2e634.css @@ -0,0 +1,2 @@ + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} \ No newline at end of file diff --git a/docs/static.files/noscript-5d8b3c7633ad77ba.css b/docs/static.files/noscript-5d8b3c7633ad77ba.css new file mode 100644 index 000000000..8c63ef065 --- /dev/null +++ b/docs/static.files/noscript-5d8b3c7633ad77ba.css @@ -0,0 +1 @@ + #main-content .attributes{margin-left:0 !important;}#copy-path{display:none;}nav.sub{display:none;}.src .sidebar{display:none;}.notable-traits{display:none;}:root{--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);}@media (prefers-color-scheme:dark){:root{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);}} \ No newline at end of file diff --git a/docs/static.files/rust-logo-151179464ae7ed46.svg b/docs/static.files/rust-logo-151179464ae7ed46.svg new file mode 100644 index 000000000..62424d8ff --- /dev/null +++ b/docs/static.files/rust-logo-151179464ae7ed46.svg @@ -0,0 +1,61 @@ + + + diff --git a/docs/static.files/rustdoc-fa3bb1812debf86c.css b/docs/static.files/rustdoc-fa3bb1812debf86c.css new file mode 100644 index 000000000..2dd5cebca --- /dev/null +++ b/docs/static.files/rustdoc-fa3bb1812debf86c.css @@ -0,0 +1,10 @@ + :root{--nav-sub-mobile-padding:8px;--search-typename-width:6.75rem;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular-018c141bf0843ffd.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium-8f9a781e4970d388.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular-46f98efaafac5295.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'NanumBarunGothic';src:url("NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2") format("woff2");font-display:swap;unicode-range:U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF;}*{box-sizing:border-box;}body{font:1rem/1.5 "Source Serif 4",NanumBarunGothic,serif;margin:0;position:relative;overflow-wrap:break-word;overflow-wrap:anywhere;font-feature-settings:"kern","liga";background-color:var(--main-background-color);color:var(--main-color);}h1{font-size:1.5rem;}h2{font-size:1.375rem;}h3{font-size:1.25rem;}h1,h2,h3,h4,h5,h6{font-weight:500;}h1,h2,h3,h4{margin:25px 0 15px 0;padding-bottom:6px;}.docblock h3,.docblock h4,h5,h6{margin:15px 0 5px 0;}.docblock>h2:first-child,.docblock>h3:first-child,.docblock>h4:first-child,.docblock>h5:first-child,.docblock>h6:first-child{margin-top:0;}.main-heading h1{margin:0;padding:0;flex-grow:1;overflow-wrap:break-word;overflow-wrap:anywhere;}.main-heading{display:flex;flex-wrap:wrap;padding-bottom:6px;margin-bottom:15px;}.content h2,.top-doc .docblock>h3,.top-doc .docblock>h4{border-bottom:1px solid var(--headings-border-bottom-color);}h1,h2{line-height:1.25;padding-top:3px;padding-bottom:9px;}h3.code-header{font-size:1.125rem;}h4.code-header{font-size:1rem;}.code-header{font-weight:600;margin:0;padding:0;white-space:pre-wrap;}#crate-search,h1,h2,h3,h4,h5,h6,.sidebar,.mobile-topbar,.search-input,.search-results .result-name,.item-name>a,.out-of-band,span.since,a.src,#help-button>a,summary.hideme,.scraped-example-list,ul.all-items{font-family:"Fira Sans",Arial,NanumBarunGothic,sans-serif;}#toggle-all-docs,a.anchor,.small-section-header a,#src-sidebar a,.rust a,.sidebar h2 a,.sidebar h3 a,.mobile-topbar h2 a,h1 a,.search-results a,.stab,.result-name i{color:var(--main-color);}span.enum,a.enum,span.struct,a.struct,span.union,a.union,span.primitive,a.primitive,span.type,a.type,span.foreigntype,a.foreigntype{color:var(--type-link-color);}span.trait,a.trait,span.traitalias,a.traitalias{color:var(--trait-link-color);}span.associatedtype,a.associatedtype,span.constant,a.constant,span.static,a.static{color:var(--assoc-item-link-color);}span.fn,a.fn,span.method,a.method,span.tymethod,a.tymethod{color:var(--function-link-color);}span.attr,a.attr,span.derive,a.derive,span.macro,a.macro{color:var(--macro-link-color);}span.mod,a.mod{color:var(--mod-link-color);}span.keyword,a.keyword{color:var(--keyword-link-color);}a{color:var(--link-color);text-decoration:none;}ol,ul{padding-left:24px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.625em;}p,.docblock>.warning{margin:0 0 .75em 0;}p:last-child,.docblock>.warning:last-child{margin:0;}button{padding:1px 6px;cursor:pointer;}button#toggle-all-docs{padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.rustdoc{display:flex;flex-direction:row;flex-wrap:nowrap;}main{position:relative;flex-grow:1;padding:10px 15px 40px 45px;min-width:0;}.src main{padding:15px;}.width-limiter{max-width:960px;margin-right:auto;}details:not(.toggle) summary{margin-bottom:.6em;}code,pre,a.test-arrow,.code-header{font-family:"Source Code Pro",monospace;}.docblock code,.docblock-short code{border-radius:3px;padding:0 0.125em;}.docblock pre code,.docblock-short pre code{padding:0;}pre{padding:14px;line-height:1.5;}pre.item-decl{overflow-x:auto;}.item-decl .type-contents-toggle{contain:initial;}.src .content pre{padding:20px;}.rustdoc.src .example-wrap pre.src-line-numbers{padding:20px 0 20px 4px;}img{max-width:100%;}.sub-logo-container,.logo-container{line-height:0;display:block;}.sub-logo-container{margin-right:32px;}.sub-logo-container>img{height:60px;width:60px;object-fit:contain;}.rust-logo{filter:var(--rust-logo-filter);}.sidebar{font-size:0.875rem;flex:0 0 200px;overflow-y:scroll;overscroll-behavior:contain;position:sticky;height:100vh;top:0;left:0;}.rustdoc.src .sidebar{flex-basis:50px;border-right:1px solid;overflow-x:hidden;overflow-y:hidden;z-index:1;}.sidebar,.mobile-topbar,.sidebar-menu-toggle,#src-sidebar-toggle,#src-sidebar{background-color:var(--sidebar-background-color);}#src-sidebar-toggle>button:hover,#src-sidebar-toggle>button:focus{background-color:var(--sidebar-background-color-hover);}.src .sidebar>*:not(#src-sidebar-toggle){visibility:hidden;}.src-sidebar-expanded .src .sidebar{overflow-y:auto;flex-basis:300px;}.src-sidebar-expanded .src .sidebar>*:not(#src-sidebar-toggle){visibility:visible;}#all-types{margin-top:1em;}*{scrollbar-width:initial;scrollbar-color:var(--scrollbar-color);}.sidebar{scrollbar-width:thin;scrollbar-color:var(--scrollbar-color);}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;background-color:var(--scrollbar-track-background-color);}.sidebar::-webkit-scrollbar-track{background-color:var(--scrollbar-track-background-color);}::-webkit-scrollbar-thumb,.sidebar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-background-color);}.hidden{display:none !important;}.sidebar .logo-container{margin-top:10px;margin-bottom:10px;text-align:center;}.version{overflow-wrap:break-word;}.logo-container>img{height:100px;width:100px;}ul.block,.block li{padding:0;margin:0;list-style:none;}.sidebar-elems a,.sidebar>h2 a{display:block;padding:0.25rem;margin-left:-0.25rem;}.sidebar h2{overflow-wrap:anywhere;padding:0;margin:0.7rem 0;}.sidebar h3{font-size:1.125rem;padding:0;margin:0;}.sidebar-elems,.sidebar>h2{padding-left:24px;}.sidebar a{color:var(--sidebar-link-color);}.sidebar .current,.sidebar a:hover:not(.logo-container){background-color:var(--sidebar-current-link-background-color);}.sidebar-elems .block{margin-bottom:2em;}.sidebar-elems .block li a{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}.mobile-topbar{display:none;}.rustdoc .example-wrap{display:flex;position:relative;margin-bottom:10px;}.rustdoc .example-wrap:last-child{margin-bottom:0px;}.rustdoc .example-wrap pre{margin:0;flex-grow:1;}.rustdoc:not(.src) .example-wrap pre{overflow:auto hidden;}.rustdoc .example-wrap pre.example-line-numbers,.rustdoc .example-wrap pre.src-line-numbers{flex-grow:0;min-width:fit-content;overflow:initial;text-align:right;-webkit-user-select:none;user-select:none;padding:14px 8px;color:var(--src-line-numbers-span-color);}.rustdoc .example-wrap pre.src-line-numbers{padding:14px 0;}.src-line-numbers a,.src-line-numbers span{color:var(--src-line-numbers-span-color);padding:0 8px;}.src-line-numbers :target{background-color:transparent;border-right:none;padding:0 8px;}.src-line-numbers .line-highlighted{background-color:var(--src-line-number-highlighted-background-color);}.search-loading{text-align:center;}.docblock-short{overflow-wrap:break-word;overflow-wrap:anywhere;}.docblock :not(pre)>code,.docblock-short code{white-space:pre-wrap;}.top-doc .docblock h2{font-size:1.375rem;}.top-doc .docblock h3{font-size:1.25rem;}.top-doc .docblock h4,.top-doc .docblock h5{font-size:1.125rem;}.top-doc .docblock h6{font-size:1rem;}.docblock h5{font-size:1rem;}.docblock h6{font-size:0.875rem;}.docblock{margin-left:24px;position:relative;}.docblock>:not(.more-examples-toggle):not(.example-wrap){max-width:100%;overflow-x:auto;}.out-of-band{flex-grow:0;font-size:1.125rem;}.docblock code,.docblock-short code,pre,.rustdoc.src .example-wrap{background-color:var(--code-block-background-color);}#main-content{position:relative;}.docblock table{margin:.5em 0;border-collapse:collapse;}.docblock table td,.docblock table th{padding:.5em;border:1px solid var(--border-color);}.docblock table tbody tr:nth-child(2n){background:var(--table-alt-row-background-color);}.method .where,.fn .where,.where.fmt-newline{display:block;white-space:pre-wrap;font-size:0.875rem;}.item-info{display:block;margin-left:24px;}.item-info code{font-size:0.875rem;}#main-content>.item-info{margin-left:0;}nav.sub{flex-grow:1;flex-flow:row nowrap;margin:4px 0 25px 0;display:flex;align-items:center;}.search-form{position:relative;display:flex;height:34px;flex-grow:1;}.src nav.sub{margin:0 0 15px 0;}.small-section-header{display:block;position:relative;}.small-section-header:hover>.anchor,.impl:hover>.anchor,.trait-impl:hover>.anchor,.variant:hover>.anchor{display:initial;}.anchor{display:none;position:absolute;left:-0.5em;background:none !important;}.anchor.field{left:-5px;}.small-section-header>.anchor{left:-15px;padding-right:8px;}h2.small-section-header>.anchor{padding-right:6px;}.main-heading a:hover,.example-wrap .rust a:hover,.all-items a:hover,.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,.item-info a{text-decoration:underline;}.crate.block a.current{font-weight:500;}table,.item-table{overflow-wrap:break-word;}.item-table{display:table;padding:0;margin:0;}.item-table>li{display:table-row;}.item-table>li>div{display:table-cell;}.item-table>li>.item-name{padding-right:1.25rem;}.search-results-title{margin-top:0;white-space:nowrap;display:flex;align-items:baseline;}#crate-search-div{position:relative;min-width:5em;}#crate-search{min-width:115px;padding:0 23px 0 4px;max-width:100%;text-overflow:ellipsis;border:1px solid var(--border-color);border-radius:4px;outline:none;cursor:pointer;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;background-color:var(--main-background-color);color:inherit;line-height:1.5;font-weight:500;}#crate-search:hover,#crate-search:focus{border-color:var(--crate-search-hover-border);}#crate-search-div::after{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0;content:"";background-repeat:no-repeat;background-size:20px;background-position:calc(100% - 2px) 56%;background-image:url('data:image/svg+xml, \ + ');filter:var(--crate-search-div-filter);}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:var(--crate-search-div-hover-filter);}#crate-search>option{font-size:1rem;}.search-input{-webkit-appearance:none;outline:none;border:1px solid var(--border-color);border-radius:2px;padding:8px;font-size:1rem;flex-grow:1;background-color:var(--button-background-color);color:var(--search-color);}.search-input:focus{border-color:var(--search-input-focused-border-color);}.search-results{display:none;}.search-results.active{display:block;}.search-results>a{display:flex;margin-left:2px;margin-right:2px;border-bottom:1px solid var(--search-result-border-color);gap:1em;}.search-results>a>div.desc{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex:2;}.search-results a:hover,.search-results a:focus{background-color:var(--search-result-link-focus-background-color);}.search-results .result-name{display:flex;align-items:center;justify-content:start;flex:3;}.search-results .result-name .alias{color:var(--search-results-alias-color);}.search-results .result-name .grey{color:var(--search-results-grey-color);}.search-results .result-name .typename{color:var(--search-results-grey-color);font-size:0.875rem;width:var(--search-typename-width);}.search-results .result-name .path{word-break:break-all;max-width:calc(100% - var(--search-typename-width));display:inline-block;}.search-results .result-name .path>*{display:inline;}.popover{position:absolute;top:100%;right:0;z-index:2;margin-top:7px;border-radius:3px;border:1px solid var(--border-color);background-color:var(--main-background-color);color:var(--main-color);--popover-arrow-offset:11px;}.popover::before{content:'';position:absolute;right:var(--popover-arrow-offset);border:solid var(--border-color);border-width:1px 1px 0 0;background-color:var(--main-background-color);padding:4px;transform:rotate(-45deg);top:-5px;}.setting-line{margin:1.2em 0.6em;}.setting-radio input,.setting-check input{margin-right:0.3em;height:1.2rem;width:1.2rem;border:2px solid var(--settings-input-border-color);outline:none;-webkit-appearance:none;cursor:pointer;}.setting-radio input{border-radius:50%;}.setting-radio span,.setting-check span{padding-bottom:1px;}.setting-radio{margin-top:0.1em;margin-bottom:0.1em;min-width:3.8em;padding:0.3em;display:inline-flex;align-items:center;cursor:pointer;}.setting-radio+.setting-radio{margin-left:0.5em;}.setting-check{margin-right:20px;display:flex;align-items:center;cursor:pointer;}.setting-radio input:checked{box-shadow:inset 0 0 0 3px var(--main-background-color);background-color:var(--settings-input-color);}.setting-check input:checked{background-color:var(--settings-input-color);border-width:1px;content:url('data:image/svg+xml,\ + \ + ');}.setting-radio input:focus,.setting-check input:focus{box-shadow:0 0 1px 1px var(--settings-input-color);}.setting-radio input:checked:focus{box-shadow:inset 0 0 0 3px var(--main-background-color),0 0 2px 2px var(--settings-input-color);}.setting-radio input:hover,.setting-check input:hover{border-color:var(--settings-input-color) !important;}#help.popover{max-width:600px;--popover-arrow-offset:48px;}#help dt{float:left;clear:left;margin-right:0.5rem;}#help span.top,#help span.bottom{text-align:center;display:block;font-size:1.125rem;}#help span.top{margin:10px 0;border-bottom:1px solid var(--border-color);padding-bottom:4px;margin-bottom:6px;}#help span.bottom{clear:both;border-top:1px solid var(--border-color);}.side-by-side>div{width:50%;float:left;padding:0 20px 20px 17px;}.item-info .stab{min-height:36px;display:flex;padding:3px;margin-bottom:5px;align-items:center;vertical-align:text-bottom;}.item-name .stab{margin-left:0.3125em;}.stab{padding:0 2px;font-size:0.875rem;font-weight:normal;color:var(--main-color);background-color:var(--stab-background-color);width:fit-content;white-space:pre-wrap;border-radius:3px;display:inline;}.stab.portability>code{background:none;color:var(--stab-code-color);}.stab .emoji{font-size:1.25rem;margin-right:0.3rem;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.since{font-weight:normal;font-size:initial;}.rightside{padding-left:12px;float:right;}.rightside:not(a),.out-of-band{color:var(--right-side-color);}pre.rust{tab-size:4;-moz-tab-size:4;}pre.rust .kw{color:var(--code-highlight-kw-color);}pre.rust .kw-2{color:var(--code-highlight-kw-2-color);}pre.rust .lifetime{color:var(--code-highlight-lifetime-color);}pre.rust .prelude-ty{color:var(--code-highlight-prelude-color);}pre.rust .prelude-val{color:var(--code-highlight-prelude-val-color);}pre.rust .string{color:var(--code-highlight-string-color);}pre.rust .number{color:var(--code-highlight-number-color);}pre.rust .bool-val{color:var(--code-highlight-literal-color);}pre.rust .self{color:var(--code-highlight-self-color);}pre.rust .attr{color:var(--code-highlight-attribute-color);}pre.rust .macro,pre.rust .macro-nonterminal{color:var(--code-highlight-macro-color);}pre.rust .question-mark{font-weight:bold;color:var(--code-highlight-question-mark-color);}pre.rust .comment{color:var(--code-highlight-comment-color);}pre.rust .doccomment{color:var(--code-highlight-doc-comment-color);}.rustdoc.src .example-wrap pre.rust a{background:var(--codeblock-link-background);}.example-wrap.compile_fail,.example-wrap.should_panic{border-left:2px solid var(--codeblock-error-color);}.ignore.example-wrap{border-left:2px solid var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover,.example-wrap.should_panic:hover{border-left:2px solid var(--codeblock-error-hover-color);}.example-wrap.ignore:hover{border-left:2px solid var(--codeblock-ignore-hover-color);}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip{color:var(--codeblock-error-color);}.example-wrap.ignore .tooltip{color:var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover .tooltip,.example-wrap.should_panic:hover .tooltip{color:var(--codeblock-error-hover-color);}.example-wrap.ignore:hover .tooltip{color:var(--codeblock-ignore-hover-color);}.example-wrap .tooltip{position:absolute;display:block;left:-25px;top:5px;margin:0;line-height:1;}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip,.example-wrap.ignore .tooltip{font-weight:bold;font-size:1.25rem;}.content .docblock .warning{border-left:2px solid var(--warning-border-color);padding:14px;position:relative;overflow-x:visible !important;}.content .docblock .warning::before{color:var(--warning-border-color);content:"ⓘ";position:absolute;left:-25px;top:5px;font-weight:bold;font-size:1.25rem;}a.test-arrow{visibility:hidden;position:absolute;padding:5px 10px 5px 10px;border-radius:5px;font-size:1.375rem;top:5px;right:5px;z-index:1;color:var(--test-arrow-color);background-color:var(--test-arrow-background-color);}a.test-arrow:hover{color:var(--test-arrow-hover-color);background-color:var(--test-arrow-hover-background-color);}.example-wrap:hover .test-arrow{visibility:visible;}.code-attribute{font-weight:300;color:var(--code-attribute-color);}.item-spacer{width:100%;height:12px;display:block;}.out-of-band>span.since{font-size:1.25rem;}.sub-variant h4{font-size:1rem;font-weight:400;margin-top:0;margin-bottom:0;}.sub-variant{margin-left:24px;margin-bottom:40px;}.sub-variant>.sub-variant-field{margin-left:24px;}:target{padding-right:3px;background-color:var(--target-background-color);border-right:3px solid var(--target-border-color);}.code-header a.tooltip{color:inherit;margin-right:15px;position:relative;}.code-header a.tooltip:hover{color:var(--link-color);}a.tooltip:hover::after{position:absolute;top:calc(100% - 10px);left:-15px;right:-15px;height:20px;content:"\00a0";}.fade-out{opacity:0;transition:opacity 0.45s cubic-bezier(0,0,0.1,1.0);}.popover.tooltip .content{margin:0.25em 0.5em;}.popover.tooltip .content pre,.popover.tooltip .content code{background:transparent;margin:0;padding:0;font-size:1.25rem;white-space:pre-wrap;}.popover.tooltip .content>h3:first-child{margin:0 0 5px 0;}.search-failed{text-align:center;margin-top:20px;display:none;}.search-failed.active{display:block;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#search-tabs{display:flex;flex-direction:row;gap:1px;margin-bottom:4px;}#search-tabs button{text-align:center;font-size:1.125rem;border:0;border-top:2px solid;flex:1;line-height:1.5;color:inherit;}#search-tabs button:not(.selected){background-color:var(--search-tab-button-not-selected-background);border-top-color:var(--search-tab-button-not-selected-border-top-color);}#search-tabs button:hover,#search-tabs button.selected{background-color:var(--search-tab-button-selected-background);border-top-color:var(--search-tab-button-selected-border-top-color);}#search-tabs .count{font-size:1rem;font-variant-numeric:tabular-nums;color:var(--search-tab-title-count-color);}#search .error code{border-radius:3px;background-color:var(--search-error-code-background-color);}.search-corrections{font-weight:normal;}#src-sidebar-toggle{position:sticky;top:0;left:0;font-size:1.25rem;border-bottom:1px solid;display:flex;height:40px;justify-content:stretch;align-items:stretch;z-index:10;}#src-sidebar{width:100%;overflow:auto;}#src-sidebar>.title{font-size:1.5rem;text-align:center;border-bottom:1px solid var(--border-color);margin-bottom:6px;}#src-sidebar div.files>a:hover,details.dir-entry summary:hover,#src-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:var(--src-sidebar-background-hover);}#src-sidebar div.files>a.selected{background-color:var(--src-sidebar-background-selected);}#src-sidebar-toggle>button{font-size:inherit;font-weight:bold;background:none;color:inherit;text-align:center;border:none;outline:none;flex:1 1;-webkit-appearance:none;opacity:1;}#settings-menu,#help-button{margin-left:4px;display:flex;}#settings-menu>a,#help-button>a{display:flex;align-items:center;justify-content:center;background-color:var(--button-background-color);border:1px solid var(--border-color);border-radius:2px;color:var(--settings-button-color);font-size:20px;width:33px;}#settings-menu>a:hover,#settings-menu>a:focus,#help-button>a:hover,#help-button>a:focus{border-color:var(--settings-button-border-focus);}#copy-path{color:var(--copy-path-button-color);background:var(--main-background-color);height:34px;margin-left:10px;padding:0;padding-left:2px;border:0;width:33px;}#copy-path>img{filter:var(--copy-path-img-filter);}#copy-path:hover>img{filter:var(--copy-path-img-hover-filter);}@keyframes rotating{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}#settings-menu.rotate>a img{animation:rotating 2s linear infinite;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px var(--border-color);border-radius:3px;color:var(--kbd-color);background-color:var(--kbd-background);box-shadow:inset 0 -1px 0 var(--kbd-box-shadow-color);}ul.all-items>li{list-style:none;}details.dir-entry{padding-left:4px;}details.dir-entry>summary{margin:0 0 0 -4px;padding:0 0 0 4px;cursor:pointer;}details.dir-entry div.folders,details.dir-entry div.files{padding-left:23px;}details.dir-entry a{display:block;}details.toggle{contain:layout;position:relative;}details.toggle>summary.hideme{cursor:pointer;font-size:1rem;}details.toggle>summary{list-style:none;outline:none;}details.toggle>summary::-webkit-details-marker,details.toggle>summary::marker{display:none;}details.toggle>summary.hideme>span{margin-left:9px;}details.toggle>summary::before{background:url('data:image/svg+xml,') no-repeat top left;content:"";cursor:pointer;width:16px;height:16px;display:inline-block;vertical-align:middle;opacity:.5;filter:var(--toggle-filter);}details.toggle>summary.hideme>span,.more-examples-toggle summary,.more-examples-toggle .hide-more{color:var(--toggles-color);}details.toggle>summary::after{content:"Expand";overflow:hidden;width:0;height:0;position:absolute;}details.toggle>summary.hideme::after{content:"";}details.toggle>summary:focus::before,details.toggle>summary:hover::before{opacity:1;}details.toggle>summary:focus-visible::before{outline:1px dotted #000;outline-offset:1px;}details.non-exhaustive{margin-bottom:8px;}details.toggle>summary.hideme::before{position:relative;}details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;top:4px;}.impl-items>details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;}details.toggle[open] >summary.hideme{position:absolute;}details.toggle[open] >summary.hideme>span{display:none;}details.toggle[open] >summary::before{background:url('data:image/svg+xml,') no-repeat top left;}details.toggle[open] >summary::after{content:"Collapse";}.docblock summary>*{display:inline-block;}.docblock>.example-wrap:first-child .tooltip{margin-top:16px;}@media (max-width:850px){#search-tabs .count{display:block;}}@media (max-width:700px){*[id]{scroll-margin-top:45px;}.rustdoc{display:block;}main{padding-left:15px;padding-top:0px;}.main-heading{flex-direction:column;}.out-of-band{text-align:left;margin-left:initial;padding:initial;}.out-of-band .since::before{content:"Since ";}.sidebar .logo-container,.sidebar .location{display:none;}.sidebar{position:fixed;top:45px;left:-1000px;z-index:11;height:calc(100vh - 45px);width:200px;}.src main,.rustdoc.src .sidebar{top:0;padding:0;height:100vh;border:0;}.sidebar.shown,.src-sidebar-expanded .src .sidebar,.rustdoc:not(.src) .sidebar:focus-within{left:0;}.mobile-topbar h2{padding-bottom:0;margin:auto 0.5em auto auto;overflow:hidden;font-size:24px;}.mobile-topbar h2 a{display:block;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;}.mobile-topbar .logo-container>img{max-width:35px;max-height:35px;margin:5px 0 5px 20px;}.mobile-topbar{display:flex;flex-direction:row;position:sticky;z-index:10;font-size:2rem;height:45px;width:100%;left:0;top:0;}.sidebar-menu-toggle{width:45px;font-size:32px;border:none;color:var(--main-color);}.sidebar-elems{margin-top:1em;}.anchor{display:none !important;}#main-content>details.toggle>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}#src-sidebar-toggle{position:fixed;left:1px;top:100px;width:30px;font-size:1.5rem;padding:0;z-index:10;border-top-right-radius:3px;border-bottom-right-radius:3px;border:1px solid;border-left:0;}.src-sidebar-expanded #src-sidebar-toggle{left:unset;top:unset;width:unset;border-top-right-radius:unset;border-bottom-right-radius:unset;position:sticky;border:0;border-bottom:1px solid;}#copy-path,#help-button{display:none;}.item-table,.item-row,.item-table>li,.item-table>li>div,.search-results>a,.search-results>a>div{display:block;}.search-results>a{padding:5px 0px;}.search-results>a>div.desc,.item-table>li>div.desc{padding-left:2em;}.search-results .result-name{display:block;}.search-results .result-name .typename{width:initial;margin-right:0;}.search-results .result-name .typename,.search-results .result-name .path{display:inline;}.src-sidebar-expanded .src .sidebar{max-width:100vw;width:100vw;}details.toggle:not(.top-doc)>summary{margin-left:10px;}.impl-items>details.toggle>summary:not(.hideme)::before,#main-content>details.toggle:not(.top-doc)>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}.impl-items>.item-info{margin-left:34px;}.src nav.sub{margin:0;padding:var(--nav-sub-mobile-padding);}}@media (min-width:701px){.scraped-example-title{position:absolute;z-index:10;background:var(--main-background-color);bottom:8px;right:5px;padding:2px 4px;box-shadow:0 0 4px var(--main-background-color);}}@media print{nav.sidebar,nav.sub,.out-of-band,a.src,#copy-path,details.toggle[open] >summary::before,details.toggle>summary::before,details.toggle.top-doc>summary{display:none;}.docblock{margin-left:0;}main{padding:10px;}}@media (max-width:464px){.docblock{margin-left:12px;}.docblock code{overflow-wrap:break-word;overflow-wrap:anywhere;}nav.sub{flex-direction:column;}.search-form{align-self:stretch;}.sub-logo-container>img{height:35px;width:35px;margin-bottom:var(--nav-sub-mobile-padding);}}.variant,.implementors-toggle>summary,.impl,#implementors-list>.docblock,.impl-items>section,.impl-items>.toggle>summary,.methods>section,.methods>.toggle>summary{margin-bottom:0.75em;}.variants>.docblock,.implementors-toggle>.docblock,.impl-items>.toggle[open]:not(:last-child),.methods>.toggle[open]:not(:last-child),.implementors-toggle[open]:not(:last-child){margin-bottom:2em;}#trait-implementations-list .impl-items>.toggle:not(:last-child),#synthetic-implementations-list .impl-items>.toggle:not(:last-child),#blanket-implementations-list .impl-items>.toggle:not(:last-child){margin-bottom:1em;}.scraped-example-list .scrape-help{margin-left:10px;padding:0 4px;font-weight:normal;font-size:12px;position:relative;bottom:1px;border:1px solid var(--scrape-example-help-border-color);border-radius:50px;color:var(--scrape-example-help-color);}.scraped-example-list .scrape-help:hover{border-color:var(--scrape-example-help-hover-border-color);color:var(--scrape-example-help-hover-color);}.scraped-example{position:relative;}.scraped-example .code-wrapper{position:relative;display:flex;flex-direction:row;flex-wrap:wrap;width:100%;}.scraped-example:not(.expanded) .code-wrapper{max-height:calc(1.5em * 5 + 10px);}.scraped-example:not(.expanded) .code-wrapper pre{overflow-y:hidden;padding-bottom:0;max-height:calc(1.5em * 5 + 10px);}.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper,.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper pre{max-height:calc(1.5em * 10 + 10px);}.scraped-example .code-wrapper .next,.scraped-example .code-wrapper .prev,.scraped-example .code-wrapper .expand{color:var(--main-color);position:absolute;top:0.25em;z-index:1;padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.scraped-example .code-wrapper .prev{right:2.25em;}.scraped-example .code-wrapper .next{right:1.25em;}.scraped-example .code-wrapper .expand{right:0.25em;}.scraped-example:not(.expanded) .code-wrapper::before,.scraped-example:not(.expanded) .code-wrapper::after{content:" ";width:100%;height:5px;position:absolute;z-index:1;}.scraped-example:not(.expanded) .code-wrapper::before{top:0;background:linear-gradient(to bottom,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example:not(.expanded) .code-wrapper::after{bottom:0;background:linear-gradient(to top,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example .code-wrapper .example-wrap{width:100%;overflow-y:hidden;margin-bottom:0;}.scraped-example:not(.expanded) .code-wrapper .example-wrap{overflow-x:hidden;}.scraped-example .example-wrap .rust span.highlight{background:var(--scrape-example-code-line-highlight);}.scraped-example .example-wrap .rust span.highlight.focus{background:var(--scrape-example-code-line-highlight-focus);}.more-examples-toggle{max-width:calc(100% + 25px);margin-top:10px;margin-left:-25px;}.more-examples-toggle .hide-more{margin-left:25px;cursor:pointer;}.more-scraped-examples{margin-left:25px;position:relative;}.toggle-line{position:absolute;top:5px;bottom:0;right:calc(100% + 10px);padding:0 4px;cursor:pointer;}.toggle-line-inner{min-width:2px;height:100%;background:var(--scrape-example-toggle-line-background);}.toggle-line:hover .toggle-line-inner{background:var(--scrape-example-toggle-line-hover-background);}.more-scraped-examples .scraped-example,.example-links{margin-top:20px;}.more-scraped-examples .scraped-example:first-child{margin-top:5px;}.example-links ul{margin-bottom:0;}:root[data-theme="light"]{--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);}:root[data-theme="dark"]{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);}:root[data-theme="ayu"]{--main-background-color:#0f1419;--main-color:#c5c5c5;--settings-input-color:#ffb454;--settings-input-border-color:#999;--settings-button-color:#fff;--settings-button-border-focus:#e0e0e0;--sidebar-background-color:#14191f;--sidebar-background-color-hover:rgba(70,70,70,0.33);--code-block-background-color:#191f26;--scrollbar-track-background-color:transparent;--scrollbar-thumb-background-color:#5c6773;--scrollbar-color:#5c6773 #24292f;--headings-border-bottom-color:#5c6773;--border-color:#5c6773;--button-background-color:#141920;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--search-input-focused-border-color:#5c6773;--copy-path-button-color:#fff;--copy-path-img-filter:invert(70%);--copy-path-img-hover-filter:invert(100%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ffa0a5;--trait-link-color:#39afd7;--assoc-item-link-color:#39afd7;--function-link-color:#fdd687;--macro-link-color:#a37acc;--keyword-link-color:#39afd7;--mod-link-color:#39afd7;--link-color:#39afd7;--sidebar-link-color:#53b1db;--sidebar-current-link-background-color:transparent;--search-result-link-focus-background-color:#3c3c3c;--search-result-border-color:#aaa3;--search-color:#fff;--search-error-code-background-color:#4f4c4c;--search-results-alias-color:#c5c5c5;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:none;--search-tab-button-not-selected-background:transparent !important;--search-tab-button-selected-border-top-color:none;--search-tab-button-selected-background:#141920 !important;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ff7733;--code-highlight-kw-2-color:#ff7733;--code-highlight-lifetime-color:#ff7733;--code-highlight-prelude-color:#69f2df;--code-highlight-prelude-val-color:#ff7733;--code-highlight-number-color:#b8cc52;--code-highlight-string-color:#b8cc52;--code-highlight-literal-color:#ff7733;--code-highlight-attribute-color:#e6e1cf;--code-highlight-self-color:#36a3d9;--code-highlight-macro-color:#a37acc;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#788797;--code-highlight-doc-comment-color:#a1ac88;--src-line-numbers-span-color:#5c6773;--src-line-number-highlighted-background-color:rgba(255,236,164,0.06);--test-arrow-color:#788797;--test-arrow-background-color:rgba(57,175,215,0.09);--test-arrow-hover-color:#c5c5c5;--test-arrow-hover-background-color:rgba(57,175,215,0.368);--target-background-color:rgba(255,236,164,0.06);--target-border-color:rgba(255,180,76,0.85);--kbd-color:#c5c5c5;--kbd-background:#314559;--kbd-box-shadow-color:#5c6773;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);--crate-search-div-hover-filter:invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);--crate-search-hover-border:#e0e0e0;--src-sidebar-background-selected:#14191f;--src-sidebar-background-hover:#14191f;--table-alt-row-background-color:#191f26;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(15,20,25,1);--scrape-example-code-wrapper-background-end:rgba(15,20,25,0);}:root[data-theme="ayu"] h1,:root[data-theme="ayu"] h2,:root[data-theme="ayu"] h3,:root[data-theme="ayu"] h4,:where(:root[data-theme="ayu"]) h1 a,:root[data-theme="ayu"] .sidebar h2 a,:root[data-theme="ayu"] .sidebar h3 a,:root[data-theme="ayu"] #source-sidebar>.title{color:#fff;}:root[data-theme="ayu"] .docblock code{color:#ffb454;}:root[data-theme="ayu"] .docblock a>code{color:#39AFD7 !important;}:root[data-theme="ayu"] .code-header,:root[data-theme="ayu"] .docblock pre>code,:root[data-theme="ayu"] pre,:root[data-theme="ayu"] pre>code,:root[data-theme="ayu"] .item-info code,:root[data-theme="ayu"] .rustdoc.source .example-wrap{color:#e6e1cf;}:root[data-theme="ayu"] .sidebar .current,:root[data-theme="ayu"] .sidebar a:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:hover,:root[data-theme="ayu"] details.dir-entry summary:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:focus,:root[data-theme="ayu"] details.dir-entry summary:focus,:root[data-theme="ayu"] #src-sidebar div.files>a.selected{color:#ffb44c;}:root[data-theme="ayu"] .sidebar-elems .location{color:#ff7733;}:root[data-theme="ayu"] .src-line-numbers .line-highlighted{color:#708090;padding-right:7px;border-right:1px solid #ffb44c;}:root[data-theme="ayu"] .search-results a:hover,:root[data-theme="ayu"] .search-results a:focus{color:#fff !important;background-color:#3c3c3c;}:root[data-theme="ayu"] .search-results a{color:#0096cf;}:root[data-theme="ayu"] .search-results a div.desc{color:#c5c5c5;}:root[data-theme="ayu"] .result-name .primitive>i,:root[data-theme="ayu"] .result-name .keyword>i{color:#788797;}:root[data-theme="ayu"] #search-tabs>button.selected{border-bottom:1px solid #ffb44c !important;border-top:none;}:root[data-theme="ayu"] #search-tabs>button:not(.selected){border:none;background-color:transparent !important;}:root[data-theme="ayu"] #search-tabs>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}:root[data-theme="ayu"] #settings-menu>a img{filter:invert(100);} \ No newline at end of file diff --git a/docs/static.files/scrape-examples-ef1e698c1d417c0c.js b/docs/static.files/scrape-examples-ef1e698c1d417c0c.js new file mode 100644 index 000000000..ba830e374 --- /dev/null +++ b/docs/static.files/scrape-examples-ef1e698c1d417c0c.js @@ -0,0 +1 @@ +"use strict";(function(){const DEFAULT_MAX_LINES=5;const HIDDEN_MAX_LINES=10;function scrollToLoc(elt,loc,isHidden){const lines=elt.querySelector(".src-line-numbers");let scrollOffset;const maxLines=isHidden?HIDDEN_MAX_LINES:DEFAULT_MAX_LINES;if(loc[1]-loc[0]>maxLines){const line=Math.max(0,loc[0]-1);scrollOffset=lines.children[line].offsetTop}else{const wrapper=elt.querySelector(".code-wrapper");const halfHeight=wrapper.offsetHeight/2;const offsetTop=lines.children[loc[0]].offsetTop;const lastLine=lines.children[loc[1]];const offsetBot=lastLine.offsetTop+lastLine.offsetHeight;const offsetMid=(offsetTop+offsetBot)/2;scrollOffset=offsetMid-halfHeight}lines.scrollTo(0,scrollOffset);elt.querySelector(".rust").scrollTo(0,scrollOffset)}function updateScrapedExample(example,isHidden){const locs=JSON.parse(example.attributes.getNamedItem("data-locs").textContent);let locIndex=0;const highlights=Array.prototype.slice.call(example.querySelectorAll(".highlight"));const link=example.querySelector(".scraped-example-title a");if(locs.length>1){const onChangeLoc=changeIndex=>{removeClass(highlights[locIndex],"focus");changeIndex();scrollToLoc(example,locs[locIndex][0],isHidden);addClass(highlights[locIndex],"focus");const url=locs[locIndex][1];const title=locs[locIndex][2];link.href=url;link.innerHTML=title};example.querySelector(".prev").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex-1+locs.length)%locs.length})});example.querySelector(".next").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex+1)%locs.length})})}const expandButton=example.querySelector(".expand");if(expandButton){expandButton.addEventListener("click",()=>{if(hasClass(example,"expanded")){removeClass(example,"expanded");scrollToLoc(example,locs[0][0],isHidden)}else{addClass(example,"expanded")}})}scrollToLoc(example,locs[0][0],isHidden)}const firstExamples=document.querySelectorAll(".scraped-example-list > .scraped-example");onEachLazy(firstExamples,el=>updateScrapedExample(el,false));onEachLazy(document.querySelectorAll(".more-examples-toggle"),toggle=>{onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"),button=>{button.addEventListener("click",()=>{toggle.open=false})});const moreExamples=toggle.querySelectorAll(".scraped-example");toggle.querySelector("summary").addEventListener("click",()=>{setTimeout(()=>{onEachLazy(moreExamples,el=>updateScrapedExample(el,true))})},{once:true})})})() \ No newline at end of file diff --git a/docs/static.files/search-8be46b629f5f14a8.js b/docs/static.files/search-8be46b629f5f14a8.js new file mode 100644 index 000000000..4ecf5c55f --- /dev/null +++ b/docs/static.files/search-8be46b629f5f14a8.js @@ -0,0 +1,5 @@ +"use strict";if(!Array.prototype.toSpliced){Array.prototype.toSpliced=function(){const me=this.slice();Array.prototype.splice.apply(me,arguments);return me}}(function(){const itemTypes=["mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","primitive","associatedtype","constant","associatedconstant","union","foreigntype","keyword","existential","attr","derive","traitalias","generic",];const longItemTypes=["module","extern crate","re-export","struct","enum","function","type alias","static","trait","","trait method","method","struct field","enum variant","macro","primitive type","assoc type","constant","assoc const","union","foreign type","keyword","existential type","attribute macro","derive macro","trait alias",];const TY_PRIMITIVE=itemTypes.indexOf("primitive");const TY_KEYWORD=itemTypes.indexOf("keyword");const TY_GENERIC=itemTypes.indexOf("generic");const ROOT_PATH=typeof window!=="undefined"?window.rootPath:"../";function hasOwnPropertyRustdoc(obj,property){return Object.prototype.hasOwnProperty.call(obj,property)}function printTab(nb){let iter=0;let foundCurrentTab=false;let foundCurrentResultSet=false;onEachLazy(document.getElementById("search-tabs").childNodes,elem=>{if(nb===iter){addClass(elem,"selected");foundCurrentTab=true}else{removeClass(elem,"selected")}iter+=1});const isTypeSearch=(nb>0||iter===1);iter=0;onEachLazy(document.getElementById("results").childNodes,elem=>{if(nb===iter){addClass(elem,"active");foundCurrentResultSet=true}else{removeClass(elem,"active")}iter+=1});if(foundCurrentTab&&foundCurrentResultSet){searchState.currentTab=nb;const correctionsElem=document.getElementsByClassName("search-corrections");if(isTypeSearch){removeClass(correctionsElem[0],"hidden")}else{addClass(correctionsElem[0],"hidden")}}else if(nb!==0){printTab(0)}}const editDistanceState={current:[],prev:[],prevPrev:[],calculate:function calculate(a,b,limit){if(a.lengthlimit){return limit+1}while(b.length>0&&b[0]===a[0]){a=a.substring(1);b=b.substring(1)}while(b.length>0&&b[b.length-1]===a[a.length-1]){a=a.substring(0,a.length-1);b=b.substring(0,b.length-1)}if(b.length===0){return minDist}const aLength=a.length;const bLength=b.length;for(let i=0;i<=bLength;++i){this.current[i]=0;this.prev[i]=i;this.prevPrev[i]=Number.MAX_VALUE}for(let i=1;i<=aLength;++i){this.current[0]=i;const aIdx=i-1;for(let j=1;j<=bLength;++j){const bIdx=j-1;const substitutionCost=a[aIdx]===b[bIdx]?0:1;this.current[j]=Math.min(this.prev[j]+1,this.current[j-1]+1,this.prev[j-1]+substitutionCost);if((i>1)&&(j>1)&&(a[aIdx]===b[bIdx-1])&&(a[aIdx-1]===b[bIdx])){this.current[j]=Math.min(this.current[j],this.prevPrev[j-2]+1)}}const prevPrevTmp=this.prevPrev;this.prevPrev=this.prev;this.prev=this.current;this.current=prevPrevTmp}const distance=this.prev[bLength];return distance<=limit?distance:(limit+1)},};function editDistance(a,b,limit){return editDistanceState.calculate(a,b,limit)}function initSearch(rawSearchIndex){const MAX_RESULTS=200;const NO_TYPE_FILTER=-1;let searchIndex;let currentResults;let typeNameIdMap;const ALIASES=new Map();let typeNameIdOfArray;let typeNameIdOfSlice;let typeNameIdOfArrayOrSlice;function buildTypeMapIndex(name){if(name===""||name===null){return null}if(typeNameIdMap.has(name)){return typeNameIdMap.get(name)}else{const id=typeNameIdMap.size;typeNameIdMap.set(name,id);return id}}function isWhitespace(c){return" \t\n\r".indexOf(c)!==-1}function isSpecialStartCharacter(c){return"<\"".indexOf(c)!==-1}function isEndCharacter(c){return",>-]".indexOf(c)!==-1}function isStopCharacter(c){return isEndCharacter(c)}function isErrorCharacter(c){return"()".indexOf(c)!==-1}function itemTypeFromName(typename){const index=itemTypes.findIndex(i=>i===typename);if(index<0){throw["Unknown type filter ",typename]}return index}function getStringElem(query,parserState,isInGenerics){if(isInGenerics){throw["Unexpected ","\""," in generics"]}else if(query.literalSearch){throw["Cannot have more than one literal search element"]}else if(parserState.totalElems-parserState.genericsElems>0){throw["Cannot use literal search when there is more than one element"]}parserState.pos+=1;const start=parserState.pos;const end=getIdentEndPosition(parserState);if(parserState.pos>=parserState.length){throw["Unclosed ","\""]}else if(parserState.userQuery[end]!=="\""){throw["Unexpected ",parserState.userQuery[end]," in a string element"]}else if(start===end){throw["Cannot have empty string element"]}parserState.pos+=1;query.literalSearch=true}function isPathStart(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="::"}function isReturnArrow(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="->"}function isIdentCharacter(c){return(c==="_"||(c>="0"&&c<="9")||(c>="a"&&c<="z")||(c>="A"&&c<="Z"))}function isSeparatorCharacter(c){return c===","}function isPathSeparator(c){return c===":"||isWhitespace(c)}function prevIs(parserState,lookingFor){let pos=parserState.pos;while(pos>0){const c=parserState.userQuery[pos-1];if(c===lookingFor){return true}else if(!isWhitespace(c)){break}pos-=1}return false}function isLastElemGeneric(elems,parserState){return(elems.length>0&&elems[elems.length-1].generics.length>0)||prevIs(parserState,">")}function skipWhitespace(parserState){while(parserState.pos0){throw["Cannot have more than one element if you use quotes"]}const typeFilter=parserState.typeFilter;parserState.typeFilter=null;if(name==="!"){if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive never type ","!"," and ",typeFilter," both specified",]}if(generics.length!==0){throw["Never type ","!"," does not accept generic parameters",]}return{name:"never",id:null,fullPath:["never"],pathWithoutLast:[],pathLast:"never",generics:[],typeFilter:"primitive",}}if(path.startsWith("::")){throw["Paths cannot start with ","::"]}else if(path.endsWith("::")){throw["Paths cannot end with ","::"]}else if(path.includes("::::")){throw["Unexpected ","::::"]}else if(path.includes(" ::")){throw["Unexpected "," ::"]}else if(path.includes(":: ")){throw["Unexpected ",":: "]}const pathSegments=path.split(/::|\s+/);if(pathSegments.length===0||(pathSegments.length===1&&pathSegments[0]==="")){if(generics.length>0||prevIs(parserState,">")){throw["Found generics without a path"]}else{throw["Unexpected ",parserState.userQuery[parserState.pos]]}}for(const[i,pathSegment]of pathSegments.entries()){if(pathSegment==="!"){if(i!==0){throw["Never type ","!"," is not associated item"]}pathSegments[i]="never"}}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}return{name:name.trim(),id:null,fullPath:pathSegments,pathWithoutLast:pathSegments.slice(0,pathSegments.length-1),pathLast:pathSegments[pathSegments.length-1],generics:generics,typeFilter,}}function getIdentEndPosition(parserState){const start=parserState.pos;let end=parserState.pos;let foundExclamation=-1;while(parserState.pos=end){throw["Found generics without a path"]}parserState.pos+=1;getItemsBefore(query,parserState,generics,">")}if(isStringElem){skipWhitespace(parserState)}if(start>=end&&generics.length===0){return}elems.push(createQueryElement(query,parserState,parserState.userQuery.slice(start,end),generics,isInGenerics))}}function getItemsBefore(query,parserState,elems,endChar){let foundStopChar=true;let start=parserState.pos;const oldTypeFilter=parserState.typeFilter;parserState.typeFilter=null;let extra="";if(endChar===">"){extra="<"}else if(endChar==="]"){extra="["}else if(endChar===""){extra="->"}else{extra=endChar}while(parserState.pos"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(endChar!==""){throw["Expected ",","," or ",endChar,...extra,", found ",c,]}throw["Expected ",",",...extra,", found ",c,]}const posBefore=parserState.pos;start=parserState.pos;getNextElem(query,parserState,elems,endChar!=="");if(endChar!==""&&parserState.pos>=parserState.length){throw["Unclosed ",extra]}if(posBefore===parserState.pos){parserState.pos+=1}foundStopChar=false}if(parserState.pos>=parserState.length&&endChar!==""){throw["Unclosed ",extra]}parserState.pos+=1;parserState.typeFilter=oldTypeFilter}function checkExtraTypeFilterCharacters(start,parserState){const query=parserState.userQuery.slice(start,parserState.pos).trim();for(const c in query){if(!isIdentCharacter(query[c])){throw["Unexpected ",query[c]," in type filter (before ",":",")",]}}}function parseInput(query,parserState){let foundStopChar=true;let start=parserState.pos;while(parserState.pos"){if(isReturnArrow(parserState)){break}throw["Unexpected ",c," (did you mean ","->","?)"]}throw["Unexpected ",c]}else if(c===":"&&!isPathStart(parserState)){if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}else if(query.elems.length===0){throw["Expected type filter before ",":"]}else if(query.literalSearch){throw["Cannot use quotes on type filter"]}const typeFilterElem=query.elems.pop();checkExtraTypeFilterCharacters(start,parserState);parserState.typeFilter=typeFilterElem.name;parserState.pos+=1;parserState.totalElems-=1;query.literalSearch=false;foundStopChar=true;continue}else if(isWhitespace(c)){skipWhitespace(parserState);continue}if(!foundStopChar){let extra="";if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(parserState.typeFilter!==null){throw["Expected ",","," or ","->",...extra,", found ",c,]}throw["Expected ",",",", ",":"," or ","->",...extra,", found ",c,]}const before=query.elems.length;start=parserState.pos;getNextElem(query,parserState,query.elems,false);if(query.elems.length===before){parserState.pos+=1}foundStopChar=false}if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}while(parserState.pos"]}break}else{parserState.pos+=1}}}function newParsedQuery(userQuery){return{original:userQuery,userQuery:userQuery.toLowerCase(),elems:[],returned:[],foundElems:0,totalElems:0,literalSearch:false,error:null,correction:null,proposeCorrectionFrom:null,proposeCorrectionTo:null,}}function buildUrl(search,filterCrates){let extra="?search="+encodeURIComponent(search);if(filterCrates!==null){extra+="&filter-crate="+encodeURIComponent(filterCrates)}return getNakedUrl()+extra+window.location.hash}function getFilterCrates(){const elem=document.getElementById("crate-search");if(elem&&elem.value!=="all crates"&&hasOwnPropertyRustdoc(rawSearchIndex,elem.value)){return elem.value}return null}function parseQuery(userQuery){function convertTypeFilterOnElem(elem){if(elem.typeFilter!==null){let typeFilter=elem.typeFilter;if(typeFilter==="const"){typeFilter="constant"}elem.typeFilter=itemTypeFromName(typeFilter)}else{elem.typeFilter=NO_TYPE_FILTER}for(const elem2 of elem.generics){convertTypeFilterOnElem(elem2)}}userQuery=userQuery.trim();const parserState={length:userQuery.length,pos:0,totalElems:0,genericsElems:0,typeFilter:null,userQuery:userQuery.toLowerCase(),};let query=newParsedQuery(userQuery);try{parseInput(query,parserState);for(const elem of query.elems){convertTypeFilterOnElem(elem)}for(const elem of query.returned){convertTypeFilterOnElem(elem)}}catch(err){query=newParsedQuery(userQuery);query.error=err;return query}if(!query.literalSearch){query.literalSearch=parserState.totalElems>1}query.foundElems=query.elems.length+query.returned.length;query.totalElems=parserState.totalElems;return query}function createQueryResults(results_in_args,results_returned,results_others,parsedQuery){return{"in_args":results_in_args,"returned":results_returned,"others":results_others,"query":parsedQuery,}}function execQuery(parsedQuery,searchWords,filterCrates,currentCrate){const results_others=new Map(),results_in_args=new Map(),results_returned=new Map();function transformResults(results){const duplicates=new Set();const out=[];for(const result of results){if(result.id!==-1){const obj=searchIndex[result.id];obj.dist=result.dist;const res=buildHrefAndPath(obj);obj.displayPath=pathSplitter(res[0]);obj.fullPath=obj.displayPath+obj.name;obj.fullPath+="|"+obj.ty;if(duplicates.has(obj.fullPath)){continue}duplicates.add(obj.fullPath);obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}return out}function sortResults(results,isType,preferredCrate){if(results.size===0){return[]}const userQuery=parsedQuery.userQuery;const result_list=[];for(const result of results.values()){result.word=searchWords[result.id];result.item=searchIndex[result.id]||{};result_list.push(result)}result_list.sort((aaa,bbb)=>{let a,b;a=(aaa.word!==userQuery);b=(bbb.word!==userQuery);if(a!==b){return a-b}a=(aaa.index<0);b=(bbb.index<0);if(a!==b){return a-b}a=aaa.path_dist;b=bbb.path_dist;if(a!==b){return a-b}a=aaa.index;b=bbb.index;if(a!==b){return a-b}a=(aaa.dist);b=(bbb.dist);if(a!==b){return a-b}a=aaa.item.deprecated;b=bbb.item.deprecated;if(a!==b){return a-b}a=(aaa.item.crate!==preferredCrate);b=(bbb.item.crate!==preferredCrate);if(a!==b){return a-b}a=aaa.word.length;b=bbb.word.length;if(a!==b){return a-b}a=aaa.word;b=bbb.word;if(a!==b){return(a>b?+1:-1)}if((aaa.item.ty===TY_PRIMITIVE&&bbb.item.ty!==TY_KEYWORD)||(aaa.item.ty===TY_KEYWORD&&bbb.item.ty!==TY_PRIMITIVE)){return-1}if((bbb.item.ty===TY_PRIMITIVE&&aaa.item.ty!==TY_PRIMITIVE)||(bbb.item.ty===TY_KEYWORD&&aaa.item.ty!==TY_KEYWORD)){return 1}a=(aaa.item.desc==="");b=(bbb.item.desc==="");if(a!==b){return a-b}a=aaa.item.ty;b=bbb.item.ty;if(a!==b){return a-b}a=aaa.item.path;b=bbb.item.path;if(a!==b){return(a>b?+1:-1)}return 0});let nameSplit=null;if(parsedQuery.elems.length===1){const hasPath=typeof parsedQuery.elems[0].path==="undefined";nameSplit=hasPath?null:parsedQuery.elems[0].path}for(const result of result_list){if(result.dontValidate){continue}const name=result.item.name.toLowerCase(),path=result.item.path.toLowerCase(),parent=result.item.parent;if(!isType&&!validateResult(name,path,nameSplit,parent)){result.id=-1}}return transformResults(result_list)}function checkGenerics(fnType,queryElem,whereClause,mgensInout){return unifyFunctionTypes(fnType.generics,queryElem.generics,whereClause,mgensInout,mgens=>{if(mgensInout){for(const[fid,qid]of mgens.entries()){mgensInout.set(fid,qid)}}return true})}function unifyFunctionTypes(fnTypesIn,queryElems,whereClause,mgensIn,solutionCb){let mgens=new Map(mgensIn);if(queryElems.length===0){return!solutionCb||solutionCb(mgens)}if(!fnTypesIn||fnTypesIn.length===0){return false}const ql=queryElems.length;let fl=fnTypesIn.length;let fnTypes=fnTypesIn.slice();const backtracking=[];let i=0;let j=0;const backtrack=()=>{while(backtracking.length!==0){const{fnTypesScratch,mgensScratch,queryElemsOffset,fnTypesOffset,unbox,}=backtracking.pop();mgens=new Map(mgensScratch);const fnType=fnTypesScratch[fnTypesOffset];const queryElem=queryElems[queryElemsOffset];if(unbox){if(fnType.id<0){if(mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){continue}mgens.set(fnType.id,0)}const generics=fnType.id<0?whereClause[(-fnType.id)-1]:fnType.generics;fnTypes=fnTypesScratch.toSpliced(fnTypesOffset,1,...generics);fl=fnTypes.length;i=queryElemsOffset-1}else{if(fnType.id<0){if(mgens.has(fnType.id)&&mgens.get(fnType.id)!==queryElem.id){continue}mgens.set(fnType.id,queryElem.id)}fnTypes=fnTypesScratch.slice();fl=fnTypes.length;const tmp=fnTypes[queryElemsOffset];fnTypes[queryElemsOffset]=fnTypes[fnTypesOffset];fnTypes[fnTypesOffset]=tmp;i=queryElemsOffset}return true}return false};for(i=0;i!==ql;++i){const queryElem=queryElems[i];const matchCandidates=[];let fnTypesScratch=null;let mgensScratch=null;for(j=i;j!==fl;++j){const fnType=fnTypes[j];if(unifyFunctionTypeIsMatchCandidate(fnType,queryElem,whereClause,mgens)){if(!fnTypesScratch){fnTypesScratch=fnTypes.slice()}unifyFunctionTypes(fnType.generics,queryElem.generics,whereClause,mgens,mgensScratch=>{matchCandidates.push({fnTypesScratch,mgensScratch,queryElemsOffset:i,fnTypesOffset:j,unbox:false,});return false})}if(unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens)){if(!fnTypesScratch){fnTypesScratch=fnTypes.slice()}if(!mgensScratch){mgensScratch=new Map(mgens)}backtracking.push({fnTypesScratch,mgensScratch,queryElemsOffset:i,fnTypesOffset:j,unbox:true,})}}if(matchCandidates.length===0){if(backtrack()){continue}else{return false}}const{fnTypesOffset:candidate,mgensScratch:mgensNew}=matchCandidates.pop();if(fnTypes[candidate].id<0&&queryElems[i].id<0){mgens.set(fnTypes[candidate].id,queryElems[i].id)}for(const[fid,qid]of mgensNew){mgens.set(fid,qid)}const tmp=fnTypes[candidate];fnTypes[candidate]=fnTypes[i];fnTypes[i]=tmp;for(const otherCandidate of matchCandidates){backtracking.push(otherCandidate)}while(i===(ql-1)&&solutionCb&&!solutionCb(mgens)){if(!backtrack()){return false}}}return true}function unifyFunctionTypeIsMatchCandidate(fnType,queryElem,whereClause,mgens){if(!typePassesFilter(queryElem.typeFilter,fnType.ty)){return false}if(fnType.id<0&&queryElem.id<0){if(mgens.has(fnType.id)&&mgens.get(fnType.id)!==queryElem.id){return false}for(const[fid,qid]of mgens.entries()){if(fnType.id!==fid&&queryElem.id===qid){return false}if(fnType.id===fid&&queryElem.id!==qid){return false}}}else if(fnType.id!==null){if(queryElem.id===typeNameIdOfArrayOrSlice&&(fnType.id===typeNameIdOfSlice||fnType.id===typeNameIdOfArray)){}else if(fnType.id!==queryElem.id){return false}if(fnType.generics.length===0&&queryElem.generics.length!==0){return false}const queryElemPathLength=queryElem.pathWithoutLast.length;if(queryElemPathLength>0){const fnTypePath=fnType.path!==undefined&&fnType.path!==null?fnType.path.split("::"):[];if(queryElemPathLength>fnTypePath.length){return false}let i=0;for(const path of fnTypePath){if(path===queryElem.pathWithoutLast[i]){i+=1;if(i>=queryElemPathLength){break}}}if(i=0){if(!whereClause){return false}if(mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){return false}return checkIfInList(whereClause[(-fnType.id)-1],queryElem,whereClause)}else if(fnType.generics&&fnType.generics.length>0){return checkIfInList(fnType.generics,queryElem,whereClause)}return false}function checkIfInList(list,elem,whereClause){for(const entry of list){if(checkType(entry,elem,whereClause)){return true}}return false}function checkType(row,elem,whereClause){if(row.id===null){return row.generics.length>0?checkIfInList(row.generics,elem,whereClause):false}if(row.id<0&&elem.id>=0){const gid=(-row.id)-1;return checkIfInList(whereClause[gid],elem,whereClause)}if(row.id<0&&elem.id<0){return true}const matchesExact=row.id===elem.id;const matchesArrayOrSlice=elem.id===typeNameIdOfArrayOrSlice&&(row.id===typeNameIdOfSlice||row.id===typeNameIdOfArray);if((matchesExact||matchesArrayOrSlice)&&typePassesFilter(elem.typeFilter,row.ty)){if(elem.generics.length>0){return checkGenerics(row,elem,whereClause,new Map())}return true}return checkIfInList(row.generics,elem,whereClause)}function checkPath(contains,ty,maxEditDistance){if(contains.length===0){return 0}let ret_dist=maxEditDistance+1;const path=ty.path.split("::");if(ty.parent&&ty.parent.name){path.push(ty.parent.name.toLowerCase())}const length=path.length;const clength=contains.length;if(clength>length){return maxEditDistance+1}for(let i=0;ilength){break}let dist_total=0;let aborted=false;for(let x=0;xmaxEditDistance){aborted=true;break}dist_total+=dist}if(!aborted){ret_dist=Math.min(ret_dist,Math.round(dist_total/clength))}}return ret_dist}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER||filter===type)return true;const name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,desc:item.desc,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,deprecated:item.deprecated,}}function handleAliases(ret,query,filterCrates,currentCrate){const lowerQuery=query.toLowerCase();const aliases=[];const crateAliases=[];if(filterCrates!==null){if(ALIASES.has(filterCrates)&&ALIASES.get(filterCrates).has(lowerQuery)){const query_aliases=ALIASES.get(filterCrates).get(lowerQuery);for(const alias of query_aliases){aliases.push(createAliasFromItem(searchIndex[alias]))}}}else{for(const[crate,crateAliasesIndex]of ALIASES){if(crateAliasesIndex.has(lowerQuery)){const pushTo=crate===currentCrate?crateAliases:aliases;const query_aliases=crateAliasesIndex.get(lowerQuery);for(const alias of query_aliases){pushTo.push(createAliasFromItem(searchIndex[alias]))}}}}const sortFunc=(aaa,bbb)=>{if(aaa.path{alias.alias=query;const res=buildHrefAndPath(alias);alias.displayPath=pathSplitter(res[0]);alias.fullPath=alias.displayPath+alias.name;alias.href=res[1];ret.others.unshift(alias);if(ret.others.length>MAX_RESULTS){ret.others.pop()}};aliases.forEach(pushFunc);crateAliases.forEach(pushFunc)}function addIntoResults(results,fullId,id,index,dist,path_dist,maxEditDistance){const inBounds=dist<=maxEditDistance||index!==-1;if(dist===0||(!parsedQuery.literalSearch&&inBounds)){if(results.has(fullId)){const result=results.get(fullId);if(result.dontValidate||result.dist<=dist){return}}results.set(fullId,{id:id,index:index,dontValidate:parsedQuery.literalSearch,dist:dist,path_dist:path_dist,})}}function handleSingleArg(row,pos,elem,results_others,results_in_args,results_returned,maxEditDistance){if(!row||(filterCrates!==null&&row.crate!==filterCrates)){return}let index=-1,path_dist=0;const fullId=row.id;const searchWord=searchWords[pos];const in_args=row.type&&row.type.inputs&&checkIfInList(row.type.inputs,elem,row.type.where_clause);if(in_args){addIntoResults(results_in_args,fullId,pos,-1,0,0,maxEditDistance)}const returned=row.type&&row.type.output&&checkIfInList(row.type.output,elem,row.type.where_clause);if(returned){addIntoResults(results_returned,fullId,pos,-1,0,0,maxEditDistance)}if(!typePassesFilter(elem.typeFilter,row.ty)){return}const row_index=row.normalizedName.indexOf(elem.pathLast);const word_index=searchWord.indexOf(elem.pathLast);if(row_index===-1){index=word_index}else if(word_index===-1){index=row_index}else if(word_index1){path_dist=checkPath(elem.pathWithoutLast,row,maxEditDistance);if(path_dist>maxEditDistance){return}}if(parsedQuery.literalSearch){if(searchWord===elem.name){addIntoResults(results_others,fullId,pos,index,0,path_dist)}return}const dist=editDistance(searchWord,elem.pathLast,maxEditDistance);if(index===-1&&dist+path_dist>maxEditDistance){return}addIntoResults(results_others,fullId,pos,index,dist,path_dist,maxEditDistance)}function handleArgs(row,pos,results){if(!row||(filterCrates!==null&&row.crate!==filterCrates)||!row.type){return}if(!unifyFunctionTypes(row.type.inputs,parsedQuery.elems,row.type.where_clause,null,mgens=>{return unifyFunctionTypes(row.type.output,parsedQuery.returned,row.type.where_clause,mgens)})){return}addIntoResults(results,row.id,pos,0,0,0,Number.MAX_VALUE)}function innerRunQuery(){let elem,i,nSearchWords,in_returned,row;let queryLen=0;for(const elem of parsedQuery.elems){queryLen+=elem.name.length}for(const elem of parsedQuery.returned){queryLen+=elem.name.length}const maxEditDistance=Math.floor(queryLen/3);const genericSymbols=new Map();function convertNameToId(elem){if(typeNameIdMap.has(elem.pathLast)){elem.id=typeNameIdMap.get(elem.pathLast)}else if(!parsedQuery.literalSearch){let match=null;let matchDist=maxEditDistance+1;let matchName="";for(const[name,id]of typeNameIdMap){const dist=editDistance(name,elem.pathLast,maxEditDistance);if(dist<=matchDist&&dist<=maxEditDistance){if(dist===matchDist&&matchName>name){continue}match=id;matchDist=dist;matchName=name}}if(match!==null){parsedQuery.correction=matchName}elem.id=match}if((elem.id===null&&parsedQuery.totalElems>1&&elem.typeFilter===-1&&elem.generics.length===0)||elem.typeFilter===TY_GENERIC){if(genericSymbols.has(elem.name)){elem.id=genericSymbols.get(elem.name)}else{elem.id=-(genericSymbols.size+1);genericSymbols.set(elem.name,elem.id)}if(elem.typeFilter===-1&&elem.name.length>=3){const maxPartDistance=Math.floor(elem.name.length/3);let matchDist=maxPartDistance+1;let matchName="";for(const name of typeNameIdMap.keys()){const dist=editDistance(name,elem.name,maxPartDistance);if(dist<=matchDist&&dist<=maxPartDistance){if(dist===matchDist&&matchName>name){continue}matchDist=dist;matchName=name}}if(matchName!==""){parsedQuery.proposeCorrectionFrom=elem.name;parsedQuery.proposeCorrectionTo=matchName}}elem.typeFilter=TY_GENERIC}if(elem.generics.length>0&&elem.typeFilter===TY_GENERIC){parsedQuery.error=["Generic type parameter ",elem.name," does not accept generic parameters",]}for(const elem2 of elem.generics){convertNameToId(elem2)}}for(const elem of parsedQuery.elems){convertNameToId(elem)}for(const elem of parsedQuery.returned){convertNameToId(elem)}if(parsedQuery.foundElems===1){if(parsedQuery.elems.length===1){elem=parsedQuery.elems[0];for(i=0,nSearchWords=searchWords.length;i0){for(i=0,nSearchWords=searchWords.length;i-1||path.indexOf(key)>-1||(parent!==undefined&&parent.name!==undefined&&parent.name.toLowerCase().indexOf(key)>-1)||editDistance(name,key,maxEditDistance)<=maxEditDistance)){return false}}return true}function nextTab(direction){const next=(searchState.currentTab+direction+3)%searchState.focusedByTab.length;searchState.focusedByTab[searchState.currentTab]=document.activeElement;printTab(next);focusSearchResult()}function focusSearchResult(){const target=searchState.focusedByTab[searchState.currentTab]||document.querySelectorAll(".search-results.active a").item(0)||document.querySelectorAll("#search-tabs button").item(searchState.currentTab);searchState.focusedByTab[searchState.currentTab]=null;if(target){target.focus()}}function buildHrefAndPath(item){let displayPath;let href;const type=itemTypes[item.ty];const name=item.name;let path=item.path;if(type==="mod"){displayPath=path+"::";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="import"){displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/index.html#reexport."+name}else if(type==="primitive"||type==="keyword"){displayPath="";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=ROOT_PATH+name+"/index.html"}else if(item.parent!==undefined){const myparent=item.parent;let anchor="#"+type+"."+name;const parentType=itemTypes[myparent.ty];let pageType=parentType;let pageName=myparent.name;if(parentType==="primitive"){displayPath=myparent.name+"::"}else if(type==="structfield"&&parentType==="variant"){const enumNameIdx=item.path.lastIndexOf("::");const enumName=item.path.substr(enumNameIdx+2);path=item.path.substr(0,enumNameIdx);displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="#variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}href=ROOT_PATH+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html"+anchor}else{displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/"+type+"."+name+".html"}return[displayPath,href]}function pathSplitter(path){const tmp=""+path.replace(/::/g,"::");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}function addTab(array,query,display){let extraClass="";if(display===true){extraClass=" active"}const output=document.createElement("div");let length=0;if(array.length>0){output.className="search-results "+extraClass;array.forEach(item=>{const name=item.name;const type=itemTypes[item.ty];const longType=longItemTypes[item.ty];const typeName=longType.length!==0?`${longType}`:"?";length+=1;const link=document.createElement("a");link.className="result-"+type;link.href=item.href;const resultName=document.createElement("div");resultName.className="result-name";resultName.insertAdjacentHTML("beforeend",`${typeName}`);link.appendChild(resultName);let alias=" ";if(item.is_alias){alias=`
\ +${item.alias} - see \ +
`}resultName.insertAdjacentHTML("beforeend",`
${alias}\ +${item.displayPath}${name}\ +
`);const description=document.createElement("div");description.className="desc";description.insertAdjacentHTML("beforeend",item.desc);link.appendChild(description);output.appendChild(link)})}else if(query.error===null){output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return[output,length]}function makeTabHeader(tabNb,text,nbElems){const fmtNbElems=nbElems<10?`\u{2007}(${nbElems})\u{2007}\u{2007}`:nbElems<100?`\u{2007}(${nbElems})\u{2007}`:`\u{2007}(${nbElems})`;if(searchState.currentTab===tabNb){return""}return""}function showResults(results,go_to_first,filterCrates){const search=searchState.outputElement();if(go_to_first||(results.others.length===1&&getSettingValue("go-to-only-result")==="true")){window.onunload=()=>{};searchState.removeQueryParameters();const elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}if(results.query===undefined){results.query=parseQuery(searchState.input.value)}currentResults=results.query.userQuery;const ret_others=addTab(results.others,results.query,true);const ret_in_args=addTab(results.in_args,results.query,false);const ret_returned=addTab(results.returned,results.query,false);let currentTab=searchState.currentTab;if((currentTab===0&&ret_others[1]===0)||(currentTab===1&&ret_in_args[1]===0)||(currentTab===2&&ret_returned[1]===0)){if(ret_others[1]!==0){currentTab=0}else if(ret_in_args[1]!==0){currentTab=1}else if(ret_returned[1]!==0){currentTab=2}}let crates="";const crates_list=Object.keys(rawSearchIndex);if(crates_list.length>1){crates=" in 
"}let output=`

Results${crates}

`;if(results.query.error!==null){const error=results.query.error;error.forEach((value,index)=>{value=value.split("<").join("<").split(">").join(">");if(index%2!==0){error[index]=`${value.replaceAll(" ", " ")}`}else{error[index]=value}});output+=`

Query parser error: "${error.join("")}".

`;output+="
"+makeTabHeader(0,"In Names",ret_others[1])+"
";currentTab=0}else if(results.query.foundElems<=1&&results.query.returned.length===0){output+="
"+makeTabHeader(0,"In Names",ret_others[1])+makeTabHeader(1,"In Parameters",ret_in_args[1])+makeTabHeader(2,"In Return Types",ret_returned[1])+"
"}else{const signatureTabTitle=results.query.elems.length===0?"In Function Return Types":results.query.returned.length===0?"In Function Parameters":"In Function Signatures";output+="
"+makeTabHeader(0,signatureTabTitle,ret_others[1])+"
";currentTab=0}if(results.query.correction!==null){const orig=results.query.returned.length>0?results.query.returned[0].name:results.query.elems[0].name;output+="

"+`Type "${orig}" not found. `+"Showing results for closest type name "+`"${results.query.correction}" instead.

`}if(results.query.proposeCorrectionFrom!==null){const orig=results.query.proposeCorrectionFrom;const targ=results.query.proposeCorrectionTo;output+="

"+`Type "${orig}" not found and used as generic parameter. `+`Consider searching for "${targ}" instead.

`}const resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others[0]);resultsElem.appendChild(ret_in_args[0]);resultsElem.appendChild(ret_returned[0]);search.innerHTML=output;const crateSearch=document.getElementById("crate-search");if(crateSearch){crateSearch.addEventListener("input",updateCrate)}search.appendChild(resultsElem);searchState.showResults(search);const elems=document.getElementById("search-tabs").childNodes;searchState.focusedByTab=[];let i=0;for(const elem of elems){const j=i;elem.onclick=()=>printTab(j);searchState.focusedByTab.push(null);i+=1}printTab(currentTab)}function updateSearchHistory(url){if(!browserSupportsHistoryApi()){return}const params=searchState.getQueryStringParams();if(!history.state&&!params.search){history.pushState(null,"",url)}else{history.replaceState(null,"",url)}}function search(e,forced){if(e){e.preventDefault()}const query=parseQuery(searchState.input.value.trim());let filterCrates=getFilterCrates();if(!forced&&query.userQuery===currentResults){if(query.userQuery.length>0){putBackSearch()}return}searchState.setLoadingSearch();const params=searchState.getQueryStringParams();if(filterCrates===null&¶ms["filter-crate"]!==undefined){filterCrates=params["filter-crate"]}searchState.title="Results for "+query.original+" - Rust";updateSearchHistory(buildUrl(query.original,filterCrates));showResults(execQuery(query,searchWords,filterCrates,window.currentCrate),params.go_to_first,filterCrates)}function buildItemSearchTypeAll(types,lowercasePaths){return types.map(type=>buildItemSearchType(type,lowercasePaths))}function buildItemSearchType(type,lowercasePaths){const PATH_INDEX_DATA=0;const GENERICS_DATA=1;let pathIndex,generics;if(typeof type==="number"){pathIndex=type;generics=[]}else{pathIndex=type[PATH_INDEX_DATA];generics=buildItemSearchTypeAll(type[GENERICS_DATA],lowercasePaths)}if(pathIndex<0){return{id:pathIndex,ty:TY_GENERIC,path:null,generics,}}if(pathIndex===0){return{id:null,ty:null,path:null,generics,}}const item=lowercasePaths[pathIndex-1];return{id:buildTypeMapIndex(item.name),ty:item.ty,path:item.path,generics,}}function buildFunctionSearchType(functionSearchType,lowercasePaths){const INPUTS_DATA=0;const OUTPUT_DATA=1;if(functionSearchType===0){return null}let inputs,output;if(typeof functionSearchType[INPUTS_DATA]==="number"){inputs=[buildItemSearchType(functionSearchType[INPUTS_DATA],lowercasePaths)]}else{inputs=buildItemSearchTypeAll(functionSearchType[INPUTS_DATA],lowercasePaths)}if(functionSearchType.length>1){if(typeof functionSearchType[OUTPUT_DATA]==="number"){output=[buildItemSearchType(functionSearchType[OUTPUT_DATA],lowercasePaths)]}else{output=buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA],lowercasePaths)}}else{output=[]}const where_clause=[];const l=functionSearchType.length;for(let i=2;i2){path=itemPaths.has(elem[2])?itemPaths.get(elem[2]):lastPath;lastPath=path}lowercasePaths.push({ty:ty,name:name.toLowerCase(),path:path});paths[i]={ty:ty,name:name,path:path}}lastPath="";len=itemTypes.length;for(let i=0;i0?paths[itemParentIdxs[i]-1]:undefined,type:buildFunctionSearchType(itemFunctionSearchTypes[i],lowercasePaths),id:id,normalizedName:word.indexOf("_")===-1?word:word.replace(/_/g,""),deprecated:deprecatedItems.has(i),};id+=1;searchIndex.push(row);lastPath=row.path;crateSize+=1}if(aliases){const currentCrateAliases=new Map();ALIASES.set(crate,currentCrateAliases);for(const alias_name in aliases){if(!hasOwnPropertyRustdoc(aliases,alias_name)){continue}let currentNameAliases;if(currentCrateAliases.has(alias_name)){currentNameAliases=currentCrateAliases.get(alias_name)}else{currentNameAliases=[];currentCrateAliases.set(alias_name,currentNameAliases)}for(const local_alias of aliases[alias_name]){currentNameAliases.push(local_alias+currentIndex)}}}currentIndex+=crateSize}return searchWords}function onSearchSubmit(e){e.preventDefault();searchState.clearInputTimeout();search()}function putBackSearch(){const search_input=searchState.input;if(!searchState.input){return}if(search_input.value!==""&&!searchState.isDisplayed()){searchState.showResults();if(browserSupportsHistoryApi()){history.replaceState(null,"",buildUrl(search_input.value,getFilterCrates()))}document.title=searchState.title}}function registerSearchEvents(){const params=searchState.getQueryStringParams();if(searchState.input.value===""){searchState.input.value=params.search||""}const searchAfter500ms=()=>{searchState.clearInputTimeout();if(searchState.input.value.length===0){searchState.hideResults()}else{searchState.timeout=setTimeout(search,500)}};searchState.input.onkeyup=searchAfter500ms;searchState.input.oninput=searchAfter500ms;document.getElementsByClassName("search-form")[0].onsubmit=onSearchSubmit;searchState.input.onchange=e=>{if(e.target!==document.activeElement){return}searchState.clearInputTimeout();setTimeout(search,0)};searchState.input.onpaste=searchState.input.onchange;searchState.outputElement().addEventListener("keydown",e=>{if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey){return}if(e.which===38){const previous=document.activeElement.previousElementSibling;if(previous){previous.focus()}else{searchState.focus()}e.preventDefault()}else if(e.which===40){const next=document.activeElement.nextElementSibling;if(next){next.focus()}const rect=document.activeElement.getBoundingClientRect();if(window.innerHeight-rect.bottom{if(e.which===40){focusSearchResult();e.preventDefault()}});searchState.input.addEventListener("focus",()=>{putBackSearch()});searchState.input.addEventListener("blur",()=>{searchState.input.placeholder=searchState.input.origPlaceholder});if(browserSupportsHistoryApi()){const previousTitle=document.title;window.addEventListener("popstate",e=>{const params=searchState.getQueryStringParams();document.title=previousTitle;currentResults=null;if(params.search&¶ms.search.length>0){searchState.input.value=params.search;search(e)}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=()=>{const qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}function updateCrate(ev){if(ev.target.value==="all crates"){const query=searchState.input.value.trim();updateSearchHistory(buildUrl(query,null))}currentResults=null;search(undefined,true)}const searchWords=buildIndex(rawSearchIndex);if(typeof window!=="undefined"){registerSearchEvents();if(window.searchState.getQueryStringParams().search){search()}}if(typeof exports!=="undefined"){exports.initSearch=initSearch;exports.execQuery=execQuery;exports.parseQuery=parseQuery}return searchWords}if(typeof window!=="undefined"){window.initSearch=initSearch;if(window.searchIndex!==undefined){initSearch(window.searchIndex)}}else{initSearch({})}})() \ No newline at end of file diff --git a/docs/static.files/settings-74424d7eec62a23e.js b/docs/static.files/settings-74424d7eec62a23e.js new file mode 100644 index 000000000..3014f75c5 --- /dev/null +++ b/docs/static.files/settings-74424d7eec62a23e.js @@ -0,0 +1,17 @@ +"use strict";(function(){const isSettingsPage=window.location.pathname.endsWith("/settings.html");function changeSetting(settingName,value){if(settingName==="theme"){const useSystem=value==="system preference"?"true":"false";updateLocalStorage("use-system-theme",useSystem)}updateLocalStorage(settingName,value);switch(settingName){case"theme":case"preferred-dark-theme":case"preferred-light-theme":updateTheme();updateLightAndDark();break;case"line-numbers":if(value===true){window.rustdoc_add_line_numbers_to_examples()}else{window.rustdoc_remove_line_numbers_from_examples()}break}}function showLightAndDark(){removeClass(document.getElementById("preferred-light-theme"),"hidden");removeClass(document.getElementById("preferred-dark-theme"),"hidden")}function hideLightAndDark(){addClass(document.getElementById("preferred-light-theme"),"hidden");addClass(document.getElementById("preferred-dark-theme"),"hidden")}function updateLightAndDark(){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||(useSystem===null&&getSettingValue("theme")===null)){showLightAndDark()}else{hideLightAndDark()}}function setEvents(settingsElement){updateLightAndDark();onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"),toggle=>{const settingId=toggle.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=()=>{changeSetting(toggle.id,toggle.checked)}});onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"),elem=>{const settingId=elem.name;let settingValue=getSettingValue(settingId);if(settingId==="theme"){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||settingValue===null){settingValue=useSystem==="false"?"light":"system preference"}}if(settingValue!==null&&settingValue!=="null"){elem.checked=settingValue===elem.value}elem.addEventListener("change",ev=>{changeSetting(ev.target.name,ev.target.value)})})}function buildSettingsPageSections(settings){let output="";for(const setting of settings){const js_data_name=setting["js_name"];const setting_name=setting["name"];if(setting["options"]!==undefined){output+=`\ +
+
${setting_name}
+
`;onEach(setting["options"],option=>{const checked=option===setting["default"]?" checked":"";const full=`${js_data_name}-${option.replace(/ /g,"-")}`;output+=`\ + `});output+=`\ +
+
`}else{const checked=setting["default"]===true?" checked":"";output+=`\ +
\ + \ +
`}}return output}function buildSettingsPage(){const theme_names=getVar("themes").split(",").filter(t=>t);theme_names.push("light","dark","ayu");const settings=[{"name":"Theme","js_name":"theme","default":"system preference","options":theme_names.concat("system preference"),},{"name":"Preferred light theme","js_name":"preferred-light-theme","default":"light","options":theme_names,},{"name":"Preferred dark theme","js_name":"preferred-dark-theme","default":"dark","options":theme_names,},{"name":"Auto-hide item contents for large items","js_name":"auto-hide-large-items","default":true,},{"name":"Auto-hide item methods' documentation","js_name":"auto-hide-method-docs","default":false,},{"name":"Auto-hide trait implementation documentation","js_name":"auto-hide-trait-implementations","default":false,},{"name":"Directly go to item in search if there is only one result","js_name":"go-to-only-result","default":false,},{"name":"Show line numbers on code examples","js_name":"line-numbers","default":false,},{"name":"Disable keyboard shortcuts","js_name":"disable-shortcuts","default":false,},];const elementKind=isSettingsPage?"section":"div";const innerHTML=`
${buildSettingsPageSections(settings)}
`;const el=document.createElement(elementKind);el.id="settings";if(!isSettingsPage){el.className="popover"}el.innerHTML=innerHTML;if(isSettingsPage){document.getElementById(MAIN_ID).appendChild(el)}else{el.setAttribute("tabindex","-1");getSettingsButton().appendChild(el)}return el}const settingsMenu=buildSettingsPage();function displaySettings(){settingsMenu.style.display=""}function settingsBlurHandler(event){blurHandler(event,getSettingsButton(),window.hidePopoverMenus)}if(isSettingsPage){getSettingsButton().onclick=event=>{event.preventDefault()}}else{const settingsButton=getSettingsButton();const settingsMenu=document.getElementById("settings");settingsButton.onclick=event=>{if(elemIsInParent(event.target,settingsMenu)){return}event.preventDefault();const shouldDisplaySettings=settingsMenu.style.display==="none";window.hideAllModals();if(shouldDisplaySettings){displaySettings()}};settingsButton.onblur=settingsBlurHandler;settingsButton.querySelector("a").onblur=settingsBlurHandler;onEachLazy(settingsMenu.querySelectorAll("input"),el=>{el.onblur=settingsBlurHandler});settingsMenu.onblur=settingsBlurHandler}setTimeout(()=>{setEvents(settingsMenu);if(!isSettingsPage){displaySettings()}removeClass(getSettingsButton(),"rotate")},0)})() \ No newline at end of file diff --git a/docs/static.files/src-script-3280b574d94e47b4.js b/docs/static.files/src-script-3280b574d94e47b4.js new file mode 100644 index 000000000..9ea88921e --- /dev/null +++ b/docs/static.files/src-script-3280b574d94e47b4.js @@ -0,0 +1 @@ +"use strict";(function(){const rootPath=getVar("root-path");const NAME_OFFSET=0;const DIRS_OFFSET=1;const FILES_OFFSET=2;const RUSTDOC_MOBILE_BREAKPOINT=700;function closeSidebarIfMobile(){if(window.innerWidth"){addClass(document.documentElement,"src-sidebar-expanded");child.innerText="<";updateLocalStorage("source-sidebar-show","true")}else{removeClass(document.documentElement,"src-sidebar-expanded");child.innerText=">";updateLocalStorage("source-sidebar-show","false")}}function createSidebarToggle(){const sidebarToggle=document.createElement("div");sidebarToggle.id="src-sidebar-toggle";const inner=document.createElement("button");if(getCurrentValue("source-sidebar-show")==="true"){inner.innerText="<"}else{inner.innerText=">"}inner.onclick=toggleSidebar;sidebarToggle.appendChild(inner);return sidebarToggle}function createSrcSidebar(){const container=document.querySelector("nav.sidebar");const sidebarToggle=createSidebarToggle();container.insertBefore(sidebarToggle,container.firstChild);const sidebar=document.createElement("div");sidebar.id="src-sidebar";let hasFoundFile=false;const title=document.createElement("div");title.className="title";title.innerText="Files";sidebar.appendChild(title);Object.keys(srcIndex).forEach(key=>{srcIndex[key][NAME_OFFSET]=key;hasFoundFile=createDirEntry(srcIndex[key],sidebar,"",hasFoundFile)});container.appendChild(sidebar);const selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}const lineNumbersRegex=/^#?(\d+)(?:-(\d+))?$/;function highlightSrcLines(match){if(typeof match==="undefined"){match=window.location.hash.match(lineNumbersRegex)}if(!match){return}let from=parseInt(match[1],10);let to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to{onEachLazy(e.getElementsByTagName("a"),i_e=>{removeClass(i_e,"line-highlighted")})});for(let i=from;i<=to;++i){elem=document.getElementById(i);if(!elem){break}addClass(elem,"line-highlighted")}}const handleSrcHighlight=(function(){let prev_line_id=0;const set_fragment=name=>{const x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,null,"#"+name);highlightSrcLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return ev=>{let cur_line_id=parseInt(ev.target.id,10);if(isNaN(cur_line_id)||ev.ctrlKey||ev.altKey||ev.metaKey){return}ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){const tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(cur_line_id)}}}());window.addEventListener("hashchange",()=>{const match=window.location.hash.match(lineNumbersRegex);if(match){return highlightSrcLines(match)}});onEachLazy(document.getElementsByClassName("src-line-numbers"),el=>{el.addEventListener("click",handleSrcHighlight)});highlightSrcLines();window.createSrcSidebar=createSrcSidebar})() \ No newline at end of file diff --git a/docs/static.files/storage-fec3eaa3851e447d.js b/docs/static.files/storage-fec3eaa3851e447d.js new file mode 100644 index 000000000..a687118f3 --- /dev/null +++ b/docs/static.files/storage-fec3eaa3851e447d.js @@ -0,0 +1 @@ +"use strict";const builtinThemes=["light","dark","ayu"];const darkThemes=["dark","ayu"];window.currentTheme=document.getElementById("themeStyle");const settingsDataset=(function(){const settingsElement=document.getElementById("default-settings");return settingsElement&&settingsElement.dataset?settingsElement.dataset:null})();function getSettingValue(settingName){const current=getCurrentValue(settingName);if(current===null&&settingsDataset!==null){const def=settingsDataset[settingName.replace(/-/g,"_")];if(def!==undefined){return def}}return current}const localStoredTheme=getSettingValue("theme");function hasClass(elem,className){return elem&&elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(elem&&elem.classList){elem.classList.add(className)}}function removeClass(elem,className){if(elem&&elem.classList){elem.classList.remove(className)}}function onEach(arr,func,reversed){if(arr&&arr.length>0){if(reversed){for(let i=arr.length-1;i>=0;--i){if(func(arr[i])){return true}}}else{for(const elem of arr){if(func(elem)){return true}}}}return false}function onEachLazy(lazyArray,func,reversed){return onEach(Array.prototype.slice.call(lazyArray),func,reversed)}function updateLocalStorage(name,value){try{window.localStorage.setItem("rustdoc-"+name,value)}catch(e){}}function getCurrentValue(name){try{return window.localStorage.getItem("rustdoc-"+name)}catch(e){return null}}const getVar=(function getVar(name){const el=document.querySelector("head > meta[name='rustdoc-vars']");return el?el.attributes["data-"+name].value:null});function switchTheme(newThemeName,saveTheme){if(saveTheme){updateLocalStorage("theme",newThemeName)}document.documentElement.setAttribute("data-theme",newThemeName);if(builtinThemes.indexOf(newThemeName)!==-1){if(window.currentTheme){window.currentTheme.parentNode.removeChild(window.currentTheme);window.currentTheme=null}}else{const newHref=getVar("root-path")+newThemeName+getVar("resource-suffix")+".css";if(!window.currentTheme){if(document.readyState==="loading"){document.write(``);window.currentTheme=document.getElementById("themeStyle")}else{window.currentTheme=document.createElement("link");window.currentTheme.rel="stylesheet";window.currentTheme.id="themeStyle";window.currentTheme.href=newHref;document.documentElement.appendChild(window.currentTheme)}}else if(newHref!==window.currentTheme.href){window.currentTheme.href=newHref}}}const updateTheme=(function(){const mql=window.matchMedia("(prefers-color-scheme: dark)");function updateTheme(){if(getSettingValue("use-system-theme")!=="false"){const lightTheme=getSettingValue("preferred-light-theme")||"light";const darkTheme=getSettingValue("preferred-dark-theme")||"dark";updateLocalStorage("use-system-theme","true");switchTheme(mql.matches?darkTheme:lightTheme,true)}else{switchTheme(getSettingValue("theme"),false)}}mql.addEventListener("change",updateTheme);return updateTheme})();if(getSettingValue("use-system-theme")!=="false"&&window.matchMedia){if(getSettingValue("use-system-theme")===null&&getSettingValue("preferred-dark-theme")===null&&darkThemes.indexOf(localStoredTheme)>=0){updateLocalStorage("preferred-dark-theme",localStoredTheme)}}updateTheme();if(getSettingValue("source-sidebar-show")==="true"){addClass(document.documentElement,"src-sidebar-expanded")}window.addEventListener("pageshow",ev=>{if(ev.persisted){setTimeout(updateTheme,0)}}) \ No newline at end of file diff --git a/docs/static.files/wheel-7b819b6101059cd0.svg b/docs/static.files/wheel-7b819b6101059cd0.svg new file mode 100644 index 000000000..83c07f63d --- /dev/null +++ b/docs/static.files/wheel-7b819b6101059cd0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/statime/all.html b/docs/statime/all.html new file mode 100644 index 000000000..f2fb27a1a --- /dev/null +++ b/docs/statime/all.html @@ -0,0 +1 @@ +List of all items in this crate
\ No newline at end of file diff --git a/docs/statime/clock/trait.Clock.html b/docs/statime/clock/trait.Clock.html new file mode 100644 index 000000000..38df2cb42 --- /dev/null +++ b/docs/statime/clock/trait.Clock.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/trait.Clock.html...

+ + + \ No newline at end of file diff --git a/docs/statime/config/instance/struct.InstanceConfig.html b/docs/statime/config/instance/struct.InstanceConfig.html new file mode 100644 index 000000000..a25a4e693 --- /dev/null +++ b/docs/statime/config/instance/struct.InstanceConfig.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/struct.InstanceConfig.html...

+ + + \ No newline at end of file diff --git a/docs/statime/config/port/enum.DelayMechanism.html b/docs/statime/config/port/enum.DelayMechanism.html new file mode 100644 index 000000000..a592f9037 --- /dev/null +++ b/docs/statime/config/port/enum.DelayMechanism.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/enum.DelayMechanism.html...

+ + + \ No newline at end of file diff --git a/docs/statime/config/port/struct.PortConfig.html b/docs/statime/config/port/struct.PortConfig.html new file mode 100644 index 000000000..f862d1ad4 --- /dev/null +++ b/docs/statime/config/port/struct.PortConfig.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/struct.PortConfig.html...

+ + + \ No newline at end of file diff --git a/docs/statime/constant.MAX_DATA_LEN.html b/docs/statime/constant.MAX_DATA_LEN.html new file mode 100644 index 000000000..50794c066 --- /dev/null +++ b/docs/statime/constant.MAX_DATA_LEN.html @@ -0,0 +1 @@ +MAX_DATA_LEN in statime - Rust

Constant statime::MAX_DATA_LEN

source ·
pub const MAX_DATA_LEN: usize = 255;
\ No newline at end of file diff --git a/docs/statime/datastructures/common/clock_accuracy/enum.ClockAccuracy.html b/docs/statime/datastructures/common/clock_accuracy/enum.ClockAccuracy.html new file mode 100644 index 000000000..8fd931836 --- /dev/null +++ b/docs/statime/datastructures/common/clock_accuracy/enum.ClockAccuracy.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/enum.ClockAccuracy.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/common/clock_identity/struct.ClockIdentity.html b/docs/statime/datastructures/common/clock_identity/struct.ClockIdentity.html new file mode 100644 index 000000000..489a6e2ff --- /dev/null +++ b/docs/statime/datastructures/common/clock_identity/struct.ClockIdentity.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/struct.ClockIdentity.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/common/clock_quality/struct.ClockQuality.html b/docs/statime/datastructures/common/clock_quality/struct.ClockQuality.html new file mode 100644 index 000000000..0570e83f4 --- /dev/null +++ b/docs/statime/datastructures/common/clock_quality/struct.ClockQuality.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/struct.ClockQuality.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/common/leap_indicator/enum.LeapIndicator.html b/docs/statime/datastructures/common/leap_indicator/enum.LeapIndicator.html new file mode 100644 index 000000000..c3b20443e --- /dev/null +++ b/docs/statime/datastructures/common/leap_indicator/enum.LeapIndicator.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/enum.LeapIndicator.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/common/time_source/enum.TimeSource.html b/docs/statime/datastructures/common/time_source/enum.TimeSource.html new file mode 100644 index 000000000..9ea07bc19 --- /dev/null +++ b/docs/statime/datastructures/common/time_source/enum.TimeSource.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/enum.TimeSource.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/datasets/time_properties/struct.TimePropertiesDS.html b/docs/statime/datastructures/datasets/time_properties/struct.TimePropertiesDS.html new file mode 100644 index 000000000..1bedc2858 --- /dev/null +++ b/docs/statime/datastructures/datasets/time_properties/struct.TimePropertiesDS.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/struct.TimePropertiesDS.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/messages/constant.MAX_DATA_LEN.html b/docs/statime/datastructures/messages/constant.MAX_DATA_LEN.html new file mode 100644 index 000000000..6d4f657f9 --- /dev/null +++ b/docs/statime/datastructures/messages/constant.MAX_DATA_LEN.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/constant.MAX_DATA_LEN.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/messages/fuzz/struct.FuzzMessage.html b/docs/statime/datastructures/messages/fuzz/struct.FuzzMessage.html new file mode 100644 index 000000000..87947b3df --- /dev/null +++ b/docs/statime/datastructures/messages/fuzz/struct.FuzzMessage.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/struct.FuzzMessage.html...

+ + + \ No newline at end of file diff --git a/docs/statime/datastructures/messages/header/struct.SdoId.html b/docs/statime/datastructures/messages/header/struct.SdoId.html new file mode 100644 index 000000000..a90d5a494 --- /dev/null +++ b/docs/statime/datastructures/messages/header/struct.SdoId.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../statime/struct.SdoId.html...

+ + + \ No newline at end of file diff --git a/docs/statime/enum.ClockAccuracy.html b/docs/statime/enum.ClockAccuracy.html new file mode 100644 index 000000000..8cffcb7cc --- /dev/null +++ b/docs/statime/enum.ClockAccuracy.html @@ -0,0 +1,92 @@ +ClockAccuracy in statime - Rust
pub enum ClockAccuracy {
+
Show 30 variants Reserved, + PS1, + PS2_5, + PS10, + PS25, + PS100, + PS250, + NS1, + NS2_5, + NS10, + NS25, + NS100, + NS250, + US1, + US2_5, + US10, + US25, + US100, + US250, + MS1, + MS2_5, + MS10, + MS25, + MS100, + MS250, + S1, + S10, + SGT10, + ProfileSpecific(u8), + Unknown, +
}
Expand description

How accurate the underlying clock device is expected to be when not +synchronized.

+

Variants§

§

Reserved

Reserved

+
§

PS1

Accurate within 1 ps

+
§

PS2_5

Accurate within 2.5 ps

+
§

PS10

Accurate within 10 ps

+
§

PS25

Accurate within 25 ps

+
§

PS100

Accurate within 100 ps

+
§

PS250

Accurate within 250 ps

+
§

NS1

Accurate within 1 ns

+
§

NS2_5

Accurate within 2.5 ns

+
§

NS10

Accurate within 10 ns

+
§

NS25

Accurate within 25 ns

+
§

NS100

Accurate within 100 ns

+
§

NS250

Accurate within 250 ns

+
§

US1

Accurate within 1 us

+
§

US2_5

Accurate within 2.5 us

+
§

US10

Accurate within 10 us

+
§

US25

Accurate within 25 us

+
§

US100

Accurate within 100 us

+
§

US250

Accurate within 250 us

+
§

MS1

Accurate within 1 ms

+
§

MS2_5

Accurate within 2.5 ms

+
§

MS10

Accurate within 10 ms

+
§

MS25

Accurate within 25 ms

+
§

MS100

Accurate within 100 ms

+
§

MS250

Accurate within 250 ms

+
§

S1

Accurate within 1 s

+
§

S10

Accurate within 10 s

+
§

SGT10

Accurate within >10 s

+
§

ProfileSpecific(u8)

Specific to a profile

+
§

Unknown

Accuracy is unknown

+

Trait Implementations§

source§

impl Clone for ClockAccuracy

source§

fn clone(&self) -> ClockAccuracy

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for ClockAccuracy

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for ClockAccuracy

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl PartialEq<ClockAccuracy> for ClockAccuracy

source§

fn eq(&self, other: &ClockAccuracy) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for ClockAccuracy

source§

impl Eq for ClockAccuracy

source§

impl StructuralEq for ClockAccuracy

source§

impl StructuralPartialEq for ClockAccuracy

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/enum.DelayMechanism.html b/docs/statime/enum.DelayMechanism.html new file mode 100644 index 000000000..7e8df4896 --- /dev/null +++ b/docs/statime/enum.DelayMechanism.html @@ -0,0 +1,40 @@ +DelayMechanism in statime - Rust
pub enum DelayMechanism {
+    E2E {
+        interval: Interval,
+    },
+}
Expand description

Which delay mechanism a port is using.

+

Currently, statime only supports the end to end (E2E) delay mechanism.

+

Variants§

§

E2E

Fields

§interval: Interval

End to end delay mechanism. Delay measurement is done directly to the +chosen master, across potential transparent nodes in between.

+

the interval corresponds to the PortDS logMinDelayReqInterval

+

Trait Implementations§

source§

impl Clone for DelayMechanism

source§

fn clone(&self) -> DelayMechanism

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for DelayMechanism

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Hash for DelayMechanism

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl PartialEq<DelayMechanism> for DelayMechanism

source§

fn eq(&self, other: &DelayMechanism) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for DelayMechanism

source§

impl Eq for DelayMechanism

source§

impl StructuralEq for DelayMechanism

source§

impl StructuralPartialEq for DelayMechanism

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/enum.LeapIndicator.html b/docs/statime/enum.LeapIndicator.html new file mode 100644 index 000000000..7def3af5f --- /dev/null +++ b/docs/statime/enum.LeapIndicator.html @@ -0,0 +1,35 @@ +LeapIndicator in statime - Rust
pub enum LeapIndicator {
+    NoLeap,
+    Leap61,
+    Leap59,
+}

Variants§

§

NoLeap

§

Leap61

the last minute of the current UTC day contains 61 seconds.

+
§

Leap59

the last minute of the current UTC day contains 59 seconds.

+

Trait Implementations§

source§

impl Clone for LeapIndicator

source§

fn clone(&self) -> LeapIndicator

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for LeapIndicator

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for LeapIndicator

source§

fn default() -> LeapIndicator

Returns the “default value” for a type. Read more
source§

impl PartialEq<LeapIndicator> for LeapIndicator

source§

fn eq(&self, other: &LeapIndicator) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for LeapIndicator

source§

impl Eq for LeapIndicator

source§

impl StructuralEq for LeapIndicator

source§

impl StructuralPartialEq for LeapIndicator

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/enum.PortAction.html b/docs/statime/enum.PortAction.html new file mode 100644 index 000000000..5b95587da --- /dev/null +++ b/docs/statime/enum.PortAction.html @@ -0,0 +1,49 @@ +PortAction in statime - Rust

Enum statime::PortAction

source ·
pub enum PortAction<'a> {
+    SendTimeCritical {
+        context: TimestampContext,
+        data: &'a [u8],
+    },
+    SendGeneral {
+        data: &'a [u8],
+    },
+    ResetAnnounceTimer {
+        duration: Duration,
+    },
+    ResetSyncTimer {
+        duration: Duration,
+    },
+    ResetDelayRequestTimer {
+        duration: Duration,
+    },
+    ResetAnnounceReceiptTimer {
+        duration: Duration,
+    },
+    ResetFilterUpdateTimer {
+        duration: Duration,
+    },
+}

Variants§

§

SendTimeCritical

Fields

§data: &'a [u8]
§

SendGeneral

Fields

§data: &'a [u8]
§

ResetAnnounceTimer

Fields

§duration: Duration
§

ResetSyncTimer

Fields

§duration: Duration
§

ResetDelayRequestTimer

Fields

§duration: Duration
§

ResetAnnounceReceiptTimer

Fields

§duration: Duration
§

ResetFilterUpdateTimer

Fields

§duration: Duration

Trait Implementations§

source§

impl<'a> Debug for PortAction<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> RefUnwindSafe for PortAction<'a>

§

impl<'a> Send for PortAction<'a>

§

impl<'a> Sync for PortAction<'a>

§

impl<'a> Unpin for PortAction<'a>

§

impl<'a> UnwindSafe for PortAction<'a>

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/enum.TimeSource.html b/docs/statime/enum.TimeSource.html new file mode 100644 index 000000000..2ea5007e9 --- /dev/null +++ b/docs/statime/enum.TimeSource.html @@ -0,0 +1,47 @@ +TimeSource in statime - Rust

Enum statime::TimeSource

source ·
pub enum TimeSource {
+    AtomicClock,
+    Gnss,
+    TerrestrialRadio,
+    SerialTimeCode,
+    Ptp,
+    Ntp,
+    HandSet,
+    Other,
+    InternalOscillator,
+    ProfileSpecific(u8),
+    Reserved,
+    Unknown(u8),
+}
Expand description

What the time values for a system are derived from

+

This enum encodes the root source of a system’s time values. For most use +cases, the default InternalOscillator will suffice.

+

Variants§

§

AtomicClock

§

Gnss

§

TerrestrialRadio

§

SerialTimeCode

§

Ptp

§

Ntp

§

HandSet

§

Other

§

InternalOscillator

§

ProfileSpecific(u8)

§

Reserved

§

Unknown(u8)

Time source is unknown. This is not an official variant from the spec, +but we just need it in practise

+

Trait Implementations§

source§

impl Clone for TimeSource

source§

fn clone(&self) -> TimeSource

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for TimeSource

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for TimeSource

source§

fn default() -> TimeSource

Returns the “default value” for a type. Read more
source§

impl PartialEq<TimeSource> for TimeSource

source§

fn eq(&self, other: &TimeSource) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for TimeSource

source§

impl Eq for TimeSource

source§

impl StructuralEq for TimeSource

source§

impl StructuralPartialEq for TimeSource

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/filters/basic/struct.BasicFilter.html b/docs/statime/filters/basic/struct.BasicFilter.html new file mode 100644 index 000000000..2fb1d6601 --- /dev/null +++ b/docs/statime/filters/basic/struct.BasicFilter.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/struct.BasicFilter.html...

+ + + \ No newline at end of file diff --git a/docs/statime/filters/trait.Filter.html b/docs/statime/filters/trait.Filter.html new file mode 100644 index 000000000..95da0038d --- /dev/null +++ b/docs/statime/filters/trait.Filter.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/trait.Filter.html...

+ + + \ No newline at end of file diff --git a/docs/statime/index.html b/docs/statime/index.html new file mode 100644 index 000000000..4445125cc --- /dev/null +++ b/docs/statime/index.html @@ -0,0 +1,33 @@ +statime - Rust

Crate statime

source ·
Expand description

Statime is a library providing an implementation of PTP version 2.1 +(IEEE1588-2019). It provides all the building blocks to setup PTP ordinary +and boundary clocks.

+

Note: We are currently planning a major overhaul of the library. This will +also result in significant changes to the public API.

+

Device interfaces

+

statime is designed to be able to work with many different underlying +platforms, including embedded targets. This does mean that it cannot use the +standard library and platform specific libraries to interact with the system +clock and to access the network. That needs to be provided by the user of +the library.

+

The statime crate defines a Clock interface that provide access to the +system clock. The [NetworkRuntime] and [NetworkPort] +abstractions provide the needed glue to access the network.

+

On modern linux kernels, the statime-linux crate provides ready to use +implementations of these interfaces. For other platforms the user will need +to implement these themselves.

+

Clock identities

+

All ptp clocks in a network need a unique clock identity. One way to achieve +this is to use (one of) the device’s mac address to generate this +identifier. As this requires platform specific code to get the mac address, +this library does not implement this. Rather, direct access is given to the +clock identity type, and the user can create one from a mac address by +storing it in the first six bytes of the clock identifier, setting the +remaining bytes to 0. For more details on the exact specification of the +generation procedure, see IEEE1588-2019 section 7.5.2.2.2

+

Structs

Enums

Constants

Traits

  • Clock manipulation and querying interface
  • A filter for post-processing time measurements.
\ No newline at end of file diff --git a/docs/statime/port/enum.PortAction.html b/docs/statime/port/enum.PortAction.html new file mode 100644 index 000000000..6558d2bb1 --- /dev/null +++ b/docs/statime/port/enum.PortAction.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/enum.PortAction.html...

+ + + \ No newline at end of file diff --git a/docs/statime/port/measurement/struct.Measurement.html b/docs/statime/port/measurement/struct.Measurement.html new file mode 100644 index 000000000..bc6e96b68 --- /dev/null +++ b/docs/statime/port/measurement/struct.Measurement.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/struct.Measurement.html...

+ + + \ No newline at end of file diff --git a/docs/statime/port/struct.InBmca.html b/docs/statime/port/struct.InBmca.html new file mode 100644 index 000000000..8561a3343 --- /dev/null +++ b/docs/statime/port/struct.InBmca.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/struct.InBmca.html...

+ + + \ No newline at end of file diff --git a/docs/statime/port/struct.Port.html b/docs/statime/port/struct.Port.html new file mode 100644 index 000000000..b6d704e0e --- /dev/null +++ b/docs/statime/port/struct.Port.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/struct.Port.html...

+ + + \ No newline at end of file diff --git a/docs/statime/port/struct.PortActionIterator.html b/docs/statime/port/struct.PortActionIterator.html new file mode 100644 index 000000000..21a462cf4 --- /dev/null +++ b/docs/statime/port/struct.PortActionIterator.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/struct.PortActionIterator.html...

+ + + \ No newline at end of file diff --git a/docs/statime/port/struct.Running.html b/docs/statime/port/struct.Running.html new file mode 100644 index 000000000..c6858757d --- /dev/null +++ b/docs/statime/port/struct.Running.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/struct.Running.html...

+ + + \ No newline at end of file diff --git a/docs/statime/port/struct.TimestampContext.html b/docs/statime/port/struct.TimestampContext.html new file mode 100644 index 000000000..4191b21fe --- /dev/null +++ b/docs/statime/port/struct.TimestampContext.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/struct.TimestampContext.html...

+ + + \ No newline at end of file diff --git a/docs/statime/ptp_instance/struct.PtpInstance.html b/docs/statime/ptp_instance/struct.PtpInstance.html new file mode 100644 index 000000000..eaa0aedad --- /dev/null +++ b/docs/statime/ptp_instance/struct.PtpInstance.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../statime/struct.PtpInstance.html...

+ + + \ No newline at end of file diff --git a/docs/statime/sidebar-items.js b/docs/statime/sidebar-items.js new file mode 100644 index 000000000..f3b103f8b --- /dev/null +++ b/docs/statime/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["MAX_DATA_LEN"],"enum":["ClockAccuracy","DelayMechanism","LeapIndicator","PortAction","TimeSource"],"struct":["BasicFilter","ClockIdentity","ClockQuality","Duration","FuzzMessage","InBmca","InstanceConfig","Interval","Measurement","Port","PortActionIterator","PortConfig","PtpInstance","Running","SdoId","Time","TimePropertiesDS","TimestampContext"],"trait":["Clock","Filter"]}; \ No newline at end of file diff --git a/docs/statime/struct.BasicFilter.html b/docs/statime/struct.BasicFilter.html new file mode 100644 index 000000000..a93d1d2de --- /dev/null +++ b/docs/statime/struct.BasicFilter.html @@ -0,0 +1,35 @@ +BasicFilter in statime - Rust

Struct statime::BasicFilter

source ·
pub struct BasicFilter { /* private fields */ }
Expand description

A simple averaging filter

+

This filter uses simple averaging to determine what the clock control +outputs should be.

+

Trait Implementations§

source§

impl Debug for BasicFilter

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Filter for BasicFilter

§

type Config = f64

source§

fn new(gain: f64) -> Self

Create a new instance of the filter.
source§

fn measurement<C: Clock>( + &mut self, + measurement: Measurement, + clock: &mut C +) -> FilterUpdate

Put a new measurement in the filter. +The filter can then use this to adjust the clock
source§

fn demobilize<C: Clock>(self, _clock: &mut C)

Handle ending of time synchronization from the source +associated with this filter.
source§

fn update<C: Clock>(&mut self, _clock: &mut C) -> FilterUpdate

Update initiated through [FilterUpdate::next_update] timeout.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.ClockIdentity.html b/docs/statime/struct.ClockIdentity.html new file mode 100644 index 000000000..90e012192 --- /dev/null +++ b/docs/statime/struct.ClockIdentity.html @@ -0,0 +1,39 @@ +ClockIdentity in statime - Rust

Struct statime::ClockIdentity

source ·
pub struct ClockIdentity(pub [u8; 8]);
Expand description

The identity of a PTP node.

+

Must have a unique value for each node in a ptp network. For notes on +generating these, see IEEE1588-2019 section 7.5.2.2

+

Tuple Fields§

§0: [u8; 8]

Trait Implementations§

source§

impl Clone for ClockIdentity

source§

fn clone(&self) -> ClockIdentity

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for ClockIdentity

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for ClockIdentity

source§

fn default() -> ClockIdentity

Returns the “default value” for a type. Read more
source§

impl Hash for ClockIdentity

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for ClockIdentity

source§

fn cmp(&self, other: &ClockIdentity) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere + Self: Sized + PartialOrd<Self>,

Restrict a value to a certain interval. Read more
source§

impl PartialEq<ClockIdentity> for ClockIdentity

source§

fn eq(&self, other: &ClockIdentity) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd<ClockIdentity> for ClockIdentity

source§

fn partial_cmp(&self, other: &ClockIdentity) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Copy for ClockIdentity

source§

impl Eq for ClockIdentity

source§

impl StructuralEq for ClockIdentity

source§

impl StructuralPartialEq for ClockIdentity

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.ClockQuality.html b/docs/statime/struct.ClockQuality.html new file mode 100644 index 000000000..f43561fb6 --- /dev/null +++ b/docs/statime/struct.ClockQuality.html @@ -0,0 +1,43 @@ +ClockQuality in statime - Rust

Struct statime::ClockQuality

source ·
pub struct ClockQuality {
+    pub clock_class: u8,
+    pub clock_accuracy: ClockAccuracy,
+    pub offset_scaled_log_variance: u16,
+}
Expand description

A description of the accuracy and type of a clock.

+

Fields§

§clock_class: u8

The PTP clock class.

+

Per the standard, 248 is the default, and a good option for most use +cases. For grandmaster clocks, this should be below 128 to ensure the +clock never takes time from another source. A value of 6 is a good +option for a node with an external time source.

+

For other potential values, see IEEE1588-2019 section 7.6.2.5

+
§clock_accuracy: ClockAccuracy

The accuracy of the clock

+
§offset_scaled_log_variance: u16

2-log of the variance (in seconds^2) of the clock when not synchronized. +See IEEE1588-2019 section 7.6.3.5 for more details.

+

Trait Implementations§

source§

impl Clone for ClockQuality

source§

fn clone(&self) -> ClockQuality

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for ClockQuality

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for ClockQuality

source§

fn default() -> ClockQuality

Returns the “default value” for a type. Read more
source§

impl PartialEq<ClockQuality> for ClockQuality

source§

fn eq(&self, other: &ClockQuality) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for ClockQuality

source§

impl Eq for ClockQuality

source§

impl StructuralEq for ClockQuality

source§

impl StructuralPartialEq for ClockQuality

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.Duration.html b/docs/statime/struct.Duration.html new file mode 100644 index 000000000..91c7596c2 --- /dev/null +++ b/docs/statime/struct.Duration.html @@ -0,0 +1,54 @@ +Duration in statime - Rust

Struct statime::Duration

source ·
pub struct Duration { /* private fields */ }
Expand description

A duration is a span of time that can also be negative.

+

For example, the difference between two instants is a duration. +And an instant plus a duration is another instant.

+

Implementations§

source§

impl Duration

source

pub const ZERO: Duration = _

source

pub fn from_seconds(secs: f64) -> Self

Create an instance with the given amount of seconds

+
source

pub fn from_secs(secs: i64) -> Self

Create an instance with the given amount of seconds

+
source

pub fn from_millis(millis: i64) -> Self

Create an instance with the given amount of milliseconds

+
source

pub fn from_micros(micros: i64) -> Self

Create an instance with the given amount of microseconds

+
source

pub fn from_nanos(nanos: i64) -> Self

Create an instance with the given amount of nanoseconds

+
source

pub fn from_fixed_nanos<F: ToFixed>(nanos: F) -> Self

Create an instance with the given amount of nanoseconds, using a fixed +point number so the subnanoseconds can be specified as well

+
source

pub fn nanos(&self) -> I96F32

Get the total amount of nanoseconds

+
source

pub fn nanos_rounded(&self) -> i128

source

pub fn nanos_lossy(&self) -> f64

Get the total amount of nanoseconds, losing some precision

+
source

pub fn secs(&self) -> i64

Get the total amount of seconds

+
source

pub fn seconds(&self) -> f64

Get the total amount of seconds

+
source

pub fn from_log_interval(log_interval: i8) -> Self

Converts a log interval (as defined by the PTP spec) to a duration

+
source

pub fn from_interval(interval: Interval) -> Self

Converts a interval (as defined by the PTP spec) to a duration

+
source

pub fn abs(self) -> Duration

Takes the absolute (non-negative) value of the duration

+

Trait Implementations§

source§

impl Add<Duration> for Duration

§

type Output = Duration

The resulting type after applying the + operator.
source§

fn add(self, rhs: Duration) -> Self::Output

Performs the + operation. Read more
source§

impl Add<Duration> for Time

§

type Output = Time

The resulting type after applying the + operator.
source§

fn add(self, rhs: Duration) -> Self::Output

Performs the + operation. Read more
source§

impl AddAssign<Duration> for Duration

source§

fn add_assign(&mut self, rhs: Duration)

Performs the += operation. Read more
source§

impl AddAssign<Duration> for Time

source§

fn add_assign(&mut self, rhs: Duration)

Performs the += operation. Read more
source§

impl Clone for Duration

source§

fn clone(&self) -> Duration

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Duration

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Duration

source§

fn default() -> Duration

Returns the “default value” for a type. Read more
source§

impl Display for Duration

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<TF: ToFixed> Div<TF> for Duration

§

type Output = Duration

The resulting type after applying the / operator.
source§

fn div(self, rhs: TF) -> Self::Output

Performs the / operation. Read more
source§

impl<TF: ToFixed> DivAssign<TF> for Duration

source§

fn div_assign(&mut self, rhs: TF)

Performs the /= operation. Read more
source§

impl From<Duration> for Duration

source§

fn from(value: Duration) -> Self

Converts to this type from the input type.
source§

impl Hash for Duration

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl<TF: ToFixed> Mul<TF> for Duration

§

type Output = Duration

The resulting type after applying the * operator.
source§

fn mul(self, rhs: TF) -> Self::Output

Performs the * operation. Read more
source§

impl<TF: ToFixed> MulAssign<TF> for Duration

source§

fn mul_assign(&mut self, rhs: TF)

Performs the *= operation. Read more
source§

impl Neg for Duration

§

type Output = Duration

The resulting type after applying the - operator.
source§

fn neg(self) -> Self::Output

Performs the unary - operation. Read more
source§

impl Ord for Duration

source§

fn cmp(&self, other: &Duration) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere + Self: Sized + PartialOrd<Self>,

Restrict a value to a certain interval. Read more
source§

impl PartialEq<Duration> for Duration

source§

fn eq(&self, other: &Duration) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd<Duration> for Duration

source§

fn partial_cmp(&self, other: &Duration) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Rem<Duration> for Duration

§

type Output = Duration

The resulting type after applying the % operator.
source§

fn rem(self, rhs: Self) -> Self::Output

Performs the % operation. Read more
source§

impl RemAssign<Duration> for Duration

source§

fn rem_assign(&mut self, rhs: Self)

Performs the %= operation. Read more
source§

impl Sub<Duration> for Duration

§

type Output = Duration

The resulting type after applying the - operator.
source§

fn sub(self, rhs: Duration) -> Self::Output

Performs the - operation. Read more
source§

impl Sub<Duration> for Time

§

type Output = Time

The resulting type after applying the - operator.
source§

fn sub(self, rhs: Duration) -> Self::Output

Performs the - operation. Read more
source§

impl SubAssign<Duration> for Duration

source§

fn sub_assign(&mut self, rhs: Duration)

Performs the -= operation. Read more
source§

impl SubAssign<Duration> for Time

source§

fn sub_assign(&mut self, rhs: Duration)

Performs the -= operation. Read more
source§

impl Copy for Duration

source§

impl Eq for Duration

source§

impl StructuralEq for Duration

source§

impl StructuralPartialEq for Duration

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for Twhere + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.FuzzMessage.html b/docs/statime/struct.FuzzMessage.html new file mode 100644 index 000000000..5656eb55b --- /dev/null +++ b/docs/statime/struct.FuzzMessage.html @@ -0,0 +1,29 @@ +FuzzMessage in statime - Rust

Struct statime::FuzzMessage

source ·
pub struct FuzzMessage<'a> { /* private fields */ }

Implementations§

source§

impl<'a> FuzzMessage<'a>

source

pub fn deserialize(buffer: &'a [u8]) -> Result<Self, impl Error>

source

pub fn serialize(&self, buffer: &mut [u8]) -> Result<usize, impl Error>

source

pub fn tlv(&self) -> impl Iterator<Item = FuzzTlv<'_>> + '_

Trait Implementations§

source§

impl<'a> Clone for FuzzMessage<'a>

source§

fn clone(&self) -> FuzzMessage<'a>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<'a> Debug for FuzzMessage<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'a> PartialEq<FuzzMessage<'a>> for FuzzMessage<'a>

source§

fn eq(&self, other: &FuzzMessage<'a>) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl<'a> Eq for FuzzMessage<'a>

source§

impl<'a> StructuralEq for FuzzMessage<'a>

source§

impl<'a> StructuralPartialEq for FuzzMessage<'a>

Auto Trait Implementations§

§

impl<'a> RefUnwindSafe for FuzzMessage<'a>

§

impl<'a> Send for FuzzMessage<'a>

§

impl<'a> Sync for FuzzMessage<'a>

§

impl<'a> Unpin for FuzzMessage<'a>

§

impl<'a> UnwindSafe for FuzzMessage<'a>

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.InBmca.html b/docs/statime/struct.InBmca.html new file mode 100644 index 000000000..737d3d3ee --- /dev/null +++ b/docs/statime/struct.InBmca.html @@ -0,0 +1,26 @@ +InBmca in statime - Rust

Struct statime::InBmca

source ·
pub struct InBmca<'a> { /* private fields */ }

Trait Implementations§

source§

impl<'a> Debug for InBmca<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> !RefUnwindSafe for InBmca<'a>

§

impl<'a> Send for InBmca<'a>

§

impl<'a> Sync for InBmca<'a>

§

impl<'a> Unpin for InBmca<'a>

§

impl<'a> !UnwindSafe for InBmca<'a>

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.InstanceConfig.html b/docs/statime/struct.InstanceConfig.html new file mode 100644 index 000000000..6864ce045 --- /dev/null +++ b/docs/statime/struct.InstanceConfig.html @@ -0,0 +1,38 @@ +InstanceConfig in statime - Rust

Struct statime::InstanceConfig

source ·
pub struct InstanceConfig {
+    pub clock_identity: ClockIdentity,
+    pub priority_1: u8,
+    pub priority_2: u8,
+    pub domain_number: u8,
+    pub slave_only: bool,
+    pub sdo_id: SdoId,
+}

Fields§

§clock_identity: ClockIdentity§priority_1: u8§priority_2: u8§domain_number: u8§slave_only: bool§sdo_id: SdoId

Trait Implementations§

source§

impl Clone for InstanceConfig

source§

fn clone(&self) -> InstanceConfig

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for InstanceConfig

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Hash for InstanceConfig

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl PartialEq<InstanceConfig> for InstanceConfig

source§

fn eq(&self, other: &InstanceConfig) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for InstanceConfig

source§

impl Eq for InstanceConfig

source§

impl StructuralEq for InstanceConfig

source§

impl StructuralPartialEq for InstanceConfig

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.Interval.html b/docs/statime/struct.Interval.html new file mode 100644 index 000000000..4cc814748 --- /dev/null +++ b/docs/statime/struct.Interval.html @@ -0,0 +1,36 @@ +Interval in statime - Rust

Struct statime::Interval

source ·
pub struct Interval(/* private fields */);

Implementations§

source§

impl Interval

source

pub const ONE_SECOND: Self = _

source

pub const TWO_SECONDS: Self = _

source

pub const fn from_log_2(log_2: i8) -> Self

source

pub fn seconds(self) -> f64

source

pub fn as_duration(self) -> Duration

source

pub fn as_core_duration(self) -> Duration

source

pub fn as_f64(self) -> f64

source

pub fn as_log_2(self) -> i8

Trait Implementations§

source§

impl Clone for Interval

source§

fn clone(&self) -> Interval

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Interval

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<i8> for Interval

source§

fn from(value: i8) -> Self

Converts to this type from the input type.
source§

impl Hash for Interval

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl Ord for Interval

source§

fn cmp(&self, other: &Interval) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere + Self: Sized + PartialOrd<Self>,

Restrict a value to a certain interval. Read more
source§

impl PartialEq<Interval> for Interval

source§

fn eq(&self, other: &Interval) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd<Interval> for Interval

source§

fn partial_cmp(&self, other: &Interval) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Copy for Interval

source§

impl Eq for Interval

source§

impl StructuralEq for Interval

source§

impl StructuralPartialEq for Interval

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.Measurement.html b/docs/statime/struct.Measurement.html new file mode 100644 index 000000000..f4051418c --- /dev/null +++ b/docs/statime/struct.Measurement.html @@ -0,0 +1,43 @@ +Measurement in statime - Rust

Struct statime::Measurement

source ·
pub struct Measurement {
+    pub event_time: Time,
+    pub offset: Option<Duration>,
+    pub delay: Option<Duration>,
+    pub raw_sync_offset: Option<Duration>,
+    pub raw_delay_offset: Option<Duration>,
+}
Expand description

A single measurement as produced by a PTP port. +Depending on what trigerred the measurements, not +all fields will be populated

+

Fields§

§event_time: Time

Time this measurement was made.

+
§offset: Option<Duration>

Offset to the remote PTP node.

+
§delay: Option<Duration>

Delay to the remote PTP node.

+
§raw_sync_offset: Option<Duration>

Raw offset calculated from a sync message

+
§raw_delay_offset: Option<Duration>

Raw offset calculated from a delay message

+

Trait Implementations§

source§

impl Clone for Measurement

source§

fn clone(&self) -> Measurement

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Measurement

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Measurement

source§

fn default() -> Measurement

Returns the “default value” for a type. Read more
source§

impl PartialEq<Measurement> for Measurement

source§

fn eq(&self, other: &Measurement) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for Measurement

source§

impl Eq for Measurement

source§

impl StructuralEq for Measurement

source§

impl StructuralPartialEq for Measurement

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.Port.html b/docs/statime/struct.Port.html new file mode 100644 index 000000000..c2ddf2022 --- /dev/null +++ b/docs/statime/struct.Port.html @@ -0,0 +1,69 @@ +Port in statime - Rust

Struct statime::Port

source ·
pub struct Port<L, A, R, C, F: Filter> { /* private fields */ }
Expand description

A single port of the PTP instance

+

One of these needs to be created per port of the PTP instance.

+

Implementations§

source§

impl<'a, A, C: Clock, F: Filter, R: Rng> Port<Running<'a>, A, R, C, F>

source§

impl<'a, A: AcceptableMasterList, C: Clock, F: Filter, R: Rng> Port<Running<'a>, A, R, C, F>

source

pub fn handle_timecritical_receive( + &mut self, + data: &[u8], + timestamp: Time +) -> PortActionIterator<'_>

source

pub fn handle_general_receive(&mut self, data: &[u8]) -> PortActionIterator<'_>

source§

impl<'a, A, C, F: Filter, R> Port<InBmca<'a>, A, R, C, F>

source

pub fn end_bmca( + self +) -> (Port<Running<'a>, A, R, C, F>, PortActionIterator<'static>)

source§

impl<L, A, R, C, F: Filter> Port<L, A, R, C, F>

source

pub fn is_steering(&self) -> bool

Trait Implementations§

source§

impl<L: Debug, A: Debug, R: Debug, C: Debug, F: Debug + Filter> Debug for Port<L, A, R, C, F>where + F::Config: Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<L, A, R, C, F> RefUnwindSafe for Port<L, A, R, C, F>where + A: RefUnwindSafe, + C: RefUnwindSafe, + F: RefUnwindSafe, + L: RefUnwindSafe, + R: RefUnwindSafe, + <F as Filter>::Config: RefUnwindSafe,

§

impl<L, A, R, C, F> Send for Port<L, A, R, C, F>where + A: Send, + C: Send, + F: Send, + L: Send, + R: Send, + <F as Filter>::Config: Send,

§

impl<L, A, R, C, F> Sync for Port<L, A, R, C, F>where + A: Sync, + C: Sync, + F: Sync, + L: Sync, + R: Sync, + <F as Filter>::Config: Sync,

§

impl<L, A, R, C, F> Unpin for Port<L, A, R, C, F>where + A: Unpin, + C: Unpin, + F: Unpin, + L: Unpin, + R: Unpin, + <F as Filter>::Config: Unpin,

§

impl<L, A, R, C, F> UnwindSafe for Port<L, A, R, C, F>where + A: UnwindSafe, + C: UnwindSafe, + F: UnwindSafe, + L: UnwindSafe, + R: UnwindSafe, + <F as Filter>::Config: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.PortActionIterator.html b/docs/statime/struct.PortActionIterator.html new file mode 100644 index 000000000..e7b5c70e9 --- /dev/null +++ b/docs/statime/struct.PortActionIterator.html @@ -0,0 +1,216 @@ +PortActionIterator in statime - Rust
pub struct PortActionIterator<'a> { /* private fields */ }
Expand description

Guarantees to end user: Any set of actions will only ever contain a single +time critical send

+

Implementations§

source§

impl<'a> PortActionIterator<'a>

source

pub fn empty() -> Self

Trait Implementations§

source§

impl<'a> Debug for PortActionIterator<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'a> Iterator for PortActionIterator<'a>

§

type Item = PortAction<'a>

The type of the elements being iterated over.
source§

fn next(&mut self) -> Option<Self::Item>

Advances the iterator and returns the next value. Read more
source§

fn next_chunk<const N: usize>( + &mut self +) -> Result<[Self::Item; N], IntoIter<Self::Item, N>>where + Self: Sized,

🔬This is a nightly-only experimental API. (iter_next_chunk)
Advances the iterator and returns an array containing the next N values. Read more
1.0.0 · source§

fn size_hint(&self) -> (usize, Option<usize>)

Returns the bounds on the remaining length of the iterator. Read more
1.0.0 · source§

fn count(self) -> usizewhere + Self: Sized,

Consumes the iterator, counting the number of iterations and returning it. Read more
1.0.0 · source§

fn last(self) -> Option<Self::Item>where + Self: Sized,

Consumes the iterator, returning the last element. Read more
source§

fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>

🔬This is a nightly-only experimental API. (iter_advance_by)
Advances the iterator by n elements. Read more
1.0.0 · source§

fn nth(&mut self, n: usize) -> Option<Self::Item>

Returns the nth element of the iterator. Read more
1.28.0 · source§

fn step_by(self, step: usize) -> StepBy<Self>where + Self: Sized,

Creates an iterator starting at the same point, but stepping by +the given amount at each iteration. Read more
1.0.0 · source§

fn chain<U>(self, other: U) -> Chain<Self, <U as IntoIterator>::IntoIter>where + Self: Sized, + U: IntoIterator<Item = Self::Item>,

Takes two iterators and creates a new iterator over both in sequence. Read more
1.0.0 · source§

fn zip<U>(self, other: U) -> Zip<Self, <U as IntoIterator>::IntoIter>where + Self: Sized, + U: IntoIterator,

‘Zips up’ two iterators into a single iterator of pairs. Read more
source§

fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>where + Self: Sized, + G: FnMut() -> Self::Item,

🔬This is a nightly-only experimental API. (iter_intersperse)
Creates a new iterator which places an item generated by separator +between adjacent items of the original iterator. Read more
1.0.0 · source§

fn map<B, F>(self, f: F) -> Map<Self, F>where + Self: Sized, + F: FnMut(Self::Item) -> B,

Takes a closure and creates an iterator which calls that closure on each +element. Read more
1.21.0 · source§

fn for_each<F>(self, f: F)where + Self: Sized, + F: FnMut(Self::Item),

Calls a closure on each element of an iterator. Read more
1.0.0 · source§

fn filter<P>(self, predicate: P) -> Filter<Self, P>where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Creates an iterator which uses a closure to determine if an element +should be yielded. Read more
1.0.0 · source§

fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>where + Self: Sized, + F: FnMut(Self::Item) -> Option<B>,

Creates an iterator that both filters and maps. Read more
1.0.0 · source§

fn enumerate(self) -> Enumerate<Self>where + Self: Sized,

Creates an iterator which gives the current iteration count as well as +the next value. Read more
1.0.0 · source§

fn peekable(self) -> Peekable<Self>where + Self: Sized,

Creates an iterator which can use the peek and peek_mut methods +to look at the next element of the iterator without consuming it. See +their documentation for more information. Read more
1.0.0 · source§

fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Creates an iterator that skips elements based on a predicate. Read more
1.0.0 · source§

fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Creates an iterator that yields elements based on a predicate. Read more
1.57.0 · source§

fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>where + Self: Sized, + P: FnMut(Self::Item) -> Option<B>,

Creates an iterator that both yields elements based on a predicate and maps. Read more
1.0.0 · source§

fn skip(self, n: usize) -> Skip<Self>where + Self: Sized,

Creates an iterator that skips the first n elements. Read more
1.0.0 · source§

fn take(self, n: usize) -> Take<Self>where + Self: Sized,

Creates an iterator that yields the first n elements, or fewer +if the underlying iterator ends sooner. Read more
1.0.0 · source§

fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>where + Self: Sized, + F: FnMut(&mut St, Self::Item) -> Option<B>,

An iterator adapter which, like fold, holds internal state, but +unlike fold, produces a new iterator. Read more
1.0.0 · source§

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>where + Self: Sized, + U: IntoIterator, + F: FnMut(Self::Item) -> U,

Creates an iterator that works like map, but flattens nested structure. Read more
source§

fn map_windows<F, R, const N: usize>(self, f: F) -> MapWindows<Self, F, N>where + Self: Sized, + F: FnMut(&[Self::Item; N]) -> R,

🔬This is a nightly-only experimental API. (iter_map_windows)
Calls the given function f for each contiguous window of size N over +self and returns an iterator over the outputs of f. Like slice::windows(), +the windows during mapping overlap as well. Read more
1.0.0 · source§

fn fuse(self) -> Fuse<Self>where + Self: Sized,

Creates an iterator which ends after the first None. Read more
1.0.0 · source§

fn inspect<F>(self, f: F) -> Inspect<Self, F>where + Self: Sized, + F: FnMut(&Self::Item),

Does something with each element of an iterator, passing the value on. Read more
1.0.0 · source§

fn by_ref(&mut self) -> &mut Selfwhere + Self: Sized,

Borrows an iterator, rather than consuming it. Read more
1.0.0 · source§

fn collect<B>(self) -> Bwhere + B: FromIterator<Self::Item>, + Self: Sized,

Transforms an iterator into a collection. Read more
source§

fn collect_into<E>(self, collection: &mut E) -> &mut Ewhere + E: Extend<Self::Item>, + Self: Sized,

🔬This is a nightly-only experimental API. (iter_collect_into)
Collects all the items from an iterator into a collection. Read more
1.0.0 · source§

fn partition<B, F>(self, f: F) -> (B, B)where + Self: Sized, + B: Default + Extend<Self::Item>, + F: FnMut(&Self::Item) -> bool,

Consumes an iterator, creating two collections from it. Read more
source§

fn is_partitioned<P>(self, predicate: P) -> boolwhere + Self: Sized, + P: FnMut(Self::Item) -> bool,

🔬This is a nightly-only experimental API. (iter_is_partitioned)
Checks if the elements of this iterator are partitioned according to the given predicate, +such that all those that return true precede all those that return false. Read more
1.27.0 · source§

fn try_fold<B, F, R>(&mut self, init: B, f: F) -> Rwhere + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>,

An iterator method that applies a function as long as it returns +successfully, producing a single, final value. Read more
1.27.0 · source§

fn try_for_each<F, R>(&mut self, f: F) -> Rwhere + Self: Sized, + F: FnMut(Self::Item) -> R, + R: Try<Output = ()>,

An iterator method that applies a fallible function to each item in the +iterator, stopping at the first error and returning that error. Read more
1.0.0 · source§

fn fold<B, F>(self, init: B, f: F) -> Bwhere + Self: Sized, + F: FnMut(B, Self::Item) -> B,

Folds every element into an accumulator by applying an operation, +returning the final result. Read more
1.51.0 · source§

fn reduce<F>(self, f: F) -> Option<Self::Item>where + Self: Sized, + F: FnMut(Self::Item, Self::Item) -> Self::Item,

Reduces the elements to a single one, by repeatedly applying a reducing +operation. Read more
source§

fn try_reduce<F, R>( + &mut self, + f: F +) -> <<R as Try>::Residual as Residual<Option<<R as Try>::Output>>>::TryTypewhere + Self: Sized, + F: FnMut(Self::Item, Self::Item) -> R, + R: Try<Output = Self::Item>, + <R as Try>::Residual: Residual<Option<Self::Item>>,

🔬This is a nightly-only experimental API. (iterator_try_reduce)
Reduces the elements to a single one by repeatedly applying a reducing operation. If the +closure returns a failure, the failure is propagated back to the caller immediately. Read more
1.0.0 · source§

fn all<F>(&mut self, f: F) -> boolwhere + Self: Sized, + F: FnMut(Self::Item) -> bool,

Tests if every element of the iterator matches a predicate. Read more
1.0.0 · source§

fn any<F>(&mut self, f: F) -> boolwhere + Self: Sized, + F: FnMut(Self::Item) -> bool,

Tests if any element of the iterator matches a predicate. Read more
1.0.0 · source§

fn find<P>(&mut self, predicate: P) -> Option<Self::Item>where + Self: Sized, + P: FnMut(&Self::Item) -> bool,

Searches for an element of an iterator that satisfies a predicate. Read more
1.30.0 · source§

fn find_map<B, F>(&mut self, f: F) -> Option<B>where + Self: Sized, + F: FnMut(Self::Item) -> Option<B>,

Applies function to the elements of iterator and returns +the first non-none result. Read more
source§

fn try_find<F, R>( + &mut self, + f: F +) -> <<R as Try>::Residual as Residual<Option<Self::Item>>>::TryTypewhere + Self: Sized, + F: FnMut(&Self::Item) -> R, + R: Try<Output = bool>, + <R as Try>::Residual: Residual<Option<Self::Item>>,

🔬This is a nightly-only experimental API. (try_find)
Applies function to the elements of iterator and returns +the first true result or the first error. Read more
1.0.0 · source§

fn position<P>(&mut self, predicate: P) -> Option<usize>where + Self: Sized, + P: FnMut(Self::Item) -> bool,

Searches for an element in an iterator, returning its index. Read more
1.6.0 · source§

fn max_by_key<B, F>(self, f: F) -> Option<Self::Item>where + B: Ord, + Self: Sized, + F: FnMut(&Self::Item) -> B,

Returns the element that gives the maximum value from the +specified function. Read more
1.15.0 · source§

fn max_by<F>(self, compare: F) -> Option<Self::Item>where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Ordering,

Returns the element that gives the maximum value with respect to the +specified comparison function. Read more
1.6.0 · source§

fn min_by_key<B, F>(self, f: F) -> Option<Self::Item>where + B: Ord, + Self: Sized, + F: FnMut(&Self::Item) -> B,

Returns the element that gives the minimum value from the +specified function. Read more
1.15.0 · source§

fn min_by<F>(self, compare: F) -> Option<Self::Item>where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Ordering,

Returns the element that gives the minimum value with respect to the +specified comparison function. Read more
1.0.0 · source§

fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)where + FromA: Default + Extend<A>, + FromB: Default + Extend<B>, + Self: Sized + Iterator<Item = (A, B)>,

Converts an iterator of pairs into a pair of containers. Read more
1.36.0 · source§

fn copied<'a, T>(self) -> Copied<Self>where + T: 'a + Copy, + Self: Sized + Iterator<Item = &'a T>,

Creates an iterator which copies all of its elements. Read more
1.0.0 · source§

fn cloned<'a, T>(self) -> Cloned<Self>where + T: 'a + Clone, + Self: Sized + Iterator<Item = &'a T>,

Creates an iterator which clones all of its elements. Read more
source§

fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>where + Self: Sized,

🔬This is a nightly-only experimental API. (iter_array_chunks)
Returns an iterator over N elements of the iterator at a time. Read more
1.11.0 · source§

fn sum<S>(self) -> Swhere + Self: Sized, + S: Sum<Self::Item>,

Sums the elements of an iterator. Read more
1.11.0 · source§

fn product<P>(self) -> Pwhere + Self: Sized, + P: Product<Self::Item>,

Iterates over the entire iterator, multiplying all the elements Read more
source§

fn cmp_by<I, F>(self, other: I, cmp: F) -> Orderingwhere + Self: Sized, + I: IntoIterator, + F: FnMut(Self::Item, <I as IntoIterator>::Item) -> Ordering,

🔬This is a nightly-only experimental API. (iter_order_by)
Lexicographically compares the elements of this Iterator with those +of another with respect to the specified comparison function. Read more
1.5.0 · source§

fn partial_cmp<I>(self, other: I) -> Option<Ordering>where + I: IntoIterator, + Self::Item: PartialOrd<<I as IntoIterator>::Item>, + Self: Sized,

Lexicographically compares the PartialOrd elements of +this Iterator with those of another. The comparison works like short-circuit +evaluation, returning a result without comparing the remaining elements. +As soon as an order can be determined, the evaluation stops and a result is returned. Read more
source§

fn partial_cmp_by<I, F>(self, other: I, partial_cmp: F) -> Option<Ordering>where + Self: Sized, + I: IntoIterator, + F: FnMut(Self::Item, <I as IntoIterator>::Item) -> Option<Ordering>,

🔬This is a nightly-only experimental API. (iter_order_by)
Lexicographically compares the elements of this Iterator with those +of another with respect to the specified comparison function. Read more
1.5.0 · source§

fn eq<I>(self, other: I) -> boolwhere + I: IntoIterator, + Self::Item: PartialEq<<I as IntoIterator>::Item>, + Self: Sized,

Determines if the elements of this Iterator are equal to those of +another. Read more
source§

fn eq_by<I, F>(self, other: I, eq: F) -> boolwhere + Self: Sized, + I: IntoIterator, + F: FnMut(Self::Item, <I as IntoIterator>::Item) -> bool,

🔬This is a nightly-only experimental API. (iter_order_by)
Determines if the elements of this Iterator are equal to those of +another with respect to the specified equality function. Read more
1.5.0 · source§

fn ne<I>(self, other: I) -> boolwhere + I: IntoIterator, + Self::Item: PartialEq<<I as IntoIterator>::Item>, + Self: Sized,

Determines if the elements of this Iterator are not equal to those of +another. Read more
1.5.0 · source§

fn lt<I>(self, other: I) -> boolwhere + I: IntoIterator, + Self::Item: PartialOrd<<I as IntoIterator>::Item>, + Self: Sized,

Determines if the elements of this Iterator are lexicographically +less than those of another. Read more
1.5.0 · source§

fn le<I>(self, other: I) -> boolwhere + I: IntoIterator, + Self::Item: PartialOrd<<I as IntoIterator>::Item>, + Self: Sized,

Determines if the elements of this Iterator are lexicographically +less or equal to those of another. Read more
1.5.0 · source§

fn gt<I>(self, other: I) -> boolwhere + I: IntoIterator, + Self::Item: PartialOrd<<I as IntoIterator>::Item>, + Self: Sized,

Determines if the elements of this Iterator are lexicographically +greater than those of another. Read more
1.5.0 · source§

fn ge<I>(self, other: I) -> boolwhere + I: IntoIterator, + Self::Item: PartialOrd<<I as IntoIterator>::Item>, + Self: Sized,

Determines if the elements of this Iterator are lexicographically +greater than or equal to those of another. Read more
source§

fn is_sorted_by<F>(self, compare: F) -> boolwhere + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,

🔬This is a nightly-only experimental API. (is_sorted)
Checks if the elements of this iterator are sorted using the given comparator function. Read more
source§

fn is_sorted_by_key<F, K>(self, f: F) -> boolwhere + Self: Sized, + F: FnMut(Self::Item) -> K, + K: PartialOrd<K>,

🔬This is a nightly-only experimental API. (is_sorted)
Checks if the elements of this iterator are sorted using the given key extraction +function. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<I> IntoIterator for Iwhere + I: Iterator,

§

type Item = <I as Iterator>::Item

The type of the elements being iterated over.
§

type IntoIter = I

Which kind of iterator are we turning this into?
const: unstable · source§

fn into_iter(self) -> I

Creates an iterator from a value. Read more
source§

impl<I> IteratorRandom for Iwhere + I: Iterator,

source§

fn choose<R>(self, rng: &mut R) -> Option<Self::Item>where + R: Rng + ?Sized,

Choose one element at random from the iterator. Read more
source§

fn choose_stable<R>(self, rng: &mut R) -> Option<Self::Item>where + R: Rng + ?Sized,

Choose one element at random from the iterator. Read more
source§

fn choose_multiple_fill<R>(self, rng: &mut R, buf: &mut [Self::Item]) -> usizewhere + R: Rng + ?Sized,

Collects values at random from the iterator into a supplied buffer +until that buffer is filled. Read more
source§

fn choose_multiple<R>( + self, + rng: &mut R, + amount: usize +) -> Vec<Self::Item, Global>where + R: Rng + ?Sized,

Collects amount values at random from the iterator into a vector. Read more
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.PortConfig.html b/docs/statime/struct.PortConfig.html new file mode 100644 index 000000000..17c700fff --- /dev/null +++ b/docs/statime/struct.PortConfig.html @@ -0,0 +1,46 @@ +PortConfig in statime - Rust

Struct statime::PortConfig

source ·
pub struct PortConfig<A> {
+    pub acceptable_master_list: A,
+    pub delay_mechanism: DelayMechanism,
+    pub announce_interval: Interval,
+    pub announce_receipt_timeout: u8,
+    pub sync_interval: Interval,
+    pub master_only: bool,
+    pub delay_asymmetry: Duration,
+}
Expand description

Configuration items of the PTP PortDS dataset. Dynamical fields are kept +as part of crate::port::Port.

+

Fields§

§acceptable_master_list: A§delay_mechanism: DelayMechanism§announce_interval: Interval§announce_receipt_timeout: u8§sync_interval: Interval§master_only: bool§delay_asymmetry: Duration

Implementations§

source§

impl<A> PortConfig<A>

source

pub fn min_delay_req_interval(&self) -> Interval

source

pub fn announce_duration(&self, rng: &mut impl Rng) -> Duration

Trait Implementations§

source§

impl<A: Clone> Clone for PortConfig<A>

source§

fn clone(&self) -> PortConfig<A>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<A: Debug> Debug for PortConfig<A>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<A: Hash> Hash for PortConfig<A>

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl<A: PartialEq> PartialEq<PortConfig<A>> for PortConfig<A>

source§

fn eq(&self, other: &PortConfig<A>) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl<A: Copy> Copy for PortConfig<A>

source§

impl<A: Eq> Eq for PortConfig<A>

source§

impl<A> StructuralEq for PortConfig<A>

source§

impl<A> StructuralPartialEq for PortConfig<A>

Auto Trait Implementations§

§

impl<A> RefUnwindSafe for PortConfig<A>where + A: RefUnwindSafe,

§

impl<A> Send for PortConfig<A>where + A: Send,

§

impl<A> Sync for PortConfig<A>where + A: Sync,

§

impl<A> Unpin for PortConfig<A>where + A: Unpin,

§

impl<A> UnwindSafe for PortConfig<A>where + A: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.PtpInstance.html b/docs/statime/struct.PtpInstance.html new file mode 100644 index 000000000..dc3f6738b --- /dev/null +++ b/docs/statime/struct.PtpInstance.html @@ -0,0 +1,85 @@ +PtpInstance in statime - Rust

Struct statime::PtpInstance

source ·
pub struct PtpInstance<F> { /* private fields */ }
Expand description

A PTP node.

+

This object handles the complete running of the PTP protocol once created. +It provides all the logic for both ordinary and boundary clock mode.

+

Example

+

Assuming we already have a network runtime and clock runtime, an ordinary +clock can be run by first creating all the datasets, then creating the port, +then finally setting up the instance and starting it:

+ +
let default_ds = DefaultDS::new_ordinary_clock(
+    clock_identity,
+    128,
+    128,
+    0,
+    false,
+    SdoId::new(0).unwrap(),
+);
+let time_properties_ds =
+TimePropertiesDS::new_arbitrary_time(false, false, TimeSource::InternalOscillator);
+let port_ds = PortDS::new(
+    PortIdentity {
+        clock_identity,
+        port_number: 1,
+    },
+    1,
+    1,
+    3,
+    0,
+    DelayMechanism::E2E,
+    1,
+);
+let port = Port::new(port_ds, &mut network_runtime, interface_name).await;
+let mut instance = PtpInstance::new_ordinary_clock(
+    default_ds,
+    time_properties_ds,
+    port,
+    local_clock,
+    BasicFilter::new(0.25),
+);
+
+instance.run(&TimerImpl).await;
+

Implementations§

source§

impl<F> PtpInstance<F>

source

pub fn new(config: InstanceConfig, time_properties_ds: TimePropertiesDS) -> Self

source§

impl<F: Filter> PtpInstance<F>

source

pub fn add_port<A, C, R: Rng>( + &self, + config: PortConfig<A>, + filter_config: F::Config, + clock: C, + rng: R +) -> Port<InBmca<'_>, A, R, C, F>

Add and initialize this port

+

We start in the BMCA state because that is convenient

+

When providing the port with a different clock than the instance clock, +the caller is responsible for propagating any property changes to this +clock, and for synchronizing this clock with the instance clock as +appropriate based on the ports state.

+
source

pub fn bmca<A: AcceptableMasterList, C: Clock, R: Rng>( + &self, + ports: &mut [&mut Port<InBmca<'_>, A, R, C, F>] +)

source

pub fn bmca_interval(&self) -> Duration

Auto Trait Implementations§

§

impl<F> !RefUnwindSafe for PtpInstance<F>

§

impl<F> Send for PtpInstance<F>where + F: Send,

§

impl<F> Sync for PtpInstance<F>where + F: Sync,

§

impl<F> Unpin for PtpInstance<F>where + F: Unpin,

§

impl<F> UnwindSafe for PtpInstance<F>where + F: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.Running.html b/docs/statime/struct.Running.html new file mode 100644 index 000000000..11eba1a75 --- /dev/null +++ b/docs/statime/struct.Running.html @@ -0,0 +1,26 @@ +Running in statime - Rust

Struct statime::Running

source ·
pub struct Running<'a> { /* private fields */ }

Trait Implementations§

source§

impl<'a> Debug for Running<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> !RefUnwindSafe for Running<'a>

§

impl<'a> Send for Running<'a>

§

impl<'a> Sync for Running<'a>

§

impl<'a> Unpin for Running<'a>

§

impl<'a> !UnwindSafe for Running<'a>

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.SdoId.html b/docs/statime/struct.SdoId.html new file mode 100644 index 000000000..034363c0b --- /dev/null +++ b/docs/statime/struct.SdoId.html @@ -0,0 +1,37 @@ +SdoId in statime - Rust

Struct statime::SdoId

source ·
pub struct SdoId(/* private fields */);
Expand description

A wrapper type for PTP Sdo Identifiers.

+

This is a separate type as sdo identifiers should be in the range 0-4095

+

Implementations§

source§

impl SdoId

source

pub fn new(sdo_id: u16) -> Option<Self>

Create a new sdo id

+

This function only returns an SdoId instance if the given identifier +is actually between 0 and 4095. Otherwise, None is returned.

+

Trait Implementations§

source§

impl Clone for SdoId

source§

fn clone(&self) -> SdoId

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for SdoId

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for SdoId

source§

fn default() -> SdoId

Returns the “default value” for a type. Read more
source§

impl Display for SdoId

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Hash for SdoId

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where + H: Hasher, + Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl PartialEq<SdoId> for SdoId

source§

fn eq(&self, other: &SdoId) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for SdoId

source§

impl Eq for SdoId

source§

impl StructuralEq for SdoId

source§

impl StructuralPartialEq for SdoId

Auto Trait Implementations§

§

impl RefUnwindSafe for SdoId

§

impl Send for SdoId

§

impl Sync for SdoId

§

impl Unpin for SdoId

§

impl UnwindSafe for SdoId

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for Twhere + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.Time.html b/docs/statime/struct.Time.html new file mode 100644 index 000000000..fc0b2bfd9 --- /dev/null +++ b/docs/statime/struct.Time.html @@ -0,0 +1,48 @@ +Time in statime - Rust

Struct statime::Time

source ·
pub struct Time { /* private fields */ }
Expand description

Time represents a specific moment in time.

+

The starting 0 point depends on the timescale being used by PTP, but +for most uses will be the unix epoch.

+

Implementations§

source§

impl Time

source

pub fn from_secs(secs: u64) -> Self

Create an instance with the given amount of seconds from the origin

+
source

pub fn from_millis(millis: u64) -> Self

Create an instance with the given amount of milliseconds from the origin

+
source

pub fn from_micros(micros: u64) -> Self

Create an instance with the given amount of microseconds from the origin

+
source

pub fn from_nanos(nanos: u64) -> Self

Create an instance with the given amount of nanoseconds from the origin

+
source

pub fn from_fixed_nanos<F: ToFixed>(nanos: F) -> Self

Create an instance with the given amount of nanoseconds from the origin, +using a fixed point number so the subnanoseconds can be specified as +well

+
source

pub fn from_nanos_subnanos(nanos: u64, subnanos: u32) -> Self

source

pub fn nanos(&self) -> U96F32

Get the total amount of nanoseconds since the origin

+
source

pub fn subsec_nanos(&self) -> u32

Get all the nanoseconds that are under a second

+
source

pub fn secs(&self) -> u64

Get the total amount of seconds since the origin

+

Trait Implementations§

source§

impl Add<Duration> for Time

§

type Output = Time

The resulting type after applying the + operator.
source§

fn add(self, rhs: Duration) -> Self::Output

Performs the + operation. Read more
source§

impl AddAssign<Duration> for Time

source§

fn add_assign(&mut self, rhs: Duration)

Performs the += operation. Read more
source§

impl Clone for Time

source§

fn clone(&self) -> Time

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Time

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Time

source§

fn default() -> Time

Returns the “default value” for a type. Read more
source§

impl Display for Time

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Ord for Time

source§

fn cmp(&self, other: &Time) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere + Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere + Self: Sized + PartialOrd<Self>,

Restrict a value to a certain interval. Read more
source§

impl PartialEq<Time> for Time

source§

fn eq(&self, other: &Time) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl PartialOrd<Time> for Time

source§

fn partial_cmp(&self, other: &Time) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
source§

impl Sub<Duration> for Time

§

type Output = Time

The resulting type after applying the - operator.
source§

fn sub(self, rhs: Duration) -> Self::Output

Performs the - operation. Read more
source§

impl Sub<Time> for Time

§

type Output = Duration

The resulting type after applying the - operator.
source§

fn sub(self, rhs: Time) -> Self::Output

Performs the - operation. Read more
source§

impl SubAssign<Duration> for Time

source§

fn sub_assign(&mut self, rhs: Duration)

Performs the -= operation. Read more
source§

impl Copy for Time

source§

impl Eq for Time

source§

impl StructuralEq for Time

source§

impl StructuralPartialEq for Time

Auto Trait Implementations§

§

impl RefUnwindSafe for Time

§

impl Send for Time

§

impl Sync for Time

§

impl Unpin for Time

§

impl UnwindSafe for Time

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for Twhere + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.TimePropertiesDS.html b/docs/statime/struct.TimePropertiesDS.html new file mode 100644 index 000000000..2c9f70066 --- /dev/null +++ b/docs/statime/struct.TimePropertiesDS.html @@ -0,0 +1,57 @@ +TimePropertiesDS in statime - Rust
pub struct TimePropertiesDS { /* private fields */ }
Expand description

A concrete implementation of the PTP Time Properties dataset (IEEE1588-2019 +section 8.2.4

+

This dataset describes the timescale currently in use, as well as any +upcoming leap seconds on that timescale.

+

Implementations§

source§

impl TimePropertiesDS

source

pub fn new_ptp_time( + current_utc_offset: Option<i16>, + leap_indicator: LeapIndicator, + time_traceable: bool, + frequency_traceable: bool, + time_source: TimeSource +) -> Self

Create a Time Properties data set for the PTP timescale.

+

This creates a dataset for the default PTP timescale, which is UTC +seconds since the PTP epoch excluding leap seconds. The traceability +properties indicate whether the current clock time and frequency can be +traced back to an internationally recognized standard in the metrology +sense of the word. When in doubt, just set these to false.

+
source

pub fn new_arbitrary_time( + time_traceable: bool, + frequency_traceable: bool, + time_source: TimeSource +) -> Self

Create a Time Properties data set for an Arbitrary timescale

+

The arbitrary timescale can be used when wanting to synchronize multiple +computers using PTP to a timescale that is unrelated to UTC. The +traceability properties indicate whether the current clock time and +frequency can be traced back to an internationally recognized standard +in the metrology sense of the word. When in doubt, just set these to +false.

+
source

pub fn is_ptp(&self) -> bool

Is the current timescale the ptp (utc-derived) timescale?

+
source

pub fn leap_indicator(&self) -> LeapIndicator

Trait Implementations§

source§

impl Clone for TimePropertiesDS

source§

fn clone(&self) -> TimePropertiesDS

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for TimePropertiesDS

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for TimePropertiesDS

source§

fn default() -> TimePropertiesDS

Returns the “default value” for a type. Read more
source§

impl PartialEq<TimePropertiesDS> for TimePropertiesDS

source§

fn eq(&self, other: &TimePropertiesDS) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for TimePropertiesDS

source§

impl Eq for TimePropertiesDS

source§

impl StructuralEq for TimePropertiesDS

source§

impl StructuralPartialEq for TimePropertiesDS

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/struct.TimestampContext.html b/docs/statime/struct.TimestampContext.html new file mode 100644 index 000000000..d877893de --- /dev/null +++ b/docs/statime/struct.TimestampContext.html @@ -0,0 +1,26 @@ +TimestampContext in statime - Rust
pub struct TimestampContext { /* private fields */ }

Trait Implementations§

source§

impl Debug for TimestampContext

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime/time/duration/struct.Duration.html b/docs/statime/time/duration/struct.Duration.html new file mode 100644 index 000000000..256029715 --- /dev/null +++ b/docs/statime/time/duration/struct.Duration.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/struct.Duration.html...

+ + + \ No newline at end of file diff --git a/docs/statime/time/instant/struct.Time.html b/docs/statime/time/instant/struct.Time.html new file mode 100644 index 000000000..4ca5936e3 --- /dev/null +++ b/docs/statime/time/instant/struct.Time.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/struct.Time.html...

+ + + \ No newline at end of file diff --git a/docs/statime/time/interval/struct.Interval.html b/docs/statime/time/interval/struct.Interval.html new file mode 100644 index 000000000..419d4e117 --- /dev/null +++ b/docs/statime/time/interval/struct.Interval.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../statime/struct.Interval.html...

+ + + \ No newline at end of file diff --git a/docs/statime/trait.Clock.html b/docs/statime/trait.Clock.html new file mode 100644 index 000000000..6cef49784 --- /dev/null +++ b/docs/statime/trait.Clock.html @@ -0,0 +1,41 @@ +Clock in statime - Rust

Trait statime::Clock

source ·
pub trait Clock {
+    type Error: Debug;
+
+    // Required methods
+    fn now(&self) -> Time;
+    fn step_clock(&mut self, offset: Duration) -> Result<Time, Self::Error>;
+    fn set_frequency(&mut self, ppm: f64) -> Result<Time, Self::Error>;
+    fn set_properties(
+        &mut self,
+        time_properties_ds: &TimePropertiesDS
+    ) -> Result<(), Self::Error>;
+}
Expand description

Clock manipulation and querying interface

+

The clock trait is the primary way the PTP stack interfaces with the +system’s clock. It’s implementation should be provided by the user of the +Statime crate, and should provide information on and ways to manipulate the +system’s clock. An implementation of this trait for linux is provided in the +statime-linux crate.

+

Note that the clock implementation is responsible for handling leap seconds. +On most operating systems, this will be provided for by the OS, but on some +platforms this may require extra logic.

+

Required Associated Types§

Required Methods§

source

fn now(&self) -> Time

Get the current time of the clock

+
source

fn step_clock(&mut self, offset: Duration) -> Result<Time, Self::Error>

Change the current time of the clock by offset. Returns +the time at which the change was applied.

+

The applied correction should be as close as possible to +the requested correction. The reported time of the change +should be as close as possible to the time the change was +applied

+
source

fn set_frequency(&mut self, ppm: f64) -> Result<Time, Self::Error>

Set the frequency of the clock, returning the time +at which the change was applied. The value is in ppm +difference from the clocks base frequency.

+

The applied correction should be as close as possible to +the requested correction. The reported time of the change +should be as close as possible to the time the change was +applied

+
source

fn set_properties( + &mut self, + time_properties_ds: &TimePropertiesDS +) -> Result<(), Self::Error>

Adjust the timescale properties of the clock, including +things like the leap indicator, to the extend supported by the +system.

+

Implementors§

\ No newline at end of file diff --git a/docs/statime/trait.Filter.html b/docs/statime/trait.Filter.html new file mode 100644 index 000000000..0f9022ad7 --- /dev/null +++ b/docs/statime/trait.Filter.html @@ -0,0 +1,29 @@ +Filter in statime - Rust

Trait statime::Filter

source ·
pub trait Filter {
+    type Config: Clone;
+
+    // Required methods
+    fn new(config: Self::Config) -> Self;
+    fn measurement<C: Clock>(
+        &mut self,
+        m: Measurement,
+        clock: &mut C
+    ) -> FilterUpdate;
+    fn update<C: Clock>(&mut self, clock: &mut C) -> FilterUpdate;
+    fn demobilize<C: Clock>(self, clock: &mut C);
+}
Expand description

A filter for post-processing time measurements.

+

Filters are responsible for dealing with the network noise, and should +average out the input a bit so minor network variations are not immediately +reflected in the synchronization of the clock.

+

This crate provides a simple BasicFilter which is +suitable for most needs, but users can implement their own if desired.

+

Required Associated Types§

Required Methods§

source

fn new(config: Self::Config) -> Self

Create a new instance of the filter.

+
source

fn measurement<C: Clock>( + &mut self, + m: Measurement, + clock: &mut C +) -> FilterUpdate

Put a new measurement in the filter. +The filter can then use this to adjust the clock

+
source

fn update<C: Clock>(&mut self, clock: &mut C) -> FilterUpdate

Update initiated through [FilterUpdate::next_update] timeout.

+
source

fn demobilize<C: Clock>(self, clock: &mut C)

Handle ending of time synchronization from the source +associated with this filter.

+

Implementors§

\ No newline at end of file diff --git a/docs/statime_linux/all.html b/docs/statime_linux/all.html new file mode 100644 index 000000000..80e82ff5b --- /dev/null +++ b/docs/statime_linux/all.html @@ -0,0 +1 @@ +List of all items in this crate
\ No newline at end of file diff --git a/docs/statime_linux/clock/fn.libc_timespec_into_instant.html b/docs/statime_linux/clock/fn.libc_timespec_into_instant.html new file mode 100644 index 000000000..9099ac07f --- /dev/null +++ b/docs/statime_linux/clock/fn.libc_timespec_into_instant.html @@ -0,0 +1 @@ +libc_timespec_into_instant in statime_linux::clock - Rust
pub fn libc_timespec_into_instant(spec: timespec) -> Time
\ No newline at end of file diff --git a/docs/statime_linux/clock/index.html b/docs/statime_linux/clock/index.html new file mode 100644 index 000000000..a4c63e645 --- /dev/null +++ b/docs/statime_linux/clock/index.html @@ -0,0 +1,2 @@ +statime_linux::clock - Rust

Module statime_linux::clock

source ·
Expand description

Implementation of the abstract clock for the linux platform

+

Structs

Functions

\ No newline at end of file diff --git a/docs/statime_linux/clock/sidebar-items.js b/docs/statime_linux/clock/sidebar-items.js new file mode 100644 index 000000000..5aaa08935 --- /dev/null +++ b/docs/statime_linux/clock/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["libc_timespec_into_instant"],"struct":["LinuxClock"]}; \ No newline at end of file diff --git a/docs/statime_linux/clock/struct.LinuxClock.html b/docs/statime_linux/clock/struct.LinuxClock.html new file mode 100644 index 000000000..00b4993ea --- /dev/null +++ b/docs/statime_linux/clock/struct.LinuxClock.html @@ -0,0 +1,53 @@ +LinuxClock in statime_linux::clock - Rust
pub struct LinuxClock {
+    pub clock: UnixClock,
+}

Fields§

§clock: UnixClock

Implementations§

source§

impl LinuxClock

source

pub const CLOCK_REALTIME: Self = _

source

pub fn open(path: impl AsRef<Path>) -> Result<Self>

Trait Implementations§

source§

impl Clock for LinuxClock

§

type Error = Error

source§

fn now(&self) -> Time

Get the current time of the clock
source§

fn set_frequency(&mut self, freq: f64) -> Result<Time, Self::Error>

Set the frequency of the clock, returning the time +at which the change was applied. The value is in ppm +difference from the clocks base frequency. Read more
source§

fn step_clock(&mut self, time_offset: Duration) -> Result<Time, Self::Error>

Change the current time of the clock by offset. Returns +the time at which the change was applied. Read more
source§

fn set_properties( + &mut self, + _time_properties: &TimePropertiesDS +) -> Result<(), Self::Error>

Adjust the timescale properties of the clock, including +things like the leap indicator, to the extend supported by the +system.
source§

impl Clock for LinuxClock

§

type Error = Error

source§

fn now(&self) -> Result<Timestamp, Self::Error>

Get the current time.
source§

fn resolution(&self) -> Result<Timestamp, Self::Error>

Get the clock’s resolution. Read more
source§

fn set_frequency(&self, frequency: f64) -> Result<Timestamp, Self::Error>

Change the frequency of the clock. +Returns the time at which the change was applied. Read more
source§

fn step_clock(&self, offset: TimeOffset) -> Result<Timestamp, Self::Error>

Change the current time of the clock by an offset. +Returns the time at which the change was applied.
source§

fn set_leap_seconds( + &self, + leap_status: LeapIndicator +) -> Result<(), Self::Error>

Change the indicators for upcoming leap seconds.
source§

fn error_estimate_update( + &self, + estimated_error: Duration, + maximum_error: Duration +) -> Result<(), Self::Error>

Provide the system with the current best estimates for the statistical +error of the clock, and the maximum deviation due to frequency error and +distance to the root clock.
source§

impl Clone for LinuxClock

source§

fn clone(&self) -> LinuxClock

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for LinuxClock

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime_linux/config/enum.ConfigError.html b/docs/statime_linux/config/enum.ConfigError.html new file mode 100644 index 000000000..0569a7b56 --- /dev/null +++ b/docs/statime_linux/config/enum.ConfigError.html @@ -0,0 +1,35 @@ +ConfigError in statime_linux::config - Rust
pub enum ConfigError {
+    Io(Error),
+    Toml(Error),
+}

Variants§

§

Io(Error)

§

Toml(Error)

Trait Implementations§

source§

impl Debug for ConfigError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for ConfigError

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Error for ConfigError

1.30.0 · source§

fn source(&self) -> Option<&(dyn Error + 'static)>

The lower-level source of this error, if any. Read more
1.0.0 · source§

fn description(&self) -> &str

👎Deprecated since 1.42.0: use the Display impl or to_string()
1.0.0 · source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToString for Twhere + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
\ No newline at end of file diff --git a/docs/statime_linux/config/enum.NetworkMode.html b/docs/statime_linux/config/enum.NetworkMode.html new file mode 100644 index 000000000..621ffa9b7 --- /dev/null +++ b/docs/statime_linux/config/enum.NetworkMode.html @@ -0,0 +1,43 @@ +NetworkMode in statime_linux::config - Rust
pub enum NetworkMode {
+    Ipv4,
+    Ipv6,
+}

Variants§

§

Ipv4

§

Ipv6

Trait Implementations§

source§

impl Clone for NetworkMode

source§

fn clone(&self) -> NetworkMode

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for NetworkMode

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for NetworkMode

source§

fn default() -> NetworkMode

Returns the “default value” for a type. Read more
source§

impl<'de> Deserialize<'de> for NetworkMode

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl PartialEq<NetworkMode> for NetworkMode

source§

fn eq(&self, other: &NetworkMode) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for NetworkMode

source§

impl Eq for NetworkMode

source§

impl StructuralEq for NetworkMode

source§

impl StructuralPartialEq for NetworkMode

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
§

impl<Q, K> Equivalent<K> for Qwhere + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Qwhere + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> DeserializeOwned for Twhere + T: for<'de> Deserialize<'de>,

\ No newline at end of file diff --git a/docs/statime_linux/config/index.html b/docs/statime_linux/config/index.html new file mode 100644 index 000000000..a358a3eb5 --- /dev/null +++ b/docs/statime_linux/config/index.html @@ -0,0 +1 @@ +statime_linux::config - Rust
\ No newline at end of file diff --git a/docs/statime_linux/config/sidebar-items.js b/docs/statime_linux/config/sidebar-items.js new file mode 100644 index 000000000..ec6dbbd8f --- /dev/null +++ b/docs/statime_linux/config/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["ConfigError","NetworkMode"],"struct":["Config","PortConfig"]}; \ No newline at end of file diff --git a/docs/statime_linux/config/struct.Config.html b/docs/statime_linux/config/struct.Config.html new file mode 100644 index 000000000..d6d688b2a --- /dev/null +++ b/docs/statime_linux/config/struct.Config.html @@ -0,0 +1,49 @@ +Config in statime_linux::config - Rust
pub struct Config {
+    pub loglevel: String,
+    pub sdo_id: u16,
+    pub domain: u8,
+    pub priority1: u8,
+    pub priority2: u8,
+    pub ports: Vec<PortConfig>,
+}

Fields§

§loglevel: String§sdo_id: u16§domain: u8§priority1: u8§priority2: u8§ports: Vec<PortConfig>

Implementations§

source§

impl Config

source

pub fn from_file(file: &Path) -> Result<Config, ConfigError>

Parse config from file

+
source

pub fn warn_when_unreasonable(&self)

Warns about unreasonable config values

+

Trait Implementations§

source§

impl Clone for Config

source§

fn clone(&self) -> Config

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Config

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for Config

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl PartialEq<Config> for Config

source§

fn eq(&self, other: &Config) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for Config

source§

impl StructuralEq for Config

source§

impl StructuralPartialEq for Config

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
§

impl<Q, K> Equivalent<K> for Qwhere + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Qwhere + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> DeserializeOwned for Twhere + T: for<'de> Deserialize<'de>,

\ No newline at end of file diff --git a/docs/statime_linux/config/struct.PortConfig.html b/docs/statime_linux/config/struct.PortConfig.html new file mode 100644 index 000000000..fb6c4ab4b --- /dev/null +++ b/docs/statime_linux/config/struct.PortConfig.html @@ -0,0 +1,51 @@ +PortConfig in statime_linux::config - Rust
pub struct PortConfig {
+    pub interface: InterfaceName,
+    pub acceptable_master_list: Option<Vec<ClockIdentity>>,
+    pub hardware_clock: Option<String>,
+    pub network_mode: NetworkMode,
+    pub announce_interval: i8,
+    pub sync_interval: i8,
+    pub announce_receipt_timeout: u8,
+    pub master_only: bool,
+    pub delay_asymetry: i64,
+    pub delay_mechanism: i8,
+}

Fields§

§interface: InterfaceName§acceptable_master_list: Option<Vec<ClockIdentity>>§hardware_clock: Option<String>§network_mode: NetworkMode§announce_interval: i8§sync_interval: i8§announce_receipt_timeout: u8§master_only: bool§delay_asymetry: i64§delay_mechanism: i8

Trait Implementations§

source§

impl Clone for PortConfig

source§

fn clone(&self) -> PortConfig

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for PortConfig

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for PortConfig

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where + __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<PortConfig> for PortConfig<Option<Vec<ClockIdentity>>>

source§

fn from(pc: PortConfig) -> Self

Converts to this type from the input type.
source§

impl PartialEq<PortConfig> for PortConfig

source§

fn eq(&self, other: &PortConfig) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Eq for PortConfig

source§

impl StructuralEq for PortConfig

source§

impl StructuralPartialEq for PortConfig

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere + T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere + Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where + T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere + Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
§

impl<Q, K> Equivalent<K> for Qwhere + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Qwhere + Q: Eq + ?Sized, + K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere + Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere + Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where + T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere + Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere + T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere + Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere + T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere + Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere + V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere + T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere + Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> DeserializeOwned for Twhere + T: for<'de> Deserialize<'de>,

\ No newline at end of file diff --git a/docs/statime_linux/index.html b/docs/statime_linux/index.html new file mode 100644 index 000000000..07152b337 --- /dev/null +++ b/docs/statime_linux/index.html @@ -0,0 +1 @@ +statime_linux - Rust

Crate statime_linux

source ·

Modules

  • Implementation of the abstract clock for the linux platform
  • Event and General sockets for linux systems
\ No newline at end of file diff --git a/docs/statime_linux/sidebar-items.js b/docs/statime_linux/sidebar-items.js new file mode 100644 index 000000000..20e7cdf1a --- /dev/null +++ b/docs/statime_linux/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["clock","config","socket"]}; \ No newline at end of file diff --git a/docs/statime_linux/socket/fn.open_ipv4_event_socket.html b/docs/statime_linux/socket/fn.open_ipv4_event_socket.html new file mode 100644 index 000000000..a5b9f01dc --- /dev/null +++ b/docs/statime_linux/socket/fn.open_ipv4_event_socket.html @@ -0,0 +1,4 @@ +open_ipv4_event_socket in statime_linux::socket - Rust
pub fn open_ipv4_event_socket(
+    interface: InterfaceName,
+    timestamping: InterfaceTimestampMode
+) -> Result<Socket<SocketAddrV4, Open>>
\ No newline at end of file diff --git a/docs/statime_linux/socket/fn.open_ipv4_general_socket.html b/docs/statime_linux/socket/fn.open_ipv4_general_socket.html new file mode 100644 index 000000000..c3a38bb9e --- /dev/null +++ b/docs/statime_linux/socket/fn.open_ipv4_general_socket.html @@ -0,0 +1,3 @@ +open_ipv4_general_socket in statime_linux::socket - Rust
pub fn open_ipv4_general_socket(
+    interface: InterfaceName
+) -> Result<Socket<SocketAddrV4, Open>>
\ No newline at end of file diff --git a/docs/statime_linux/socket/fn.open_ipv6_event_socket.html b/docs/statime_linux/socket/fn.open_ipv6_event_socket.html new file mode 100644 index 000000000..df7795e38 --- /dev/null +++ b/docs/statime_linux/socket/fn.open_ipv6_event_socket.html @@ -0,0 +1,4 @@ +open_ipv6_event_socket in statime_linux::socket - Rust
pub fn open_ipv6_event_socket(
+    interface: InterfaceName,
+    timestamping: InterfaceTimestampMode
+) -> Result<Socket<SocketAddrV6, Open>>
\ No newline at end of file diff --git a/docs/statime_linux/socket/fn.open_ipv6_general_socket.html b/docs/statime_linux/socket/fn.open_ipv6_general_socket.html new file mode 100644 index 000000000..3deeafda9 --- /dev/null +++ b/docs/statime_linux/socket/fn.open_ipv6_general_socket.html @@ -0,0 +1,3 @@ +open_ipv6_general_socket in statime_linux::socket - Rust
pub fn open_ipv6_general_socket(
+    interface: InterfaceName
+) -> Result<Socket<SocketAddrV6, Open>>
\ No newline at end of file diff --git a/docs/statime_linux/socket/fn.timestamp_to_time.html b/docs/statime_linux/socket/fn.timestamp_to_time.html new file mode 100644 index 000000000..98a1f77ac --- /dev/null +++ b/docs/statime_linux/socket/fn.timestamp_to_time.html @@ -0,0 +1 @@ +timestamp_to_time in statime_linux::socket - Rust
pub fn timestamp_to_time(ts: Timestamp) -> Time
\ No newline at end of file diff --git a/docs/statime_linux/socket/index.html b/docs/statime_linux/socket/index.html new file mode 100644 index 000000000..d167a6cc3 --- /dev/null +++ b/docs/statime_linux/socket/index.html @@ -0,0 +1,2 @@ +statime_linux::socket - Rust
\ No newline at end of file diff --git a/docs/statime_linux/socket/sidebar-items.js b/docs/statime_linux/socket/sidebar-items.js new file mode 100644 index 000000000..e559087b0 --- /dev/null +++ b/docs/statime_linux/socket/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["open_ipv4_event_socket","open_ipv4_general_socket","open_ipv6_event_socket","open_ipv6_general_socket","timestamp_to_time"],"trait":["PtpTargetAddress"]}; \ No newline at end of file diff --git a/docs/statime_linux/socket/trait.PtpTargetAddress.html b/docs/statime_linux/socket/trait.PtpTargetAddress.html new file mode 100644 index 000000000..46c34b1bc --- /dev/null +++ b/docs/statime_linux/socket/trait.PtpTargetAddress.html @@ -0,0 +1,6 @@ +PtpTargetAddress in statime_linux::socket - Rust
pub trait PtpTargetAddress {
+    const PRIMARY_EVENT: Self;
+    const PRIMARY_GENERAL: Self;
+    const PDELAY_EVENT: Self;
+    const PDELAY_GENERAL: Self;
+}

Required Associated Constants§

Implementations on Foreign Types§

source§

impl PtpTargetAddress for SocketAddrV4

source§

const PRIMARY_EVENT: Self = _

source§

const PRIMARY_GENERAL: Self = _

source§

const PDELAY_EVENT: Self = _

source§

const PDELAY_GENERAL: Self = _

source§

impl PtpTargetAddress for SocketAddrV6

source§

const PRIMARY_EVENT: Self = _

source§

const PRIMARY_GENERAL: Self = _

source§

const PDELAY_EVENT: Self = _

source§

const PDELAY_GENERAL: Self = _

Implementors§

\ No newline at end of file diff --git a/elasticlunr.min.js b/elasticlunr.min.js new file mode 100644 index 000000000..94b20dd2e --- /dev/null +++ b/elasticlunr.min.js @@ -0,0 +1,10 @@ +/** + * elasticlunr - http://weixsong.github.io + * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5 + * + * Copyright (C) 2017 Oliver Nightingale + * Copyright (C) 2017 Wei Song + * MIT Licensed + * @license + */ +!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o + + + + diff --git a/fonts/OPEN-SANS-LICENSE.txt b/fonts/OPEN-SANS-LICENSE.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/fonts/OPEN-SANS-LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/fonts/SOURCE-CODE-PRO-LICENSE.txt b/fonts/SOURCE-CODE-PRO-LICENSE.txt new file mode 100644 index 000000000..366206f54 --- /dev/null +++ b/fonts/SOURCE-CODE-PRO-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/fonts/fonts.css b/fonts/fonts.css new file mode 100644 index 000000000..858efa598 --- /dev/null +++ b/fonts/fonts.css @@ -0,0 +1,100 @@ +/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */ +/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */ + +/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), + url('open-sans-v17-all-charsets-300.woff2') format('woff2'); +} + +/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 300; + src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'), + url('open-sans-v17-all-charsets-300italic.woff2') format('woff2'); +} + +/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), + url('open-sans-v17-all-charsets-regular.woff2') format('woff2'); +} + +/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), + url('open-sans-v17-all-charsets-italic.woff2') format('woff2'); +} + +/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), + url('open-sans-v17-all-charsets-600.woff2') format('woff2'); +} + +/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 600; + src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'), + url('open-sans-v17-all-charsets-600italic.woff2') format('woff2'); +} + +/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), + url('open-sans-v17-all-charsets-700.woff2') format('woff2'); +} + +/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), + url('open-sans-v17-all-charsets-700italic.woff2') format('woff2'); +} + +/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), + url('open-sans-v17-all-charsets-800.woff2') format('woff2'); +} + +/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 800; + src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'), + url('open-sans-v17-all-charsets-800italic.woff2') format('woff2'); +} + +/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 500; + src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2'); +} diff --git a/fonts/open-sans-v17-all-charsets-300.woff2 b/fonts/open-sans-v17-all-charsets-300.woff2 new file mode 100644 index 000000000..9f51be370 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-300.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-300italic.woff2 b/fonts/open-sans-v17-all-charsets-300italic.woff2 new file mode 100644 index 000000000..2f5454484 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-300italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-600.woff2 b/fonts/open-sans-v17-all-charsets-600.woff2 new file mode 100644 index 000000000..f503d558d Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-600.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-600italic.woff2 b/fonts/open-sans-v17-all-charsets-600italic.woff2 new file mode 100644 index 000000000..c99aabe80 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-600italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-700.woff2 b/fonts/open-sans-v17-all-charsets-700.woff2 new file mode 100644 index 000000000..421a1ab25 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-700.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-700italic.woff2 b/fonts/open-sans-v17-all-charsets-700italic.woff2 new file mode 100644 index 000000000..12ce3d20d Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-700italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-800.woff2 b/fonts/open-sans-v17-all-charsets-800.woff2 new file mode 100644 index 000000000..c94a223b0 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-800.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-800italic.woff2 b/fonts/open-sans-v17-all-charsets-800italic.woff2 new file mode 100644 index 000000000..eed7d3c63 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-800italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-italic.woff2 b/fonts/open-sans-v17-all-charsets-italic.woff2 new file mode 100644 index 000000000..398b68a08 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-regular.woff2 b/fonts/open-sans-v17-all-charsets-regular.woff2 new file mode 100644 index 000000000..8383e94c6 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-regular.woff2 differ diff --git a/fonts/source-code-pro-v11-all-charsets-500.woff2 b/fonts/source-code-pro-v11-all-charsets-500.woff2 new file mode 100644 index 000000000..722245682 Binary files /dev/null and b/fonts/source-code-pro-v11-all-charsets-500.woff2 differ diff --git a/highlight.css b/highlight.css new file mode 100644 index 000000000..ba57b82b2 --- /dev/null +++ b/highlight.css @@ -0,0 +1,82 @@ +/* + * An increased contrast highlighting scheme loosely based on the + * "Base16 Atelier Dune Light" theme by Bram de Haan + * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) + * Original Base16 color scheme by Chris Kempson + * (https://github.com/chriskempson/base16) + */ + +/* Comment */ +.hljs-comment, +.hljs-quote { + color: #575757; +} + +/* Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d70025; +} + +/* Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b21e00; +} + +/* Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #008200; +} + +/* Blue */ +.hljs-title, +.hljs-section { + color: #0030f2; +} + +/* Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #9d00ec; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f6f7f6; + color: #000; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #22863a; + background-color: #f0fff4; +} + +.hljs-deletion { + color: #b31d28; + background-color: #ffeef0; +} diff --git a/highlight.js b/highlight.js new file mode 100644 index 000000000..180385b70 --- /dev/null +++ b/highlight.js @@ -0,0 +1,6 @@ +/* + Highlight.js 10.1.1 (93fd0d73) + License: BSD-3-Clause + Copyright (c) 2006-2020, Ivan Sagalaev +*/ +var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="
",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("php",function(){"use strict";return function(e){var r={begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:'b"',end:'"'},{begin:"b'",end:"'"},e.inherit(e.APOS_STRING_MODE,{illegal:null}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null})]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},i={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7"],case_insensitive:!0,keywords:i,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),{className:"string",begin:/<<<['"]?\w+['"]?$/,end:/^\w+;?$/,contains:[e.BACKSLASH_ESCAPE,{className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]}]},t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,e.C_BLOCK_COMMENT_MODE,a,n]}]},{className:"class",beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",end:";",illegal:/[\.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";",contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},a,n]}}}());hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{$pattern:"[a-z/_]+",literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n]},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^",end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number",begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],illegal:"[^\\s\\}]"}}}());hljs.registerLanguage("csharp",function(){"use strict";return function(e){var n={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let nameof on orderby partial remove select set value var when where yield",literal:"null false true"},i=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},t=e.inherit(s,{illegal:/\n/}),l={className:"subst",begin:"{",end:"}",keywords:n},r=e.inherit(l,{illegal:/\n/}),c={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,r]},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},l]},g=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},r]});l.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],r.contains=[g,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];var d={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i]},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},d,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",end:/[{;=]/,illegal:/[^\s:]/,contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"meta-string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[d,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}());hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={$pattern:/[\w.]+/,keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when"},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{",end:"}"},r={variants:[{begin:/\$\d/},{begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/,relevance:0}]},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{endsWithParent:!0}),s,{className:"string",contains:i,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<",end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE],relevance:0}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n,contains:a}}}());hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst",begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}]},r={className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",relevance:0};return t.contains=[r],{name:"Swift",keywords:i,contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*[!?]"},{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*",relevance:0},r,{className:"function",beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:i,contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}],illegal:/\[|%/},{className:"class",beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta",begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b"},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}());hljs.registerLanguage("makefile",function(){"use strict";return function(e){var i={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}());hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}());hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}());hljs.registerLanguage("coffeescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((e=>n=>!e.includes(n))(["var","const","let","function","static"])).join(" "),literal:n.concat(["yes","no","on","off"]).join(" "),built_in:a.concat(["npm","print"]).join(" ")},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:t},o=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[r.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=o;var c=r.inherit(r.TITLE_MODE,{begin:i}),l={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:t,contains:["self"].concat(o)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:t,illegal:/\/\*/,contains:o.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[c,l]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[l]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[c]},c]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}());hljs.registerLanguage("ruby",function(){"use strict";return function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}",keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[i,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:d}}];return{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/,contains:r.concat(g).concat(d)}}}());hljs.registerLanguage("yaml",function(){"use strict";return function(e){var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string",begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"],contains:b}}}());hljs.registerLanguage("d",function(){"use strict";return function(e){var a={$pattern:e.UNDERSCORE_IDENT_RE,keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},d="((0|[1-9][\\d_]*)|0[bB][01_]+|0[xX]([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))",n="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",t={className:"number",begin:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",relevance:0},_={className:"number",begin:"\\b(((0[xX](([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)\\.([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)|\\.?([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))[pP][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))|((0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(\\.\\d*|([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)))|\\d+\\.(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)|\\.(0|[1-9][\\d_]*)([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))?))([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",relevance:0},r={className:"string",begin:"'("+n+"|.)",end:"'",illegal:"."},i={className:"string",begin:'"',contains:[{begin:n,relevance:0}],end:'"[cwd]?'},s=e.COMMENT("\\/\\+","\\+\\/",{contains:["self"],relevance:10});return{name:"D",keywords:a,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{className:"string",begin:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',relevance:10},i,{className:"string",begin:'[rq]"',end:'"[cwd]?',relevance:5},{className:"string",begin:"`",end:"`[cwd]?"},{className:"string",begin:'q"\\{',end:'\\}"'},_,t,r,{className:"meta",begin:"^#!",end:"$",relevance:5},{className:"meta",begin:"#(line)",end:"$",relevance:5},{className:"keyword",begin:"@[a-zA-Z_][a-zA-Z_\\d]*"}]}}}());hljs.registerLanguage("properties",function(){"use strict";return function(e){var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",s={end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+"+t,returnBegin:!0,contains:[{className:"attr",begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",endsParent:!0,relevance:0}],starts:s},{begin:a+t,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:a,endsParent:!0,relevance:0}],starts:s},{className:"attr",relevance:0,begin:a+n+"$"}]}}}());hljs.registerLanguage("http",function(){"use strict";return function(e){var n="HTTP/[0-9\\.]+";return{name:"HTTP",aliases:["https"],illegal:"\\S",contains:[{begin:"^"+n,end:"$",contains:[{className:"number",begin:"\\b\\d{3}\\b"}]},{begin:"^[A-Z]+ (.*?) "+n+"$",returnBegin:!0,end:"$",contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{begin:n},{className:"keyword",begin:"[A-Z]+"}]},{className:"attribute",begin:"^\\w",end:": ",excludeEnd:!0,illegal:"\\n|\\s|=",starts:{end:"$",relevance:0}},{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}]}}}());hljs.registerLanguage("haskell",function(){"use strict";return function(e){var n={variants:[e.COMMENT("--","$"),e.COMMENT("{-","-}",{contains:["self"]})]},i={className:"meta",begin:"{-#",end:"#-}"},a={className:"meta",begin:"^#",end:"$"},s={className:"type",begin:"\\b[A-Z][\\w']*",relevance:0},l={begin:"\\(",end:"\\)",illegal:'"',contains:[i,a,{className:"type",begin:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TITLE_MODE,{begin:"[_a-z][\\w']*"}),n]};return{name:"Haskell",aliases:["hs"],keywords:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",contains:[{beginKeywords:"module",end:"where",keywords:"module where",contains:[l,n],illegal:"\\W\\.|;"},{begin:"\\bimport\\b",end:"$",keywords:"import qualified as hiding",contains:[l,n],illegal:"\\W\\.|;"},{className:"class",begin:"^(\\s*)?(class|instance)\\b",end:"where",keywords:"class family instance where",contains:[s,l,n]},{className:"class",begin:"\\b(data|(new)?type)\\b",end:"$",keywords:"data family type newtype deriving",contains:[i,s,l,{begin:"{",end:"}",contains:l.contains},n]},{beginKeywords:"default",end:"$",contains:[s,l,n]},{beginKeywords:"infix infixl infixr",end:"$",contains:[e.C_NUMBER_MODE,n]},{begin:"\\bforeign\\b",end:"$",keywords:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",contains:[s,e.QUOTE_STRING_MODE,n]},{className:"meta",begin:"#!\\/usr\\/bin\\/env runhaskell",end:"$"},i,a,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,s,e.inherit(e.TITLE_MODE,{begin:"^[_a-z][\\w']*"}),n,{begin:"->|<-"}]}}}());hljs.registerLanguage("handlebars",function(){"use strict";function e(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(n){const a={"builtin-name":"action bindattr collection component concat debugger each each-in get hash if in input link-to loc log lookup mut outlet partial query-params render template textarea unbound unless view with yield"},t=/\[.*?\]/,s=/[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/,i=e("(",/'.*?'/,"|",/".*?"/,"|",t,"|",s,"|",/\.|\//,")+"),r=e("(",t,"|",s,")(?==)"),l={begin:i,lexemes:/[\w.\/]+/},c=n.inherit(l,{keywords:{literal:"true false undefined null"}}),o={begin:/\(/,end:/\)/},m={className:"attr",begin:r,relevance:0,starts:{begin:/=/,end:/=/,starts:{contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,c,o]}}},d={contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,{begin:/as\s+\|/,keywords:{keyword:"as"},end:/\|/,contains:[{begin:/\w+/}]},m,c,o],returnEnd:!0},g=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/\)/})});o.contains=[g];const u=n.inherit(l,{keywords:a,className:"name",starts:n.inherit(d,{end:/}}/})}),b=n.inherit(l,{keywords:a,className:"name"}),h=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/}}/})});return{name:"Handlebars",aliases:["hbs","html.hbs","html.handlebars","htmlbars"],case_insensitive:!0,subLanguage:"xml",contains:[{begin:/\\\{\{/,skip:!0},{begin:/\\\\(?=\{\{)/,skip:!0},n.COMMENT(/\{\{!--/,/--\}\}/),n.COMMENT(/\{\{!/,/\}\}/),{className:"template-tag",begin:/\{\{\{\{(?!\/)/,end:/\}\}\}\}/,contains:[u],starts:{end:/\{\{\{\{\//,returnEnd:!0,subLanguage:"xml"}},{className:"template-tag",begin:/\{\{\{\{\//,end:/\}\}\}\}/,contains:[b]},{className:"template-tag",begin:/\{\{#/,end:/\}\}/,contains:[u]},{className:"template-tag",begin:/\{\{(?=else\}\})/,end:/\}\}/,keywords:"else"},{className:"template-tag",begin:/\{\{\//,end:/\}\}/,contains:[b]},{className:"template-variable",begin:/\{\{\{/,end:/\}\}\}/,contains:[h]},{className:"template-variable",begin:/\{\{/,end:/\}\}/,contains:[h]}]}}}());hljs.registerLanguage("rust",function(){"use strict";return function(e){var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!";return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield",literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}());hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}());hljs.registerLanguage("ini",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(...n){return n.map(n=>e(n)).join("")}return function(a){var s={className:"number",relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}]},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"],relevance:0},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map(n=>e(n)).join("|")+")";return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr",starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}());hljs.registerLanguage("objectivec",function(){"use strict";return function(e){var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n,keyword:"@interface @class @protocol @implementation"};return{name:"Objective-C",aliases:["mm","objc","obj-c"],keywords:{$pattern:n,keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)",excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}());hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}());hljs.registerLanguage("java",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")}function a(...n){return n.map(n=>e(n)).join("")}function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}return function(e){var t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={className:"meta",begin:"@[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},r=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{begin:`\\b(0[bB]${r("01")})[lL]?`},{begin:`\\b(0${r("0-7")})[dDfFlL]?`},{begin:a(/\b0[xX]/,s(a(r("a-fA-F0-9"),/\./,r("a-fA-F0-9")),a(r("a-fA-F0-9"),/\.?/),a(/\./,r("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/)},{begin:a(/\b/,s(a(/\d*\./,r("\\d")),r("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{begin:a(/\b/,r(/\d/),n(/\.?/),n(r(/\d/)),/[dDfFlL]?/)}],relevance:0};return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface",end:/[{;=]/,excludeEnd:!0,keywords:"class interface",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}());hljs.registerLanguage("x86asm",function(){"use strict";return function(s){return{name:"Intel x86 Assembly",case_insensitive:!0,keywords:{$pattern:"[.%]?"+s.IDENT_RE,keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},contains:[s.COMMENT(";","$",{relevance:0}),{className:"number",variants:[{begin:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",relevance:0},{begin:"\\$[0-9][0-9A-Fa-f]*",relevance:0},{begin:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{begin:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},s.QUOTE_STRING_MODE,{className:"string",variants:[{begin:"'",end:"[^\\\\]'"},{begin:"`",end:"[^\\\\]`"}],relevance:0},{className:"symbol",variants:[{begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{begin:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],relevance:0},{className:"subst",begin:"%[0-9]+",relevance:0},{className:"subst",begin:"%!S+",relevance:0},{className:"meta",begin:/^\s*\.[\w_-]+/}]}}}());hljs.registerLanguage("kotlin",function(){"use strict";return function(e){var n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}]},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},{className:"number",begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0}]}}}());hljs.registerLanguage("armasm",function(){"use strict";return function(s){const e={variants:[s.COMMENT("^[ \\t]*(?=#)","$",{relevance:0,excludeBegin:!0}),s.COMMENT("[;@]","$",{relevance:0}),s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE]};return{name:"ARM Assembly",case_insensitive:!0,aliases:["arm"],keywords:{$pattern:"\\.?"+s.IDENT_RE,meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .arm .thumb .code16 .code32 .force_thumb .thumb_func .ltorg ALIAS ALIGN ARM AREA ASSERT ATTR CN CODE CODE16 CODE32 COMMON CP DATA DCB DCD DCDU DCDO DCFD DCFDU DCI DCQ DCQU DCW DCWU DN ELIF ELSE END ENDFUNC ENDIF ENDP ENTRY EQU EXPORT EXPORTAS EXTERN FIELD FILL FUNCTION GBLA GBLL GBLS GET GLOBAL IF IMPORT INCBIN INCLUDE INFO KEEP LCLA LCLL LCLS LTORG MACRO MAP MEND MEXIT NOFP OPT PRESERVE8 PROC QN READONLY RELOC REQUIRE REQUIRE8 RLIST FN ROUT SETA SETL SETS SN SPACE SUBT THUMB THUMBX TTL WHILE WEND ",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 pc lr sp ip sl sb fp a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 f0 f1 f2 f3 f4 f5 f6 f7 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 cpsr_c cpsr_x cpsr_s cpsr_f cpsr_cx cpsr_cxs cpsr_xs cpsr_xsf cpsr_sf cpsr_cxsf spsr_c spsr_x spsr_s spsr_f spsr_cx spsr_cxs spsr_xs spsr_xsf spsr_sf spsr_cxsf s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 d31 {PC} {VAR} {TRUE} {FALSE} {OPT} {CONFIG} {ENDIAN} {CODESIZE} {CPU} {FPU} {ARCHITECTURE} {PCSTOREOFFSET} {ARMASM_VERSION} {INTER} {ROPI} {RWPI} {SWST} {NOSWST} . @"},contains:[{className:"keyword",begin:"\\b(adc|(qd?|sh?|u[qh]?)?add(8|16)?|usada?8|(q|sh?|u[qh]?)?(as|sa)x|and|adrl?|sbc|rs[bc]|asr|b[lx]?|blx|bxj|cbn?z|tb[bh]|bic|bfc|bfi|[su]bfx|bkpt|cdp2?|clz|clrex|cmp|cmn|cpsi[ed]|cps|setend|dbg|dmb|dsb|eor|isb|it[te]{0,3}|lsl|lsr|ror|rrx|ldm(([id][ab])|f[ds])?|ldr((s|ex)?[bhd])?|movt?|mvn|mra|mar|mul|[us]mull|smul[bwt][bt]|smu[as]d|smmul|smmla|mla|umlaal|smlal?([wbt][bt]|d)|mls|smlsl?[ds]|smc|svc|sev|mia([bt]{2}|ph)?|mrr?c2?|mcrr2?|mrs|msr|orr|orn|pkh(tb|bt)|rbit|rev(16|sh)?|sel|[su]sat(16)?|nop|pop|push|rfe([id][ab])?|stm([id][ab])?|str(ex)?[bhd]?|(qd?)?sub|(sh?|q|u[qh]?)?sub(8|16)|[su]xt(a?h|a?b(16)?)|srs([id][ab])?|swpb?|swi|smi|tst|teq|wfe|wfi|yield)(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo)?[sptrx]?(?=\\s)"},e,s.QUOTE_STRING_MODE,{className:"string",begin:"'",end:"[^\\\\]'",relevance:0},{className:"title",begin:"\\|",end:"\\|",illegal:"\\n",relevance:0},{className:"number",variants:[{begin:"[#$=]?0x[0-9a-f]+"},{begin:"[#$=]?0b[01]+"},{begin:"[#$=]\\d+"},{begin:"\\b\\d+"}],relevance:0},{className:"symbol",variants:[{begin:"^[ \\t]*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{begin:"^[a-z_\\.\\$][a-z0-9_\\.\\$]+"},{begin:"[=#]\\w+"}],relevance:0}]}}}());hljs.registerLanguage("go",function(){"use strict";return function(e){var n={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{name:"Go",aliases:["golang"],keywords:n,illegal:">>|\.\.\.) /},i={className:"subst",begin:/\{/,end:/\}/,keywords:n,illegal:/#/},s={begin:/\{\{/,relevance:0},r={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/(u|b)?r?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(u|b)?r?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(fr|rf|f)'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(fr|rf|f)"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(u|r|ur)'/,end:/'/,relevance:10},{begin:/(u|r|ur)"/,end:/"/,relevance:10},{begin:/(b|br)'/,end:/'/},{begin:/(b|br)"/,end:/"/},{begin:/(fr|rf|f)'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,s,i]},{begin:/(fr|rf|f)"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,i]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},l={className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},t={className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:["self",a,l,r,e.HASH_COMMENT_MODE]}]};return i.contains=[r,l,a],{name:"Python",aliases:["py","gyp","ipython"],keywords:n,illegal:/(<\/|->|\?)|=>/,contains:[a,l,{beginKeywords:"if",relevance:0},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,t,{begin:/->/,endsWithParent:!0,keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{begin:/\b(print|exec)\(/}]}}}());hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}());hljs.registerLanguage("scala",function(){"use strict";return function(e){var n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:"\\${",end:"}"}]},a={className:"string",variants:[{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'"""',end:'"""',relevance:10},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},s={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},t={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},i={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},t]},l={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[t]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},s,l,i,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}}}());hljs.registerLanguage("julia",function(){"use strict";return function(e){var r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",t={$pattern:r,keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool "},a={keywords:t,illegal:/<\//},n={className:"subst",begin:/\$\(/,end:/\)/,keywords:t},o={className:"variable",begin:"\\$"+r},i={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],variants:[{begin:/\w*"""/,end:/"""\w*/,relevance:10},{begin:/\w*"/,end:/"\w*/}]},l={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],begin:"`",end:"`"},s={className:"meta",begin:"@"+r};return a.name="Julia",a.contains=[{className:"number",begin:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,relevance:0},{className:"string",begin:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},i,l,s,{className:"comment",variants:[{begin:"#=",end:"=#",relevance:10},{begin:"#",end:"$"}]},e.HASH_COMMENT_MODE,{className:"keyword",begin:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{begin:/<:/}],n.contains=a.contains,a}}());hljs.registerLanguage("php-template",function(){"use strict";return function(n){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}}());hljs.registerLanguage("scss",function(){"use strict";return function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},i={className:"number",begin:"#[0-9A-Fa-f]+"};return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{className:"selector-pseudo",begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{className:"selector-pseudo",begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,i,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0,keywords:"and or not only",contains:[{begin:"@[a-z-]+",className:"keyword"},t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,i,e.CSS_NUMBER_MODE]}]}}}());hljs.registerLanguage("r",function(){"use strict";return function(e){var n="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{name:"R",contains:[e.HASH_COMMENT_MODE,{begin:n,keywords:{$pattern:n,keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},relevance:0},{className:"number",begin:"0[xX][0-9a-fA-F]+[Li]?\\b",relevance:0},{className:"number",begin:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",relevance:0},{className:"number",begin:"\\d+\\.(?!\\d)(?:i\\b)?",relevance:0},{className:"number",begin:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{className:"number",begin:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{begin:"`",end:"`",relevance:0},{className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:'"',end:'"'},{begin:"'",end:"'"}]}]}}}());hljs.registerLanguage("sql",function(){"use strict";return function(e){var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0,illegal:/[<>{}*]/,contains:[{beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with",end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/,keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void"},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{className:"string",begin:"`",end:"`"},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}());hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}());hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}());hljs.registerLanguage("python-repl",function(){"use strict";return function(n){return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}}());hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}());hljs.registerLanguage("javascript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function s(e){return r("(?=",e,")")}function r(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(t){var i="[A-Za-z$_][0-9A-Za-z$_]*",c={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},o={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.join(" "),literal:n.join(" "),built_in:a.join(" ")},l={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:t.C_NUMBER_RE+"n?"}],relevance:0},E={className:"subst",begin:"\\$\\{",end:"\\}",keywords:o,contains:[]},d={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},g={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,E]};E.contains=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,l,t.REGEXP_MODE];var b=E.contains.concat([{begin:/\(/,end:/\)/,contains:["self"].concat(E.contains,[t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE])},t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]),_={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:b};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:o,contains:[t.SHEBANG({binary:"node",relevance:5}),{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,t.C_LINE_COMMENT_MODE,t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:i+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,l,{begin:r(/[{,\n]\s*/,s(r(/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,i+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:i+s("\\s*:"),relevance:0}]},{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,t.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,contains:b}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:c.begin,end:c.end}],subLanguage:"xml",contains:[{begin:c.begin,end:c.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[t.inherit(t.TITLE_MODE,{begin:i}),_],illegal:/\[|%/},{begin:/\$[(.]/},t.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+i+"\\()",end:/{/,keywords:"get set",contains:[t.inherit(t.TITLE_MODE,{begin:i}),{begin:/\(\)/},_]}],illegal:/#(?!!)/}}}());hljs.registerLanguage("typescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "),literal:n.join(" "),built_in:a.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ")},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},i={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:r.C_NUMBER_RE+"n?"}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:t,contains:[]},c={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},l={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[r.BACKSLASH_ESCAPE,o]};o.contains=[r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,i,r.REGEXP_MODE];var d={begin:"\\(",end:/\)/,keywords:t,contains:["self",r.QUOTE_STRING_MODE,r.APOS_STRING_MODE,r.NUMBER_MODE]},u={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,s,d]};return{name:"TypeScript",aliases:["ts"],keywords:t,contains:[r.SHEBANG(),{className:"meta",begin:/^\s*['"]use strict['"]/},r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,i,{begin:"("+r.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,r.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+r.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:r.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:d.contains}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",r.inherit(r.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),u],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",u]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+r.IDENT_RE,relevance:0},s,d]}}}());hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}());hljs.registerLanguage("less",function(){"use strict";return function(e){var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a}},i={begin:"\\(",end:"\\)",contains:s,relevance:0};s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}",contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]},g={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{begin:"!important"}]};return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}());hljs.registerLanguage("lua",function(){"use strict";return function(e){var t={begin:"\\[=*\\[",end:"\\]=*\\]",contains:["self"]},a=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[","\\]=*\\]",{contains:[t],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:a.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:a}].concat(a)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"\\[=*\\[",end:"\\]=*\\]",contains:[t],relevance:5}])}}}()); diff --git a/images/setup.png b/images/setup.png new file mode 100644 index 000000000..72ac4d056 Binary files /dev/null and b/images/setup.png differ diff --git a/index.html b/index.html new file mode 100644 index 000000000..a07464fd5 --- /dev/null +++ b/index.html @@ -0,0 +1,334 @@ + + + + + + Setting up a simple PTP network - Statime Reference Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Setting up a simple PTP network

+

This example network configuration consists of two ordinary clocks, connected to each other through a boundary clock, +all of which are running on Linux:

+

setup

+

It should be relatively straightforward to extrapolate for more complicated networks.

+

Ordinary Clocks

+

To get PTP up and running for each of the ordinary clocks, install statime-linux on both of them:

+
cargo install --git https://github.com/pendulum-project/statime.git --rev 52b17e3 --bin statime-linux
+
+

statime-linux contains a CLI binary that can be used to start ordinary clock instances:

+
# use ifconfig to find the descriptor corresponding to the interface connected to the boundary clock
+ifconfig
+statime-linux --interface enp1s0f1
+
+

Ordinary clocks can also be configured through code. Doing so is very similar to configuring boundary clocks, which is +explained in the next section.

+

Boundary Clock

+

Setting up a boundary clock is currently only possible through code. Start by creating a new Rust project:

+
cargo new boundary_clock
+cd boundary_clock
+
+

In Cargo.toml, add the following dependencies:

+
[package]
+name = "test-bc"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "3.1.6", features = ["derive"] }
+log = "0.4.14"
+env_logger = "0.10.0"
+statime = { git = "https://github.com/pendulum-project/statime.git", rev = "52b17e3" }
+statime-linux = { git = "https://github.com/pendulum-project/statime.git", rev = "52b17e3" }
+tokio = { version = "1.27", features = ["full"] }
+
+

Then, in src/main.rs, add the following code:

+
use std::env;
+
+use statime::{
+    datastructures::{
+        common::{ClockIdentity, PortIdentity, TimeSource},
+        datasets::{DefaultDS, DelayMechanism, PortDS, TimePropertiesDS},
+        messages::SdoId,
+    },
+    filters::basic::BasicFilter,
+    port::Port,
+    ptp_instance::PtpInstance,
+};
+use statime_linux::{
+    clock::{LinuxClock, LinuxTimer, RawLinuxClock},
+    network::linux::{get_clock_id, LinuxRuntime},
+};
+
+#[tokio::main]
+async fn main() {
+    env_logger::init();
+
+    let local_clock = LinuxClock::new(RawLinuxClock::get_realtime_clock());
+    let mut network_runtime = LinuxRuntime::new(false, &local_clock);
+    let clock_identity = ClockIdentity(get_clock_id().expect("Could not get clock identity"));
+
+    let default_ds =
+        DefaultDS::new_boundary_clock(clock_identity, 2, 128, 128, 0, SdoId::default());
+
+    let time_properties_ds =
+        TimePropertiesDS::new_arbitrary_time(false, false, TimeSource::InternalOscillator);
+
+    let port_1_ds = PortDS::new(
+        PortIdentity {
+            clock_identity,
+            port_number: 1,
+        },
+        1,
+        1,
+        3,
+        0,
+        DelayMechanism::E2E,
+        1,
+    );
+    let interface = env::var("PORT1")
+        .expect("PORT1 interface descriptor not set")
+        .parse()
+        .expect("invalid interface descriptor for PORT1");
+    let port_1 = Port::new(port_1_ds, &mut network_runtime, interface).await;
+
+    let port_2_ds = PortDS::new(
+        PortIdentity {
+            clock_identity,
+            port_number: 2,
+        },
+        1,
+        1,
+        3,
+        0,
+        DelayMechanism::E2E,
+        1,
+    );
+    let interface = env::var("PORT2")
+        .expect("PORT2 interface descriptor not set")
+        .parse()
+        .expect("invalid interface descriptor for PORT2");
+    let port_2 = Port::new(port_2_ds, &mut network_runtime, interface).await;
+
+    let mut instance = PtpInstance::new_boundary_clock(
+        default_ds,
+        time_properties_ds,
+        [port_1, port_2],
+        local_clock,
+        BasicFilter::new(0.25),
+    );
+
+    instance.run(&LinuxTimer).await;
+}
+

This configures two PTP ports, binds them to interfaces described by the environment variables PORT1 and PORT2, and +starts a boundary clock PTP instance. To run the binary, execute the following commands:

+
# use ifconfig to find the descriptors corresponding to the interfaces connected to the ordinary clocks
+ifconfig
+PORT1=enp1s0f0 PORT2=enp1s0f1 cargo run
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/mark.min.js b/mark.min.js new file mode 100644 index 000000000..163623188 --- /dev/null +++ b/mark.min.js @@ -0,0 +1,7 @@ +/*!*************************************************** +* mark.js v8.11.1 +* https://markjs.io/ +* Copyright (c) 2014–2018, Julian Kühnel +* Released under the MIT license https://git.io/vwTVl +*****************************************************/ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function e(n){t(this,e),this.opt=r({},{diacritics:!0,synonyms:{},accuracy:"partially",caseSensitive:!1,ignoreJoiners:!1,ignorePunctuation:[],wildcards:"disabled"},n)}return n(e,[{key:"create",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),new RegExp(e,"gm"+(this.opt.caseSensitive?"":"i"))}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynonyms(a)+"|"+this.processSynonyms(s)+")"+r))}return e}},{key:"processSynonyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}}]),e}(),a=function(){function a(e){t(this,a),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(a,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapGroups",value:function(e,t,n,r){return r((e=this.wrapRangeInTextNode(e,t,t+n)).previousSibling),e}},{key:"separateGroups",value:function(e,t,n,r,i){for(var o=t.length,a=1;a-1&&r(t[a],e)&&(e=this.wrapGroups(e,s,t[a].length,i))}return e}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];){if(o.opt.separateGroups)t=o.separateGroups(t,i,a,n,r);else{if(!n(i[a],t))continue;var s=i.index;if(0!==a)for(var c=1;c + + + + + Statime Reference Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Setting up a simple PTP network

+

This example network configuration consists of two ordinary clocks, connected to each other through a boundary clock, +all of which are running on Linux:

+

setup

+

It should be relatively straightforward to extrapolate for more complicated networks.

+

Ordinary Clocks

+

To get PTP up and running for each of the ordinary clocks, install statime-linux on both of them:

+
cargo install --git https://github.com/pendulum-project/statime.git --rev 52b17e3 --bin statime-linux
+
+

statime-linux contains a CLI binary that can be used to start ordinary clock instances:

+
# use ifconfig to find the descriptor corresponding to the interface connected to the boundary clock
+ifconfig
+statime-linux --interface enp1s0f1
+
+

Ordinary clocks can also be configured through code. Doing so is very similar to configuring boundary clocks, which is +explained in the next section.

+

Boundary Clock

+

Setting up a boundary clock is currently only possible through code. Start by creating a new Rust project:

+
cargo new boundary_clock
+cd boundary_clock
+
+

In Cargo.toml, add the following dependencies:

+
[package]
+name = "test-bc"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "3.1.6", features = ["derive"] }
+log = "0.4.14"
+env_logger = "0.10.0"
+statime = { git = "https://github.com/pendulum-project/statime.git", rev = "52b17e3" }
+statime-linux = { git = "https://github.com/pendulum-project/statime.git", rev = "52b17e3" }
+tokio = { version = "1.27", features = ["full"] }
+
+

Then, in src/main.rs, add the following code:

+
use std::env;
+
+use statime::{
+    datastructures::{
+        common::{ClockIdentity, PortIdentity, TimeSource},
+        datasets::{DefaultDS, DelayMechanism, PortDS, TimePropertiesDS},
+        messages::SdoId,
+    },
+    filters::basic::BasicFilter,
+    port::Port,
+    ptp_instance::PtpInstance,
+};
+use statime_linux::{
+    clock::{LinuxClock, LinuxTimer, RawLinuxClock},
+    network::linux::{get_clock_id, LinuxRuntime},
+};
+
+#[tokio::main]
+async fn main() {
+    env_logger::init();
+
+    let local_clock = LinuxClock::new(RawLinuxClock::get_realtime_clock());
+    let mut network_runtime = LinuxRuntime::new(false, &local_clock);
+    let clock_identity = ClockIdentity(get_clock_id().expect("Could not get clock identity"));
+
+    let default_ds =
+        DefaultDS::new_boundary_clock(clock_identity, 2, 128, 128, 0, SdoId::default());
+
+    let time_properties_ds =
+        TimePropertiesDS::new_arbitrary_time(false, false, TimeSource::InternalOscillator);
+
+    let port_1_ds = PortDS::new(
+        PortIdentity {
+            clock_identity,
+            port_number: 1,
+        },
+        1,
+        1,
+        3,
+        0,
+        DelayMechanism::E2E,
+        1,
+    );
+    let interface = env::var("PORT1")
+        .expect("PORT1 interface descriptor not set")
+        .parse()
+        .expect("invalid interface descriptor for PORT1");
+    let port_1 = Port::new(port_1_ds, &mut network_runtime, interface).await;
+
+    let port_2_ds = PortDS::new(
+        PortIdentity {
+            clock_identity,
+            port_number: 2,
+        },
+        1,
+        1,
+        3,
+        0,
+        DelayMechanism::E2E,
+        1,
+    );
+    let interface = env::var("PORT2")
+        .expect("PORT2 interface descriptor not set")
+        .parse()
+        .expect("invalid interface descriptor for PORT2");
+    let port_2 = Port::new(port_2_ds, &mut network_runtime, interface).await;
+
+    let mut instance = PtpInstance::new_boundary_clock(
+        default_ds,
+        time_properties_ds,
+        [port_1, port_2],
+        local_clock,
+        BasicFilter::new(0.25),
+    );
+
+    instance.run(&LinuxTimer).await;
+}
+

This configures two PTP ports, binds them to interfaces described by the environment variables PORT1 and PORT2, and +starts a boundary clock PTP instance. To run the binary, execute the following commands:

+
# use ifconfig to find the descriptors corresponding to the interfaces connected to the ordinary clocks
+ifconfig
+PORT1=enp1s0f0 PORT2=enp1s0f1 cargo run
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + +
+ + diff --git a/searcher.js b/searcher.js new file mode 100644 index 000000000..d2b0aeed3 --- /dev/null +++ b/searcher.js @@ -0,0 +1,483 @@ +"use strict"; +window.search = window.search || {}; +(function search(search) { + // Search functionality + // + // You can use !hasFocus() to prevent keyhandling in your key + // event handlers while the user is typing their search. + + if (!Mark || !elasticlunr) { + return; + } + + //IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith + if (!String.prototype.startsWith) { + String.prototype.startsWith = function(search, pos) { + return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; + }; + } + + var search_wrap = document.getElementById('search-wrapper'), + searchbar = document.getElementById('searchbar'), + searchbar_outer = document.getElementById('searchbar-outer'), + searchresults = document.getElementById('searchresults'), + searchresults_outer = document.getElementById('searchresults-outer'), + searchresults_header = document.getElementById('searchresults-header'), + searchicon = document.getElementById('search-toggle'), + content = document.getElementById('content'), + + searchindex = null, + doc_urls = [], + results_options = { + teaser_word_count: 30, + limit_results: 30, + }, + search_options = { + bool: "AND", + expand: true, + fields: { + title: {boost: 1}, + body: {boost: 1}, + breadcrumbs: {boost: 0} + } + }, + mark_exclude = [], + marker = new Mark(content), + current_searchterm = "", + URL_SEARCH_PARAM = 'search', + URL_MARK_PARAM = 'highlight', + teaser_count = 0, + + SEARCH_HOTKEY_KEYCODE = 83, + ESCAPE_KEYCODE = 27, + DOWN_KEYCODE = 40, + UP_KEYCODE = 38, + SELECT_KEYCODE = 13; + + function hasFocus() { + return searchbar === document.activeElement; + } + + function removeChildren(elem) { + while (elem.firstChild) { + elem.removeChild(elem.firstChild); + } + } + + // Helper to parse a url into its building blocks. + function parseURL(url) { + var a = document.createElement('a'); + a.href = url; + return { + source: url, + protocol: a.protocol.replace(':',''), + host: a.hostname, + port: a.port, + params: (function(){ + var ret = {}; + var seg = a.search.replace(/^\?/,'').split('&'); + var len = seg.length, i = 0, s; + for (;i': '>', + '"': '"', + "'": ''' + }; + var repl = function(c) { return MAP[c]; }; + return function(s) { + return s.replace(/[&<>'"]/g, repl); + }; + })(); + + function formatSearchMetric(count, searchterm) { + if (count == 1) { + return count + " search result for '" + searchterm + "':"; + } else if (count == 0) { + return "No search results for '" + searchterm + "'."; + } else { + return count + " search results for '" + searchterm + "':"; + } + } + + function formatSearchResult(result, searchterms) { + var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms); + teaser_count++; + + // The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor + var url = doc_urls[result.ref].split("#"); + if (url.length == 1) { // no anchor found + url.push(""); + } + + // encodeURIComponent escapes all chars that could allow an XSS except + // for '. Due to that we also manually replace ' with its url-encoded + // representation (%27). + var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27"); + + return '' + result.doc.breadcrumbs + '' + + '' + + teaser + ''; + } + + function makeTeaser(body, searchterms) { + // The strategy is as follows: + // First, assign a value to each word in the document: + // Words that correspond to search terms (stemmer aware): 40 + // Normal words: 2 + // First word in a sentence: 8 + // Then use a sliding window with a constant number of words and count the + // sum of the values of the words within the window. Then use the window that got the + // maximum sum. If there are multiple maximas, then get the last one. + // Enclose the terms in . + var stemmed_searchterms = searchterms.map(function(w) { + return elasticlunr.stemmer(w.toLowerCase()); + }); + var searchterm_weight = 40; + var weighted = []; // contains elements of ["word", weight, index_in_document] + // split in sentences, then words + var sentences = body.toLowerCase().split('. '); + var index = 0; + var value = 0; + var searchterm_found = false; + for (var sentenceindex in sentences) { + var words = sentences[sentenceindex].split(' '); + value = 8; + for (var wordindex in words) { + var word = words[wordindex]; + if (word.length > 0) { + for (var searchtermindex in stemmed_searchterms) { + if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) { + value = searchterm_weight; + searchterm_found = true; + } + }; + weighted.push([word, value, index]); + value = 2; + } + index += word.length; + index += 1; // ' ' or '.' if last word in sentence + }; + index += 1; // because we split at a two-char boundary '. ' + }; + + if (weighted.length == 0) { + return body; + } + + var window_weight = []; + var window_size = Math.min(weighted.length, results_options.teaser_word_count); + + var cur_sum = 0; + for (var wordindex = 0; wordindex < window_size; wordindex++) { + cur_sum += weighted[wordindex][1]; + }; + window_weight.push(cur_sum); + for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) { + cur_sum -= weighted[wordindex][1]; + cur_sum += weighted[wordindex + window_size][1]; + window_weight.push(cur_sum); + }; + + if (searchterm_found) { + var max_sum = 0; + var max_sum_window_index = 0; + // backwards + for (var i = window_weight.length - 1; i >= 0; i--) { + if (window_weight[i] > max_sum) { + max_sum = window_weight[i]; + max_sum_window_index = i; + } + }; + } else { + max_sum_window_index = 0; + } + + // add around searchterms + var teaser_split = []; + var index = weighted[max_sum_window_index][2]; + for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) { + var word = weighted[i]; + if (index < word[2]) { + // missing text from index to start of `word` + teaser_split.push(body.substring(index, word[2])); + index = word[2]; + } + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + index = word[2] + word[0].length; + teaser_split.push(body.substring(word[2], index)); + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + }; + + return teaser_split.join(''); + } + + function init(config) { + results_options = config.results_options; + search_options = config.search_options; + searchbar_outer = config.searchbar_outer; + doc_urls = config.doc_urls; + searchindex = elasticlunr.Index.load(config.index); + + // Set up events + searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); + searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false); + document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false); + // If the user uses the browser buttons, do the same as if a reload happened + window.onpopstate = function(e) { doSearchOrMarkFromUrl(); }; + // Suppress "submit" events so the page doesn't reload when the user presses Enter + document.addEventListener('submit', function(e) { e.preventDefault(); }, false); + + // If reloaded, do the search or mark again, depending on the current url parameters + doSearchOrMarkFromUrl(); + } + + function unfocusSearchbar() { + // hacky, but just focusing a div only works once + var tmp = document.createElement('input'); + tmp.setAttribute('style', 'position: absolute; opacity: 0;'); + searchicon.appendChild(tmp); + tmp.focus(); + tmp.remove(); + } + + // On reload or browser history backwards/forwards events, parse the url and do search or mark + function doSearchOrMarkFromUrl() { + // Check current URL for search request + var url = parseURL(window.location.href); + if (url.params.hasOwnProperty(URL_SEARCH_PARAM) + && url.params[URL_SEARCH_PARAM] != "") { + showSearch(true); + searchbar.value = decodeURIComponent( + (url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20')); + searchbarKeyUpHandler(); // -> doSearch() + } else { + showSearch(false); + } + + if (url.params.hasOwnProperty(URL_MARK_PARAM)) { + var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' '); + marker.mark(words, { + exclude: mark_exclude + }); + + var markers = document.querySelectorAll("mark"); + function hide() { + for (var i = 0; i < markers.length; i++) { + markers[i].classList.add("fade-out"); + window.setTimeout(function(e) { marker.unmark(); }, 300); + } + } + for (var i = 0; i < markers.length; i++) { + markers[i].addEventListener('click', hide); + } + } + } + + // Eventhandler for keyevents on `document` + function globalKeyHandler(e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text') { return; } + + if (e.keyCode === ESCAPE_KEYCODE) { + e.preventDefault(); + searchbar.classList.remove("active"); + setSearchUrlParameters("", + (searchbar.value.trim() !== "") ? "push" : "replace"); + if (hasFocus()) { + unfocusSearchbar(); + } + showSearch(false); + marker.unmark(); + } else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) { + e.preventDefault(); + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else if (hasFocus() && e.keyCode === DOWN_KEYCODE) { + e.preventDefault(); + unfocusSearchbar(); + searchresults.firstElementChild.classList.add("focus"); + } else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE + || e.keyCode === UP_KEYCODE + || e.keyCode === SELECT_KEYCODE)) { + // not `:focus` because browser does annoying scrolling + var focused = searchresults.querySelector("li.focus"); + if (!focused) return; + e.preventDefault(); + if (e.keyCode === DOWN_KEYCODE) { + var next = focused.nextElementSibling; + if (next) { + focused.classList.remove("focus"); + next.classList.add("focus"); + } + } else if (e.keyCode === UP_KEYCODE) { + focused.classList.remove("focus"); + var prev = focused.previousElementSibling; + if (prev) { + prev.classList.add("focus"); + } else { + searchbar.select(); + } + } else { // SELECT_KEYCODE + window.location.assign(focused.querySelector('a')); + } + } + } + + function showSearch(yes) { + if (yes) { + search_wrap.classList.remove('hidden'); + searchicon.setAttribute('aria-expanded', 'true'); + } else { + search_wrap.classList.add('hidden'); + searchicon.setAttribute('aria-expanded', 'false'); + var results = searchresults.children; + for (var i = 0; i < results.length; i++) { + results[i].classList.remove("focus"); + } + } + } + + function showResults(yes) { + if (yes) { + searchresults_outer.classList.remove('hidden'); + } else { + searchresults_outer.classList.add('hidden'); + } + } + + // Eventhandler for search icon + function searchIconClickHandler() { + if (search_wrap.classList.contains('hidden')) { + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else { + showSearch(false); + } + } + + // Eventhandler for keyevents while the searchbar is focused + function searchbarKeyUpHandler() { + var searchterm = searchbar.value.trim(); + if (searchterm != "") { + searchbar.classList.add("active"); + doSearch(searchterm); + } else { + searchbar.classList.remove("active"); + showResults(false); + removeChildren(searchresults); + } + + setSearchUrlParameters(searchterm, "push_if_new_search_else_replace"); + + // Remove marks + marker.unmark(); + } + + // Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor . + // `action` can be one of "push", "replace", "push_if_new_search_else_replace" + // and replaces or pushes a new browser history item. + // "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet. + function setSearchUrlParameters(searchterm, action) { + var url = parseURL(window.location.href); + var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM); + if (searchterm != "" || action == "push_if_new_search_else_replace") { + url.params[URL_SEARCH_PARAM] = searchterm; + delete url.params[URL_MARK_PARAM]; + url.hash = ""; + } else { + delete url.params[URL_MARK_PARAM]; + delete url.params[URL_SEARCH_PARAM]; + } + // A new search will also add a new history item, so the user can go back + // to the page prior to searching. A updated search term will only replace + // the url. + if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) { + history.pushState({}, document.title, renderURL(url)); + } else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) { + history.replaceState({}, document.title, renderURL(url)); + } + } + + function doSearch(searchterm) { + + // Don't search the same twice + if (current_searchterm == searchterm) { return; } + else { current_searchterm = searchterm; } + + if (searchindex == null) { return; } + + // Do the actual search + var results = searchindex.search(searchterm, search_options); + var resultcount = Math.min(results.length, results_options.limit_results); + + // Display search metrics + searchresults_header.innerText = formatSearchMetric(resultcount, searchterm); + + // Clear and insert results + var searchterms = searchterm.split(' '); + removeChildren(searchresults); + for(var i = 0; i < resultcount ; i++){ + var resultElem = document.createElement('li'); + resultElem.innerHTML = formatSearchResult(results[i], searchterms); + searchresults.appendChild(resultElem); + } + + // Display results + showResults(true); + } + + fetch(path_to_root + 'searchindex.json') + .then(response => response.json()) + .then(json => init(json)) + .catch(error => { // Try to load searchindex.js if fetch failed + var script = document.createElement('script'); + script.src = path_to_root + 'searchindex.js'; + script.onload = () => init(window.search); + document.head.appendChild(script); + }); + + // Exported functions + search.hasFocus = hasFocus; +})(window.search); diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 000000000..6c48a0def --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Object.assign(window.search, {"doc_urls":["setup.html#setting-up-a-simple-ptp-network","setup.html#ordinary-clocks","setup.html#boundary-clock"],"index":{"documentStore":{"docInfo":{"0":{"body":21,"breadcrumbs":10,"title":5},"1":{"body":58,"breadcrumbs":7,"title":2},"2":{"body":218,"breadcrumbs":7,"title":2}},"docs":{"0":{"body":"This example network configuration consists of two ordinary clocks, connected to each other through a boundary clock, all of which are running on Linux: setup It should be relatively straightforward to extrapolate for more complicated networks.","breadcrumbs":"Setting up a simple PTP network » Setting up a simple PTP network","id":"0","title":"Setting up a simple PTP network"},"1":{"body":"To get PTP up and running for each of the ordinary clocks, install statime-linux on both of them: cargo install --git https://github.com/pendulum-project/statime.git --rev 52b17e3 --bin statime-linux statime-linux contains a CLI binary that can be used to start ordinary clock instances: # use ifconfig to find the descriptor corresponding to the interface connected to the boundary clock\nifconfig\nstatime-linux --interface enp1s0f1 Ordinary clocks can also be configured through code. Doing so is very similar to configuring boundary clocks, which is explained in the next section.","breadcrumbs":"Setting up a simple PTP network » Ordinary Clocks","id":"1","title":"Ordinary Clocks"},"2":{"body":"Setting up a boundary clock is currently only possible through code. Start by creating a new Rust project: cargo new boundary_clock\ncd boundary_clock In Cargo.toml, add the following dependencies: [package]\nname = \"test-bc\"\nversion = \"0.1.0\"\nedition = \"2021\" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies]\nclap = { version = \"3.1.6\", features = [\"derive\"] }\nlog = \"0.4.14\"\nenv_logger = \"0.10.0\"\nstatime = { git = \"https://github.com/pendulum-project/statime.git\", rev = \"52b17e3\" }\nstatime-linux = { git = \"https://github.com/pendulum-project/statime.git\", rev = \"52b17e3\" }\ntokio = { version = \"1.27\", features = [\"full\"] } Then, in src/main.rs, add the following code: use std::env; use statime::{ datastructures::{ common::{ClockIdentity, PortIdentity, TimeSource}, datasets::{DefaultDS, DelayMechanism, PortDS, TimePropertiesDS}, messages::SdoId, }, filters::basic::BasicFilter, port::Port, ptp_instance::PtpInstance,\n};\nuse statime_linux::{ clock::{LinuxClock, LinuxTimer, RawLinuxClock}, network::linux::{get_clock_id, LinuxRuntime},\n}; #[tokio::main]\nasync fn main() { env_logger::init(); let local_clock = LinuxClock::new(RawLinuxClock::get_realtime_clock()); let mut network_runtime = LinuxRuntime::new(false, &local_clock); let clock_identity = ClockIdentity(get_clock_id().expect(\"Could not get clock identity\")); let default_ds = DefaultDS::new_boundary_clock(clock_identity, 2, 128, 128, 0, SdoId::default()); let time_properties_ds = TimePropertiesDS::new_arbitrary_time(false, false, TimeSource::InternalOscillator); let port_1_ds = PortDS::new( PortIdentity { clock_identity, port_number: 1, }, 1, 1, 3, 0, DelayMechanism::E2E, 1, ); let interface = env::var(\"PORT1\") .expect(\"PORT1 interface descriptor not set\") .parse() .expect(\"invalid interface descriptor for PORT1\"); let port_1 = Port::new(port_1_ds, &mut network_runtime, interface).await; let port_2_ds = PortDS::new( PortIdentity { clock_identity, port_number: 2, }, 1, 1, 3, 0, DelayMechanism::E2E, 1, ); let interface = env::var(\"PORT2\") .expect(\"PORT2 interface descriptor not set\") .parse() .expect(\"invalid interface descriptor for PORT2\"); let port_2 = Port::new(port_2_ds, &mut network_runtime, interface).await; let mut instance = PtpInstance::new_boundary_clock( default_ds, time_properties_ds, [port_1, port_2], local_clock, BasicFilter::new(0.25), ); instance.run(&LinuxTimer).await;\n} This configures two PTP ports, binds them to interfaces described by the environment variables PORT1 and PORT2, and starts a boundary clock PTP instance. To run the binary, execute the following commands: # use ifconfig to find the descriptors corresponding to the interfaces connected to the ordinary clocks\nifconfig\nPORT1=enp1s0f0 PORT2=enp1s0f1 cargo run","breadcrumbs":"Setting up a simple PTP network » Boundary Clock","id":"2","title":"Boundary Clock"}},"length":3,"save":true},"fields":["title","body","breadcrumbs"],"index":{"body":{"root":{"0":{".":{"1":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{".":{"1":{"4":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.7320508075688772}}},"1":{".":{"2":{"7":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":2.6457513110645907}}},"2":{"0":{"2":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"3":{".":{"1":{".":{"6":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"5":{"2":{"b":{"1":{"7":{"df":0,"docs":{},"e":{"3":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{".":{"2":{"5":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":1,"docs":{"1":{"tf":1.0}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"1":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":1.7320508075688772}}},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":2.449489742783178},"2":{"tf":2.23606797749979}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"{":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}}}},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"{":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"e":{"2":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":2.23606797749979}}}}}}}}},"df":0,"docs":{}}},"o":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"0":{"tf":1.0},"1":{"tf":1.0}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"v":{":":{":":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"(":{"\"":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"2":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"d":{"df":0,"docs":{},"o":{"c":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{},"f":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}},"n":{"c":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"(":{"&":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"a":{"c":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.8284271247461903}},"e":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"2":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"/":{"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.0},"2":{"tf":1.0}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":2.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}},"df":1,"docs":{"0":{"tf":1.7320508075688772}}}}}}},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"1":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.0},"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"2":{"tf":1.0}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}},"v":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{":":{":":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}},"t":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.7320508075688772}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":2.0},"2":{"tf":1.7320508075688772}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}},"d":{":":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"a":{"df":0,"docs":{},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{":":{":":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"o":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}},"s":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.0}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}}}},"breadcrumbs":{"root":{"0":{".":{"1":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{".":{"1":{"4":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.7320508075688772}}},"1":{".":{"2":{"7":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":2.6457513110645907}}},"2":{"0":{"2":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"3":{".":{"1":{".":{"6":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"5":{"2":{"b":{"1":{"7":{"df":0,"docs":{},"e":{"3":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{".":{"2":{"5":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":1,"docs":{"1":{"tf":1.0}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"1":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":2.0}}},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":2.6457513110645907},"2":{"tf":2.449489742783178}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"{":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}}}},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"{":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"e":{"2":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":2.23606797749979}}}}}}}}},"df":0,"docs":{}}},"o":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"0":{"tf":1.0},"1":{"tf":1.0}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"v":{":":{":":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"(":{"\"":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"2":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"d":{"df":0,"docs":{},"o":{"c":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{},"f":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}},"n":{"c":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"(":{"&":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"a":{"c":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.8284271247461903}},"e":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"2":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"/":{"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.0},"2":{"tf":1.0}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":2.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}},"df":3,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"2":{"tf":1.0}}}}}}},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"1":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.23606797749979},"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"2":{"tf":1.0}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.4142135623730951},"2":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}},"v":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{":":{":":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}},"t":{"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.0},"2":{"tf":2.0}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.0},"2":{"tf":1.0}}}}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":2.0},"2":{"tf":1.7320508075688772}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}},"d":{":":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"a":{"df":0,"docs":{},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{":":{":":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"o":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.4142135623730951},"2":{"tf":1.4142135623730951}}},"s":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.0}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}}}},"title":{"root":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"0":{"tf":1.0}}}}}}}}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"lang":"English","pipeline":["trimmer","stopWordFilter","stemmer"],"ref":"id","version":"0.9.5"},"results_options":{"limit_results":30,"teaser_word_count":30},"search_options":{"bool":"OR","expand":true,"fields":{"body":{"boost":1},"breadcrumbs":{"boost":1},"title":{"boost":2}}}}); \ No newline at end of file diff --git a/searchindex.json b/searchindex.json new file mode 100644 index 000000000..45a9a81ce --- /dev/null +++ b/searchindex.json @@ -0,0 +1 @@ +{"doc_urls":["setup.html#setting-up-a-simple-ptp-network","setup.html#ordinary-clocks","setup.html#boundary-clock"],"index":{"documentStore":{"docInfo":{"0":{"body":21,"breadcrumbs":10,"title":5},"1":{"body":58,"breadcrumbs":7,"title":2},"2":{"body":218,"breadcrumbs":7,"title":2}},"docs":{"0":{"body":"This example network configuration consists of two ordinary clocks, connected to each other through a boundary clock, all of which are running on Linux: setup It should be relatively straightforward to extrapolate for more complicated networks.","breadcrumbs":"Setting up a simple PTP network » Setting up a simple PTP network","id":"0","title":"Setting up a simple PTP network"},"1":{"body":"To get PTP up and running for each of the ordinary clocks, install statime-linux on both of them: cargo install --git https://github.com/pendulum-project/statime.git --rev 52b17e3 --bin statime-linux statime-linux contains a CLI binary that can be used to start ordinary clock instances: # use ifconfig to find the descriptor corresponding to the interface connected to the boundary clock\nifconfig\nstatime-linux --interface enp1s0f1 Ordinary clocks can also be configured through code. Doing so is very similar to configuring boundary clocks, which is explained in the next section.","breadcrumbs":"Setting up a simple PTP network » Ordinary Clocks","id":"1","title":"Ordinary Clocks"},"2":{"body":"Setting up a boundary clock is currently only possible through code. Start by creating a new Rust project: cargo new boundary_clock\ncd boundary_clock In Cargo.toml, add the following dependencies: [package]\nname = \"test-bc\"\nversion = \"0.1.0\"\nedition = \"2021\" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies]\nclap = { version = \"3.1.6\", features = [\"derive\"] }\nlog = \"0.4.14\"\nenv_logger = \"0.10.0\"\nstatime = { git = \"https://github.com/pendulum-project/statime.git\", rev = \"52b17e3\" }\nstatime-linux = { git = \"https://github.com/pendulum-project/statime.git\", rev = \"52b17e3\" }\ntokio = { version = \"1.27\", features = [\"full\"] } Then, in src/main.rs, add the following code: use std::env; use statime::{ datastructures::{ common::{ClockIdentity, PortIdentity, TimeSource}, datasets::{DefaultDS, DelayMechanism, PortDS, TimePropertiesDS}, messages::SdoId, }, filters::basic::BasicFilter, port::Port, ptp_instance::PtpInstance,\n};\nuse statime_linux::{ clock::{LinuxClock, LinuxTimer, RawLinuxClock}, network::linux::{get_clock_id, LinuxRuntime},\n}; #[tokio::main]\nasync fn main() { env_logger::init(); let local_clock = LinuxClock::new(RawLinuxClock::get_realtime_clock()); let mut network_runtime = LinuxRuntime::new(false, &local_clock); let clock_identity = ClockIdentity(get_clock_id().expect(\"Could not get clock identity\")); let default_ds = DefaultDS::new_boundary_clock(clock_identity, 2, 128, 128, 0, SdoId::default()); let time_properties_ds = TimePropertiesDS::new_arbitrary_time(false, false, TimeSource::InternalOscillator); let port_1_ds = PortDS::new( PortIdentity { clock_identity, port_number: 1, }, 1, 1, 3, 0, DelayMechanism::E2E, 1, ); let interface = env::var(\"PORT1\") .expect(\"PORT1 interface descriptor not set\") .parse() .expect(\"invalid interface descriptor for PORT1\"); let port_1 = Port::new(port_1_ds, &mut network_runtime, interface).await; let port_2_ds = PortDS::new( PortIdentity { clock_identity, port_number: 2, }, 1, 1, 3, 0, DelayMechanism::E2E, 1, ); let interface = env::var(\"PORT2\") .expect(\"PORT2 interface descriptor not set\") .parse() .expect(\"invalid interface descriptor for PORT2\"); let port_2 = Port::new(port_2_ds, &mut network_runtime, interface).await; let mut instance = PtpInstance::new_boundary_clock( default_ds, time_properties_ds, [port_1, port_2], local_clock, BasicFilter::new(0.25), ); instance.run(&LinuxTimer).await;\n} This configures two PTP ports, binds them to interfaces described by the environment variables PORT1 and PORT2, and starts a boundary clock PTP instance. To run the binary, execute the following commands: # use ifconfig to find the descriptors corresponding to the interfaces connected to the ordinary clocks\nifconfig\nPORT1=enp1s0f0 PORT2=enp1s0f1 cargo run","breadcrumbs":"Setting up a simple PTP network » Boundary Clock","id":"2","title":"Boundary Clock"}},"length":3,"save":true},"fields":["title","body","breadcrumbs"],"index":{"body":{"root":{"0":{".":{"1":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{".":{"1":{"4":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.7320508075688772}}},"1":{".":{"2":{"7":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":2.6457513110645907}}},"2":{"0":{"2":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"3":{".":{"1":{".":{"6":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"5":{"2":{"b":{"1":{"7":{"df":0,"docs":{},"e":{"3":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{".":{"2":{"5":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":1,"docs":{"1":{"tf":1.0}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"1":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":1.7320508075688772}}},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":2.449489742783178},"2":{"tf":2.23606797749979}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"{":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}}}},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"{":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"e":{"2":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":2.23606797749979}}}}}}}}},"df":0,"docs":{}}},"o":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"0":{"tf":1.0},"1":{"tf":1.0}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"v":{":":{":":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"(":{"\"":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"2":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"d":{"df":0,"docs":{},"o":{"c":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{},"f":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}},"n":{"c":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"(":{"&":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"a":{"c":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.8284271247461903}},"e":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"2":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"/":{"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.0},"2":{"tf":1.0}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":2.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}},"df":1,"docs":{"0":{"tf":1.7320508075688772}}}}}}},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"1":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.0},"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"2":{"tf":1.0}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}},"v":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{":":{":":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}},"t":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.7320508075688772}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":2.0},"2":{"tf":1.7320508075688772}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}},"d":{":":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"a":{"df":0,"docs":{},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{":":{":":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"o":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}},"s":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.0}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}}}},"breadcrumbs":{"root":{"0":{".":{"1":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"4":{".":{"1":{"4":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.7320508075688772}}},"1":{".":{"2":{"7":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":2.6457513110645907}}},"2":{"0":{"2":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"3":{".":{"1":{".":{"6":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"5":{"2":{"b":{"1":{"7":{"df":0,"docs":{},"e":{"3":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"d":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{".":{"2":{"5":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"c":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":1,"docs":{"1":{"tf":1.0}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"1":{"tf":1.0}}}},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":2.0}}},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"df":3,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":2.6457513110645907},"2":{"tf":2.449489742783178}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"{":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}}}},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"2":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"{":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"e":{"2":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":2.23606797749979}}}}}}}}},"df":0,"docs":{}}},"o":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"0":{"tf":1.0},"1":{"tf":1.0}}}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"1":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"v":{":":{":":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"(":{"\"":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"2":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"l":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{":":{":":{"b":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"n":{"d":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}},"df":0,"docs":{}}},"n":{"df":1,"docs":{"2":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"s":{":":{"/":{"/":{"d":{"df":0,"docs":{},"o":{"c":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"u":{"b":{".":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"/":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{},"f":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}},"n":{"c":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"(":{"&":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"f":{"a":{"c":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.8284271247461903}},"e":{")":{".":{"a":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"df":1,"docs":{"2":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"/":{"c":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"/":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.0},"2":{"tf":1.0}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}},"o":{"c":{"a":{"df":0,"docs":{},"l":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}}},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":2.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{":":{":":{"df":0,"docs":{},"{":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}},"df":3,"docs":{"0":{"tf":2.23606797749979},"1":{"tf":1.0},"2":{"tf":1.0}}}}}}},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"x":{"df":0,"docs":{},"t":{"df":1,"docs":{"1":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":2.23606797749979},"2":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"p":{"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"1":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"0":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"=":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"p":{"1":{"df":0,"docs":{},"s":{"0":{"df":0,"docs":{},"f":{"1":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}},"df":0,"docs":{}},"_":{"1":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"2":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":1,"docs":{"2":{"tf":1.0}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.4142135623730951},"2":{"tf":1.7320508075688772}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"r":{"a":{"df":0,"docs":{},"w":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}},"v":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"s":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"i":{"d":{":":{":":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"1":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":1,"docs":{"2":{"tf":1.0}}},"t":{"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.0},"2":{"tf":2.0}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"1":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"l":{"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.0},"2":{"tf":1.0}}}}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.4142135623730951}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":2,"docs":{"1":{"tf":2.0},"2":{"tf":1.7320508075688772}},"e":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":1,"docs":{"2":{"tf":1.0}}}}}}}},"df":0,"docs":{}}}}}},"d":{":":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":1,"docs":{"2":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"0":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"2":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":3,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"2":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"_":{"d":{"df":1,"docs":{"2":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"d":{"df":1,"docs":{"2":{"tf":1.0}},"s":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"_":{"a":{"df":0,"docs":{},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"y":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"2":{"tf":1.0}},"e":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{":":{":":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":1,"docs":{"2":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"o":{"df":2,"docs":{"0":{"tf":1.0},"2":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"p":{"df":3,"docs":{"0":{"tf":1.7320508075688772},"1":{"tf":1.4142135623730951},"2":{"tf":1.4142135623730951}}},"s":{"df":2,"docs":{"1":{"tf":1.4142135623730951},"2":{"tf":2.0}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"2":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"2":{"tf":1.7320508075688772}}}}}}}}}}},"title":{"root":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"2":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"1":{"tf":1.0},"2":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"0":{"tf":1.0}}}}}}}}},"o":{"df":0,"docs":{},"r":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"0":{"tf":1.0}}}}}}},"lang":"English","pipeline":["trimmer","stopWordFilter","stemmer"],"ref":"id","version":"0.9.5"},"results_options":{"limit_results":30,"teaser_word_count":30},"search_options":{"bool":"OR","expand":true,"fields":{"body":{"boost":1},"breadcrumbs":{"boost":1},"title":{"boost":2}}}} \ No newline at end of file diff --git a/setup.html b/setup.html new file mode 100644 index 000000000..a07464fd5 --- /dev/null +++ b/setup.html @@ -0,0 +1,334 @@ + + + + + + Setting up a simple PTP network - Statime Reference Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Setting up a simple PTP network

+

This example network configuration consists of two ordinary clocks, connected to each other through a boundary clock, +all of which are running on Linux:

+

setup

+

It should be relatively straightforward to extrapolate for more complicated networks.

+

Ordinary Clocks

+

To get PTP up and running for each of the ordinary clocks, install statime-linux on both of them:

+
cargo install --git https://github.com/pendulum-project/statime.git --rev 52b17e3 --bin statime-linux
+
+

statime-linux contains a CLI binary that can be used to start ordinary clock instances:

+
# use ifconfig to find the descriptor corresponding to the interface connected to the boundary clock
+ifconfig
+statime-linux --interface enp1s0f1
+
+

Ordinary clocks can also be configured through code. Doing so is very similar to configuring boundary clocks, which is +explained in the next section.

+

Boundary Clock

+

Setting up a boundary clock is currently only possible through code. Start by creating a new Rust project:

+
cargo new boundary_clock
+cd boundary_clock
+
+

In Cargo.toml, add the following dependencies:

+
[package]
+name = "test-bc"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "3.1.6", features = ["derive"] }
+log = "0.4.14"
+env_logger = "0.10.0"
+statime = { git = "https://github.com/pendulum-project/statime.git", rev = "52b17e3" }
+statime-linux = { git = "https://github.com/pendulum-project/statime.git", rev = "52b17e3" }
+tokio = { version = "1.27", features = ["full"] }
+
+

Then, in src/main.rs, add the following code:

+
use std::env;
+
+use statime::{
+    datastructures::{
+        common::{ClockIdentity, PortIdentity, TimeSource},
+        datasets::{DefaultDS, DelayMechanism, PortDS, TimePropertiesDS},
+        messages::SdoId,
+    },
+    filters::basic::BasicFilter,
+    port::Port,
+    ptp_instance::PtpInstance,
+};
+use statime_linux::{
+    clock::{LinuxClock, LinuxTimer, RawLinuxClock},
+    network::linux::{get_clock_id, LinuxRuntime},
+};
+
+#[tokio::main]
+async fn main() {
+    env_logger::init();
+
+    let local_clock = LinuxClock::new(RawLinuxClock::get_realtime_clock());
+    let mut network_runtime = LinuxRuntime::new(false, &local_clock);
+    let clock_identity = ClockIdentity(get_clock_id().expect("Could not get clock identity"));
+
+    let default_ds =
+        DefaultDS::new_boundary_clock(clock_identity, 2, 128, 128, 0, SdoId::default());
+
+    let time_properties_ds =
+        TimePropertiesDS::new_arbitrary_time(false, false, TimeSource::InternalOscillator);
+
+    let port_1_ds = PortDS::new(
+        PortIdentity {
+            clock_identity,
+            port_number: 1,
+        },
+        1,
+        1,
+        3,
+        0,
+        DelayMechanism::E2E,
+        1,
+    );
+    let interface = env::var("PORT1")
+        .expect("PORT1 interface descriptor not set")
+        .parse()
+        .expect("invalid interface descriptor for PORT1");
+    let port_1 = Port::new(port_1_ds, &mut network_runtime, interface).await;
+
+    let port_2_ds = PortDS::new(
+        PortIdentity {
+            clock_identity,
+            port_number: 2,
+        },
+        1,
+        1,
+        3,
+        0,
+        DelayMechanism::E2E,
+        1,
+    );
+    let interface = env::var("PORT2")
+        .expect("PORT2 interface descriptor not set")
+        .parse()
+        .expect("invalid interface descriptor for PORT2");
+    let port_2 = Port::new(port_2_ds, &mut network_runtime, interface).await;
+
+    let mut instance = PtpInstance::new_boundary_clock(
+        default_ds,
+        time_properties_ds,
+        [port_1, port_2],
+        local_clock,
+        BasicFilter::new(0.25),
+    );
+
+    instance.run(&LinuxTimer).await;
+}
+

This configures two PTP ports, binds them to interfaces described by the environment variables PORT1 and PORT2, and +starts a boundary clock PTP instance. To run the binary, execute the following commands:

+
# use ifconfig to find the descriptors corresponding to the interfaces connected to the ordinary clocks
+ifconfig
+PORT1=enp1s0f0 PORT2=enp1s0f1 cargo run
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/tomorrow-night.css b/tomorrow-night.css new file mode 100644 index 000000000..81fe276e7 --- /dev/null +++ b/tomorrow-night.css @@ -0,0 +1,102 @@ +/* Tomorrow Night Theme */ +/* https://github.com/jmblog/color-themes-for-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* https://github.com/jmblog/color-themes-for-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment { + color: #969896; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-attribute, +.hljs-tag, +.hljs-regexp, +.ruby .hljs-constant, +.xml .hljs-tag .hljs-title, +.xml .hljs-pi, +.xml .hljs-doctype, +.html .hljs-doctype, +.css .hljs-id, +.css .hljs-class, +.css .hljs-pseudo { + color: #cc6666; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-preprocessor, +.hljs-pragma, +.hljs-built_in, +.hljs-literal, +.hljs-params, +.hljs-constant { + color: #de935f; +} + +/* Tomorrow Yellow */ +.ruby .hljs-class .hljs-title, +.css .hljs-rule .hljs-attribute { + color: #f0c674; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-value, +.hljs-inheritance, +.hljs-header, +.hljs-name, +.ruby .hljs-symbol, +.xml .hljs-cdata { + color: #b5bd68; +} + +/* Tomorrow Aqua */ +.hljs-title, +.css .hljs-hexcolor { + color: #8abeb7; +} + +/* Tomorrow Blue */ +.hljs-function, +.python .hljs-decorator, +.python .hljs-title, +.ruby .hljs-function .hljs-title, +.ruby .hljs-title .hljs-keyword, +.perl .hljs-sub, +.javascript .hljs-title, +.coffeescript .hljs-title { + color: #81a2be; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.javascript .hljs-function { + color: #b294bb; +} + +.hljs { + display: block; + overflow-x: auto; + background: #1d1f21; + color: #c5c8c6; +} + +.coffeescript .javascript, +.javascript .xml, +.tex .hljs-formula, +.xml .javascript, +.xml .vbscript, +.xml .css, +.xml .hljs-cdata { + opacity: 0.5; +} + +.hljs-addition { + color: #718c00; +} + +.hljs-deletion { + color: #c82829; +}