diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9081435..a69bf52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,8 @@ env: RUST_BACKTRACE: short RUSTFLAGS: -D warnings # Crate publish order (dependencies first) - CRATES: "masterror-template masterror-derive masterror" + # template → derive → knowledge → masterror → cli + CRATES: "masterror-template masterror-derive masterror-knowledge masterror masterror-cli" jobs: # ════════════════════════════════════════════════════════════════════════════ @@ -58,13 +59,160 @@ jobs: echo "version=$MSRV" >> "$GITHUB_OUTPUT" echo "MSRV: $MSRV" + # ════════════════════════════════════════════════════════════════════════════ + # Detect changed crates (dependency-aware) + # ════════════════════════════════════════════════════════════════════════════ + + changes: + name: Detect Changes + runs-on: ubuntu-latest + outputs: + # Individual crate changes + template: ${{ steps.filter.outputs.template }} + derive: ${{ steps.filter.outputs.derive }} + knowledge: ${{ steps.filter.outputs.knowledge }} + masterror: ${{ steps.filter.outputs.masterror }} + cli: ${{ steps.filter.outputs.cli }} + # Dependency-aware: need to rebuild these + need-template: ${{ steps.deps.outputs.need-template }} + need-derive: ${{ steps.deps.outputs.need-derive }} + need-knowledge: ${{ steps.deps.outputs.need-knowledge }} + need-masterror: ${{ steps.deps.outputs.need-masterror }} + need-cli: ${{ steps.deps.outputs.need-cli }} + # Any library changed (for full workspace checks) + any-lib: ${{ steps.deps.outputs.any-lib }} + # CI/config changed (force full rebuild) + ci: ${{ steps.filter.outputs.ci }} + steps: + - uses: actions/checkout@v5 + + - name: Detect file changes + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + template: + - 'masterror-template/**' + derive: + - 'masterror-derive/**' + knowledge: + - 'masterror-knowledge/**' + masterror: + - 'src/**' + - 'Cargo.toml' + - 'build.rs' + cli: + - 'masterror-cli/**' + ci: + - '.github/workflows/**' + - 'Cargo.lock' + - 'deny.toml' + - 'cliff.toml' + - '.cargo/**' + + - name: Compute dependency graph + id: deps + run: | + # Dependency graph: + # template ← derive ← masterror + # ↗ + # knowledge ← cli + # ↘ masterror (optional feature) + + TEMPLATE="${{ steps.filter.outputs.template }}" + DERIVE="${{ steps.filter.outputs.derive }}" + KNOWLEDGE="${{ steps.filter.outputs.knowledge }}" + MASTERROR="${{ steps.filter.outputs.masterror }}" + CLI="${{ steps.filter.outputs.cli }}" + CI="${{ steps.filter.outputs.ci }}" + + # Force all if CI config changed or workflow_dispatch + if [[ "$CI" == "true" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "CI config changed or manual trigger - rebuilding all" + echo "need-template=true" >> "$GITHUB_OUTPUT" + echo "need-derive=true" >> "$GITHUB_OUTPUT" + echo "need-knowledge=true" >> "$GITHUB_OUTPUT" + echo "need-masterror=true" >> "$GITHUB_OUTPUT" + echo "need-cli=true" >> "$GITHUB_OUTPUT" + echo "any-lib=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # template: standalone + NEED_TEMPLATE="$TEMPLATE" + + # derive: depends on template + if [[ "$DERIVE" == "true" ]] || [[ "$TEMPLATE" == "true" ]]; then + NEED_DERIVE=true + else + NEED_DERIVE=false + fi + + # knowledge: standalone + NEED_KNOWLEDGE="$KNOWLEDGE" + + # masterror: depends on template, derive, optionally knowledge + if [[ "$MASTERROR" == "true" ]] || [[ "$TEMPLATE" == "true" ]] || \ + [[ "$DERIVE" == "true" ]] || [[ "$KNOWLEDGE" == "true" ]]; then + NEED_MASTERROR=true + else + NEED_MASTERROR=false + fi + + # cli: depends on knowledge + if [[ "$CLI" == "true" ]] || [[ "$KNOWLEDGE" == "true" ]]; then + NEED_CLI=true + else + NEED_CLI=false + fi + + # Any library changed? + if [[ "$NEED_TEMPLATE" == "true" ]] || [[ "$NEED_DERIVE" == "true" ]] || \ + [[ "$NEED_KNOWLEDGE" == "true" ]] || [[ "$NEED_MASTERROR" == "true" ]] || \ + [[ "$NEED_CLI" == "true" ]]; then + ANY_LIB=true + else + ANY_LIB=false + fi + + echo "need-template=$NEED_TEMPLATE" >> "$GITHUB_OUTPUT" + echo "need-derive=$NEED_DERIVE" >> "$GITHUB_OUTPUT" + echo "need-knowledge=$NEED_KNOWLEDGE" >> "$GITHUB_OUTPUT" + echo "need-masterror=$NEED_MASTERROR" >> "$GITHUB_OUTPUT" + echo "need-cli=$NEED_CLI" >> "$GITHUB_OUTPUT" + echo "any-lib=$ANY_LIB" >> "$GITHUB_OUTPUT" + + echo "Summary:" + echo " template: $TEMPLATE → need: $NEED_TEMPLATE" + echo " derive: $DERIVE → need: $NEED_DERIVE" + echo " knowledge: $KNOWLEDGE → need: $NEED_KNOWLEDGE" + echo " masterror: $MASTERROR → need: $NEED_MASTERROR" + echo " cli: $CLI → need: $NEED_CLI" + echo " any-lib: $ANY_LIB" + + # GitHub Step Summary + cat >> $GITHUB_STEP_SUMMARY << EOF + ## 🔍 Change Detection + + | Crate | Changed | Rebuild | + |-------|---------|---------| + | masterror-template | $([[ "$TEMPLATE" == "true" ]] && echo "✅" || echo "—") | $([[ "$NEED_TEMPLATE" == "true" ]] && echo "🔨" || echo "⏭️") | + | masterror-derive | $([[ "$DERIVE" == "true" ]] && echo "✅" || echo "—") | $([[ "$NEED_DERIVE" == "true" ]] && echo "🔨" || echo "⏭️") | + | masterror-knowledge | $([[ "$KNOWLEDGE" == "true" ]] && echo "✅" || echo "—") | $([[ "$NEED_KNOWLEDGE" == "true" ]] && echo "🔨" || echo "⏭️") | + | masterror | $([[ "$MASTERROR" == "true" ]] && echo "✅" || echo "—") | $([[ "$NEED_MASTERROR" == "true" ]] && echo "🔨" || echo "⏭️") | + | masterror-cli | $([[ "$CLI" == "true" ]] && echo "✅" || echo "—") | $([[ "$NEED_CLI" == "true" ]] && echo "🔨" || echo "⏭️") | + + **Legend:** ✅ = changed, 🔨 = will rebuild, ⏭️ = skipped, — = no changes + EOF + # ════════════════════════════════════════════════════════════════════════════ # STAGE 1: CHECKS (parallel matrix) # ════════════════════════════════════════════════════════════════════════════ check: name: Check (${{ matrix.rust }} / ${{ matrix.os }}) - needs: msrv + needs: [msrv, changes] + if: needs.changes.outputs.any-lib == 'true' runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -124,6 +272,8 @@ jobs: fmt: name: Format + needs: changes + if: needs.changes.outputs.any-lib == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -138,6 +288,8 @@ jobs: docs: name: Documentation + needs: changes + if: needs.changes.outputs.any-lib == 'true' runs-on: ubuntu-latest env: RUSTDOCFLAGS: -D warnings @@ -155,6 +307,8 @@ jobs: no-std: name: no_std (${{ matrix.name }}) + needs: changes + if: needs.changes.outputs.need-masterror == 'true' runs-on: ubuntu-latest strategy: fail-fast: false @@ -185,7 +339,7 @@ jobs: save-if: ${{ github.ref == 'refs/heads/main' }} - name: Check ${{ matrix.name }} - run: cargo check ${{ matrix.args }} + run: cargo check -p masterror ${{ matrix.args }} security: name: Security Audit @@ -225,8 +379,16 @@ jobs: test: name: Test Suite - needs: [check, fmt, no-std, security, reuse] - if: ${{ !inputs.skip_tests }} + needs: [changes, check, fmt, no-std, security, reuse] + if: | + always() && + !inputs.skip_tests && + needs.changes.outputs.any-lib == 'true' && + (needs.check.result == 'success' || needs.check.result == 'skipped') && + (needs.fmt.result == 'success' || needs.fmt.result == 'skipped') && + (needs['no-std'].result == 'success' || needs['no-std'].result == 'skipped') && + needs.security.result == 'success' && + needs.reuse.result == 'success' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -262,7 +424,11 @@ jobs: coverage: name: Coverage - needs: test + needs: [changes, test] + if: | + always() && + needs.changes.outputs.any-lib == 'true' && + needs.test.result == 'success' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -309,9 +475,13 @@ jobs: benchmarks: name: Benchmarks - needs: test + needs: [changes, test] runs-on: ubuntu-latest - if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' + if: | + always() && + needs.changes.outputs.need-masterror == 'true' && + needs.test.result == 'success' && + (github.event_name == 'pull_request' || github.ref == 'refs/heads/main') steps: - uses: actions/checkout@v5 @@ -340,12 +510,18 @@ jobs: changelog: name: Update Changelog - needs: [check, fmt, no-std, security, reuse] + needs: [changes, check, fmt, no-std, security, reuse] runs-on: ubuntu-latest if: | + always() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' && - !contains(github.event.head_commit.message || '', '[skip ci]') + !contains(github.event.head_commit.message || '', '[skip ci]') && + (needs.check.result == 'success' || needs.check.result == 'skipped') && + (needs.fmt.result == 'success' || needs.fmt.result == 'skipped') && + (needs['no-std'].result == 'success' || needs['no-std'].result == 'skipped') && + needs.security.result == 'success' && + needs.reuse.result == 'success' steps: - uses: actions/checkout@v5 with: @@ -412,10 +588,12 @@ jobs: release: name: Release - needs: [test, changelog] + needs: [changes, test, changelog] if: | always() && + needs.changes.outputs.any-lib == 'true' && (needs.test.result == 'success' || needs.test.result == 'skipped') && + (needs.changelog.result == 'success' || needs.changelog.result == 'skipped') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message || '', '[skip ci]') @@ -508,7 +686,7 @@ jobs: declare -A LOCAL REMOTE NEEDS_PUBLISH PUBLISHED_ANY=false - for crate in masterror-template masterror-derive masterror; do + for crate in $CRATES; do LOCAL[$crate]=$(get_local_version "$crate") REMOTE[$crate]=$(get_remote_version "$crate") @@ -527,16 +705,21 @@ jobs: # Dependency-aware publishing # ══════════════════════════════════════════════════════════════════ - # If derive changes, masterror should also be republished - # (it depends on derive, users need consistent versions) + # Dependency consistency warnings if [[ "${NEEDS_PUBLISH[masterror-derive]}" == "true" ]] && \ [[ "${NEEDS_PUBLISH[masterror]}" == "false" ]]; then warn "masterror-derive changed but masterror version unchanged" warn "Consider bumping masterror version for dependency consistency" fi - # Publish in order: template → derive → masterror - for crate in masterror-template masterror-derive masterror; do + if [[ "${NEEDS_PUBLISH[masterror-knowledge]}" == "true" ]] && \ + [[ "${NEEDS_PUBLISH[masterror-cli]}" == "false" ]]; then + warn "masterror-knowledge changed but masterror-cli version unchanged" + warn "Consider bumping masterror-cli version for dependency consistency" + fi + + # Publish in order: template → derive → knowledge → masterror → cli + for crate in $CRATES; do if [[ "${NEEDS_PUBLISH[$crate]}" == "true" ]]; then if publish_crate "$crate"; then PUBLISHED_ANY=true @@ -605,7 +788,9 @@ jobs: |-------|--------| | masterror-template | ${{ steps.publish.outputs.published == 'true' && '✅ Published' || '⏭️ Skipped' }} | | masterror-derive | ${{ steps.publish.outputs.published == 'true' && '✅ Published' || '⏭️ Skipped' }} | + | masterror-knowledge | ${{ steps.publish.outputs.published == 'true' && '✅ Published' || '⏭️ Skipped' }} | | masterror | ${{ steps.publish.outputs.published == 'true' && '✅ Published' || '⏭️ Skipped' }} | + | masterror-cli | ${{ steps.publish.outputs.published == 'true' && '✅ Published' || '⏭️ Skipped' }} | **Version:** `${{ steps.publish.outputs.version }}` EOF @@ -681,19 +866,48 @@ jobs: ci-success: name: CI Success - needs: [check, fmt, docs, no-std, security, reuse, test] + needs: [changes, check, fmt, docs, no-std, security, reuse, test] if: always() runs-on: ubuntu-latest steps: - name: Check all jobs run: | - results="${{ needs.check.result }} ${{ needs.fmt.result }} ${{ needs.docs.result }} ${{ needs.no-std.result }} ${{ needs.security.result }} ${{ needs.reuse.result }} ${{ needs.test.result }}" - - for r in $results; do - if [[ "$r" == "failure" ]]; then - echo "::error::One or more required jobs failed" - exit 1 - fi - done + echo "Job results:" + echo " changes: ${{ needs.changes.result }}" + echo " check: ${{ needs.check.result }}" + echo " fmt: ${{ needs.fmt.result }}" + echo " docs: ${{ needs.docs.result }}" + echo " no-std: ${{ needs['no-std'].result }}" + echo " security: ${{ needs.security.result }}" + echo " reuse: ${{ needs.reuse.result }}" + echo " test: ${{ needs.test.result }}" + + FAILED=false + + # Changes detection must succeed + [[ "${{ needs.changes.result }}" != "success" ]] && \ + echo "::error::Changes detection failed" && FAILED=true + + # Security and REUSE must always pass + [[ "${{ needs.security.result }}" == "failure" ]] && \ + echo "::error::Security audit failed" && FAILED=true + [[ "${{ needs.reuse.result }}" == "failure" ]] && \ + echo "::error::REUSE compliance failed" && FAILED=true + + # Other jobs: failure is not OK (skipped is fine) + [[ "${{ needs.check.result }}" == "failure" ]] && \ + echo "::error::Check job failed" && FAILED=true + [[ "${{ needs.fmt.result }}" == "failure" ]] && \ + echo "::error::Format job failed" && FAILED=true + [[ "${{ needs.docs.result }}" == "failure" ]] && \ + echo "::error::Docs job failed" && FAILED=true + [[ "${{ needs['no-std'].result }}" == "failure" ]] && \ + echo "::error::no-std job failed" && FAILED=true + [[ "${{ needs.test.result }}" == "failure" ]] && \ + echo "::error::Test job failed" && FAILED=true + + if [[ "$FAILED" == "true" ]]; then + exit 1 + fi - echo "✅ All CI checks passed!" + echo "✅ All CI checks passed (some may have been skipped due to no changes)" diff --git a/.hooks/pre-commit b/.hooks/pre-commit index eeacd39..ccc498a 100755 --- a/.hooks/pre-commit +++ b/.hooks/pre-commit @@ -20,6 +20,25 @@ else echo " - pip: pip install reuse" fi +echo "🔧 Linting GitHub Actions..." +if command -v actionlint &> /dev/null; then + actionlint +else + echo "⚠️ Warning: actionlint not installed, skipping Actions linting" + echo " Install with:" + echo " - Arch Linux: paru -S actionlint" + echo " - Go: go install github.com/rhysd/actionlint/cmd/actionlint@latest" + echo " - Homebrew: brew install actionlint" +fi + +echo "🔒 Checking no_std compatibility..." +cargo check --no-default-features -q +cargo check --features std -q +cargo check --no-default-features --features tracing -q +cargo check --no-default-features --features metrics -q +cargo check --no-default-features --features colored -q +cargo check --all-features -q + echo "🔍 Running clippy (all features, all targets)..." cargo clippy --workspace --all-targets --all-features -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index 2bb2db3..d2f553b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,7 +156,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.6.1", + "socket2 0.6.2", "time", "tracing", "url", @@ -225,12 +225,56 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -258,6 +302,27 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "assert_cmd" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514" +dependencies = [ + "anstyle", + "bstr", + "libc", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -435,6 +500,17 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "bumpalo" version = "3.19.1" @@ -482,9 +558,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.53" +version = "1.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" dependencies = [ "find-msvc-tools", "shlex", @@ -544,6 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] @@ -552,8 +629,23 @@ version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ + "anstream", "anstyle", "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -562,6 +654,12 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "combine" version = "4.6.7" @@ -972,6 +1070,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.10.7" @@ -996,6 +1100,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1185,6 +1310,15 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + [[package]] name = "flume" version = "0.11.1" @@ -1551,9 +1685,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hybrid-array" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0" +checksum = "b41fb3dc24fe72c2e3a4685eed55917c2fb228851257f4a8f2d985da9443c3e5" dependencies = [ "typenum", ] @@ -1612,7 +1746,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.2", "tokio", "tower-service", "tracing", @@ -1838,6 +1972,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.13.0" @@ -1897,9 +2037,9 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" @@ -1964,7 +2104,7 @@ checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" [[package]] name = "masterror" -version = "0.27.2" +version = "0.28.0" dependencies = [ "actix-web", "anyhow", @@ -1978,9 +2118,11 @@ dependencies = [ "log", "log-mdc", "masterror-derive", + "masterror-knowledge", "masterror-template", "metrics", "owo-colors", + "phf", "redis", "reqwest", "ryu", @@ -2005,6 +2147,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "masterror-cli" +version = "0.1.0" +dependencies = [ + "assert_cmd", + "clap", + "dirs", + "masterror-knowledge", + "owo-colors", + "predicates", + "serde", + "serde_json", + "toml", +] + [[package]] name = "masterror-derive" version = "0.11.2" @@ -2015,6 +2172,24 @@ dependencies = [ "syn", ] +[[package]] +name = "masterror-knowledge" +version = "0.1.0" +dependencies = [ + "aho-corasick", + "arrayvec", +] + +[[package]] +name = "masterror-rustc" +version = "0.1.0" +dependencies = [ + "libc", + "masterror-knowledge", + "owo-colors", + "windows-sys 0.59.0", +] + [[package]] name = "masterror-template" version = "0.4.1" @@ -2122,6 +2297,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2182,9 +2363,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-integer" @@ -2242,6 +2423,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "oorandom" version = "11.1.5" @@ -2292,6 +2479,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-multimap" version = "0.7.3" @@ -2415,6 +2608,48 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -2532,6 +2767,36 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "predicates" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "pretty_assertions" version = "1.4.1" @@ -2697,7 +2962,7 @@ dependencies = [ "itoa", "percent-encoding", "ryu", - "socket2 0.6.1", + "socket2 0.6.2", "url", "xxhash-rust", ] @@ -2720,6 +2985,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror", +] + [[package]] name = "ref-cast" version = "1.0.25" @@ -3196,6 +3472,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + [[package]] name = "slab" version = "0.4.11" @@ -3223,9 +3505,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -3612,6 +3894,22 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +dependencies = [ + "rustix", + "windows-sys 0.60.2", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + [[package]] name = "thiserror" version = "2.0.18" @@ -3643,9 +3941,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -3658,15 +3956,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -3728,7 +4026,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2 0.6.2", "tokio-macros", "windows-sys 0.61.2", ] @@ -3826,7 +4124,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.1", + "socket2 0.6.2", "sync_wrapper", "tokio", "tokio-stream", @@ -4074,6 +4372,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "utoipa" version = "5.4.0" @@ -4157,6 +4461,15 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + [[package]] name = "walkdir" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 3b7d835..ab0e5cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "masterror" -version = "0.27.2" +version = "0.28.0" rust-version = "1.92" edition = "2024" license = "MIT" @@ -42,6 +42,9 @@ include = [ members = [ "masterror-derive", "masterror-template", + "masterror-knowledge", + "masterror-cli", + "masterror-rustc", "examples/axum-rest-api", "examples/custom-domain-errors", "examples/sqlx-database", @@ -60,8 +63,9 @@ readme = "README.md" [features] -default = ["std"] +default = ["std", "derive"] std = ["uuid/std", "serde/std"] +derive = ["dep:masterror-derive", "dep:masterror-template"] tracing = ["dep:tracing", "dep:log", "dep:log-mdc", "std"] metrics = ["dep:metrics", "std"] backtrace = ["std"] @@ -82,19 +86,22 @@ tokio = ["dep:tokio", "std"] reqwest = ["dep:reqwest", "std"] teloxide = ["dep:teloxide-core", "std"] init-data = ["dep:init-data-rs", "std"] +phf = ["dep:phf"] frontend = ["dep:wasm-bindgen", "dep:js-sys", "dep:serde-wasm-bindgen", "std"] turnkey = ["std"] tonic = ["dep:tonic", "std"] openapi = ["dep:utoipa", "std"] benchmarks = ["std"] +knowledge = ["dep:masterror-knowledge"] [workspace.dependencies] masterror-derive = { version = "0.11" } masterror-template = { version = "0.4" } +masterror-knowledge = { version = "0.1" } [dependencies] -masterror-derive = { version = "0.11" } -masterror-template = { workspace = true } +masterror-derive = { version = "0.11", optional = true } +masterror-template = { workspace = true, optional = true } tracing = { version = "0.1", optional = true, default-features = false, features = [ "attributes", "std", @@ -147,6 +154,8 @@ tonic = { version = "0.14", optional = true } owo-colors = { version = "4", optional = true, default-features = false, features = [ "supports-colors", ] } +masterror-knowledge = { path = "masterror-knowledge", optional = true } +phf = { version = "0.11", optional = true, features = ["macros"] } [dev-dependencies] anyhow = { version = "1", default-features = false, features = ["std"] } @@ -158,6 +167,7 @@ tokio = { version = "1", features = [ "rt-multi-thread", "net", "time", + "io-util", ], default-features = false } trybuild = "1" toml = "0.9" @@ -179,6 +189,7 @@ toml = "0.9" [package.metadata.masterror.readme] feature_order = [ "std", + "derive", "axum", "actix", "openapi", @@ -189,6 +200,7 @@ feature_order = [ "colored", "sqlx", "sqlx-migrate", + "phf", "reqwest", "redis", "validator", @@ -200,6 +212,7 @@ feature_order = [ "tonic", "frontend", "turnkey", + "knowledge", "benchmarks", ] feature_snippet_group = 4 @@ -226,6 +239,9 @@ description = "Actix Web ResponseError and Responder implementations" [package.metadata.masterror.readme.features.std] description = "Enable std support (default); required for runtime integrations" +[package.metadata.masterror.readme.features.derive] +description = "Enable #[derive(Error, Masterror)] proc-macros (default)" + [package.metadata.masterror.readme.features.openapi] description = "Generate utoipa OpenAPI schema for ErrorResponse" @@ -283,6 +299,12 @@ description = "Log to the browser console and convert to JsValue on WASM" [package.metadata.masterror.readme.features.turnkey] description = "Ship Turnkey-specific error taxonomy and conversions" +[package.metadata.masterror.readme.features.knowledge] +description = "Rust compiler error explanations and best practices (en/ru/ko)" + +[package.metadata.masterror.readme.features.phf] +description = "Use compile-time perfect hash maps for O(1) SQLSTATE lookups" + [package.metadata.masterror.readme.features.benchmarks] description = "Enable Criterion benchmarks and CI baseline tooling" extra = ["Primarily used for local profiling and continuous benchmarking runs"] diff --git a/README.ko.md b/README.ko.md index 0fe7d7d..72f2008 100644 --- a/README.ko.md +++ b/README.ko.md @@ -25,6 +25,8 @@ SPDX-License-Identifier: MIT > 🇬🇧 [Read README in English](README.md) > 🇷🇺 [Читайте README на русском языке](README.ru.md) + **참고:** [masterror-cli](https://github.com/RAprogramm/masterror-cli) — Rust 컴파일러 오류를 상세한 해결책, 모범 사례 및 다국어 지원과 함께 설명하는 CLI 도구입니다. `cargo install masterror-cli` 또는 [AUR](https://aur.archlinux.org/packages/masterror-cli)에서 설치하세요. + > [!IMPORTANT] @@ -584,25 +586,60 @@ let error = AppError::not_found("사용자를 찾을 수 없음") println!("{}", error); ~~~ -**프로덕션 vs 개발 출력:** +**오류 출력:** -`colored` 기능 없이 오류는 `AppErrorKind` 레이블을 표시합니다: -~~~ -NotFound ~~~ - -`colored` 기능 사용 시 컨텍스트가 포함된 전체 여러 줄 형식: -~~~ -Error: NotFound +Not found Code: NOT_FOUND Message: 사용자를 찾을 수 없음 Context: user_id: 12345 request_id: abc-def + +Backtrace: + → divide at src/main.rs:16 + → main at src/main.rs:4 ~~~ -이러한 구분은 프로덕션 로그를 깔끔하게 유지하면서 로컬 디버깅 세션 중에 개발자에게 풍부한 컨텍스트를 제공합니다. +- `colored` — 터미널에서 구문 강조 +- `backtrace` — 자동 스택 추적 (사용자 코드만 필터링, 지원되는 터미널에서 클릭 가능한 링크) + +
+WezTerm: 클릭 가능한 backtrace 링크 + +`$EDITOR`에서 파일을 열려면 `~/.wezterm.lua`에 추가하세요: + +~~~lua +wezterm.on('open-uri', function(window, pane, uri) + if uri:find('^editor://') then + local path = uri:match('path=([^&]+)') + local line = uri:match('line=(%d+)') + local editor = os.getenv('EDITOR') or 'hx' + local args = { editor } + + if path then + if line and (editor:find('hx') or editor:find('helix')) then + table.insert(args, path .. ':' .. line) + elseif line and (editor:find('vim') or editor:find('nvim')) then + table.insert(args, '+' .. line) + table.insert(args, path) + else + table.insert(args, path) + end + + window:perform_action( + wezterm.action.SpawnCommandInNewTab { args = args }, + pane + ) + end + return false + end + return true +end) +~~~ + +
diff --git a/README.md b/README.md index bcafb01..fdb1193 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ SPDX-License-Identifier: MIT > 🇷🇺 [Читайте README на русском языке](README.ru.md) > 🇰🇷 [한국어 README](README.ko.md) + **See also:** [masterror-cli](https://github.com/RAprogramm/masterror-cli) — CLI tool that explains Rust compiler errors with detailed solutions, best practices, and multi-language support. Install via `cargo install masterror-cli` or from [AUR](https://aur.archlinux.org/packages/masterror-cli). + --- @@ -113,6 +115,7 @@ of redaction and metadata. | [`masterror`](https://crates.io/crates/masterror) | Core error types, metadata builders, transports, integrations and the prelude. | Application crates, services and libraries that want a stable error surface. | | [`masterror-derive`](masterror-derive/README.md) | Proc-macros backing `#[derive(Error)]`, `#[derive(Masterror)]`, `#[app_error]` and `#[provide]`. | Brought in automatically via `masterror`; depend directly only for macro hacking. | | [`masterror-template`](masterror-template/README.md) | Shared template parser used by the derive macros for formatter analysis. | Internal dependency; reuse when you need the template parser elsewhere. | +| [`masterror-knowledge`](masterror-knowledge/README.md) | Knowledge base with 31+ error explanations and 15 best practices in 3 languages. | Used by [masterror-cli](https://github.com/RAprogramm/masterror-cli); depend directly for custom tooling. |
@@ -135,6 +138,7 @@ Pick only what you need; everything is off by default. colored terminal output. - **Async & IO integrations:** `tokio`, `reqwest`, `sqlx`, `sqlx-migrate`, `redis`, `validator`, `config`. +- **Performance:** `phf` for O(1) compile-time perfect hash SQLSTATE lookups. - **Messaging & bots:** `teloxide`, `telegram-webapp-sdk`. - **Front-end tooling:** `frontend` for WASM/browser console logging. - **gRPC:** `tonic` to emit `tonic::Status` responses. @@ -159,15 +163,16 @@ The build script keeps the full feature snippet below in sync with ~~~toml [dependencies] -masterror = { version = "0.27.2", default-features = false } +masterror = { version = "0.28.0", default-features = false } # or with features: -# masterror = { version = "0.27.2", features = [ -# "std", "axum", "actix", "openapi", -# "serde_json", "tracing", "metrics", "backtrace", -# "colored", "sqlx", "sqlx-migrate", "reqwest", -# "redis", "validator", "config", "tokio", -# "multipart", "teloxide", "init-data", "tonic", -# "frontend", "turnkey", "benchmarks" +# masterror = { version = "0.28.0", features = [ +# "std", "derive", "axum", "actix", +# "openapi", "serde_json", "tracing", "metrics", +# "backtrace", "colored", "sqlx", "sqlx-migrate", +# "phf", "reqwest", "redis", "validator", +# "config", "tokio", "multipart", "teloxide", +# "init-data", "tonic", "frontend", "turnkey", +# "knowledge", "benchmarks" # ] } ~~~ @@ -640,7 +645,7 @@ Enable the `colored` feature for enhanced terminal output in local mode: ~~~toml [dependencies] -masterror = { version = "0.27.2", features = ["colored"] } +masterror = { version = "0.28.0", features = ["colored"] } ~~~ With `colored` enabled, errors display with syntax highlighting: @@ -656,31 +661,63 @@ let error = AppError::not_found("User not found") .with_field(field::str("user_id", "12345")) .with_field(field::str("request_id", "abc-def")); -// Without 'colored': plain text -// With 'colored': color-coded output in terminals println!("{}", error); ~~~ -**Production vs Development Output:** +**Error Output:** -Without `colored` feature, errors display their `AppErrorKind` label: -~~~ -NotFound ~~~ - -With `colored` feature, full multi-line format with context: -~~~ -Error: NotFound +Not found Code: NOT_FOUND Message: User not found Context: user_id: 12345 request_id: abc-def + +Backtrace: + → divide at src/main.rs:16 + → main at src/main.rs:4 ~~~ -This separation keeps production logs clean while giving developers rich context -during local debugging sessions. +- `colored` — syntax highlighting in terminal +- `backtrace` — automatic stack trace (filtered to your code only, clickable links in supported terminals) + +
+WezTerm: clickable backtrace links + +Add to `~/.wezterm.lua` to open files in your `$EDITOR`: + +~~~lua +wezterm.on('open-uri', function(window, pane, uri) + if uri:find('^editor://') then + local path = uri:match('path=([^&]+)') + local line = uri:match('line=(%d+)') + local editor = os.getenv('EDITOR') or 'hx' + local args = { editor } + + if path then + if line and (editor:find('hx') or editor:find('helix')) then + table.insert(args, path .. ':' .. line) + elseif line and (editor:find('vim') or editor:find('nvim')) then + table.insert(args, '+' .. line) + table.insert(args, path) + else + table.insert(args, path) + end + + window:perform_action( + wezterm.action.SpawnCommandInNewTab { args = args }, + pane + ) + end + return false + end + return true +end) +~~~ + +
diff --git a/README.ru.md b/README.ru.md index a1c46b9..be448d7 100644 --- a/README.ru.md +++ b/README.ru.md @@ -25,6 +25,8 @@ SPDX-License-Identifier: MIT > 🇬🇧 [Read README in English](README.md) > 🇰🇷 [한국어 README](README.ko.md) + **См. также:** [masterror-cli](https://github.com/RAprogramm/masterror-cli) — CLI-инструмент для объяснения ошибок компилятора Rust с подробными решениями, лучшими практиками и поддержкой нескольких языков. Установка: `cargo install masterror-cli` или из [AUR](https://aur.archlinux.org/packages/masterror-cli). +
> [!IMPORTANT] @@ -585,25 +587,60 @@ let error = AppError::not_found("Пользователь не найден") println!("{}", error); ~~~ -**Вывод в Production vs Development:** +**Вывод ошибок:** -Без функции `colored` ошибки отображают метку `AppErrorKind`: -~~~ -NotFound ~~~ - -С функцией `colored` полный многострочный формат с контекстом: -~~~ -Error: NotFound +Not found Code: NOT_FOUND Message: Пользователь не найден Context: user_id: 12345 request_id: abc-def + +Backtrace: + → divide at src/main.rs:16 + → main at src/main.rs:4 ~~~ -Такое разделение сохраняет production логи чистыми, предоставляя разработчикам богатый контекст во время локальных сессий отладки. +- `colored` — подсветка синтаксиса в терминале +- `backtrace` — автоматический стек вызовов (фильтруется до вашего кода, кликабельные ссылки в поддерживаемых терминалах) + +
+WezTerm: кликабельные ссылки в backtrace + +Добавьте в `~/.wezterm.lua` для открытия файлов в `$EDITOR`: + +~~~lua +wezterm.on('open-uri', function(window, pane, uri) + if uri:find('^editor://') then + local path = uri:match('path=([^&]+)') + local line = uri:match('line=(%d+)') + local editor = os.getenv('EDITOR') or 'hx' + local args = { editor } + + if path then + if line and (editor:find('hx') or editor:find('helix')) then + table.insert(args, path .. ':' .. line) + elseif line and (editor:find('vim') or editor:find('nvim')) then + table.insert(args, '+' .. line) + table.insert(args, path) + else + table.insert(args, path) + end + + window:perform_action( + wezterm.action.SpawnCommandInNewTab { args = args }, + pane + ) + end + return false + end + return true +end) +~~~ + +
diff --git a/README.template.md b/README.template.md index 381a842..e3ab140 100644 --- a/README.template.md +++ b/README.template.md @@ -26,6 +26,8 @@ SPDX-License-Identifier: MIT > 🇷🇺 [Читайте README на русском языке](README.ru.md) > 🇰🇷 [한국어 README](README.ko.md) + **See also:** [masterror-cli](https://github.com/RAprogramm/masterror-cli) — CLI tool that explains Rust compiler errors with detailed solutions, best practices, and multi-language support. Install via `cargo install masterror-cli` or from [AUR](https://aur.archlinux.org/packages/masterror-cli). + --- @@ -113,6 +115,7 @@ of redaction and metadata. | [`masterror`](https://crates.io/crates/masterror) | Core error types, metadata builders, transports, integrations and the prelude. | Application crates, services and libraries that want a stable error surface. | | [`masterror-derive`](masterror-derive/README.md) | Proc-macros backing `#[derive(Error)]`, `#[derive(Masterror)]`, `#[app_error]` and `#[provide]`. | Brought in automatically via `masterror`; depend directly only for macro hacking. | | [`masterror-template`](masterror-template/README.md) | Shared template parser used by the derive macros for formatter analysis. | Internal dependency; reuse when you need the template parser elsewhere. | +| [`masterror-knowledge`](masterror-knowledge/README.md) | Knowledge base with 31+ error explanations and 15 best practices in 3 languages. | Used by [masterror-cli](https://github.com/RAprogramm/masterror-cli); depend directly for custom tooling. |
@@ -135,6 +138,7 @@ Pick only what you need; everything is off by default. colored terminal output. - **Async & IO integrations:** `tokio`, `reqwest`, `sqlx`, `sqlx-migrate`, `redis`, `validator`, `config`. +- **Performance:** `phf` for O(1) compile-time perfect hash SQLSTATE lookups. - **Messaging & bots:** `teloxide`, `telegram-webapp-sdk`. - **Front-end tooling:** `frontend` for WASM/browser console logging. - **gRPC:** `tonic` to emit `tonic::Status` responses. @@ -651,31 +655,63 @@ let error = AppError::not_found("User not found") .with_field(field::str("user_id", "12345")) .with_field(field::str("request_id", "abc-def")); -// Without 'colored': plain text -// With 'colored': color-coded output in terminals println!("{}", error); ~~~ -**Production vs Development Output:** +**Error Output:** -Without `colored` feature, errors display their `AppErrorKind` label: -~~~ -NotFound ~~~ - -With `colored` feature, full multi-line format with context: -~~~ -Error: NotFound +Not found Code: NOT_FOUND Message: User not found Context: user_id: 12345 request_id: abc-def + +Backtrace: + → divide at src/main.rs:16 + → main at src/main.rs:4 ~~~ -This separation keeps production logs clean while giving developers rich context -during local debugging sessions. +- `colored` — syntax highlighting in terminal +- `backtrace` — automatic stack trace (filtered to your code only, clickable links in supported terminals) + +
+WezTerm: clickable backtrace links + +Add to `~/.wezterm.lua` to open files in your `$EDITOR`: + +~~~lua +wezterm.on('open-uri', function(window, pane, uri) + if uri:find('^editor://') then + local path = uri:match('path=([^&]+)') + local line = uri:match('line=(%d+)') + local editor = os.getenv('EDITOR') or 'hx' + local args = { editor } + + if path then + if line and (editor:find('hx') or editor:find('helix')) then + table.insert(args, path .. ':' .. line) + elseif line and (editor:find('vim') or editor:find('nvim')) then + table.insert(args, '+' .. line) + table.insert(args, path) + else + table.insert(args, path) + end + + window:perform_action( + wezterm.action.SpawnCommandInNewTab { args = args }, + pane + ) + end + return false + end + return true +end) +~~~ + +
diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 0000000..aa45311 --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2025-2026 RAprogramm +# +# SPDX-License-Identifier: MIT + +version = 1 + +[[annotations]] +path = ["**/Cargo.lock", "pkg/aur/.SRCINFO", "**/.cargo/config.toml"] +SPDX-FileCopyrightText = "2025-2026 RAprogramm " +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = ["masterror-knowledge/src/errors/**"] +SPDX-FileCopyrightText = "2025-2026 RAprogramm " +SPDX-License-Identifier = "MIT" diff --git a/images/masterror-knowledge.png b/images/masterror-knowledge.png new file mode 100644 index 0000000..31baba7 Binary files /dev/null and b/images/masterror-knowledge.png differ diff --git a/images/masterror-knowledge.png.license b/images/masterror-knowledge.png.license new file mode 100644 index 0000000..c6d90e7 --- /dev/null +++ b/images/masterror-knowledge.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2025-2026 RAprogramm + +SPDX-License-Identifier: MIT diff --git a/masterror-cli/Cargo.toml b/masterror-cli/Cargo.toml new file mode 100644 index 0000000..9b0b998 --- /dev/null +++ b/masterror-cli/Cargo.toml @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2025-2026 RAprogramm +# +# SPDX-License-Identifier: MIT + +[package] +name = "masterror-cli" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +description = "CLI tool for explaining Rust compiler errors in human-friendly language" +keywords = ["rust", "compiler", "errors", "explain", "cli"] +categories = ["command-line-utilities", "development-tools"] + +[[bin]] +name = "masterror" +path = "src/main.rs" + +[[bin]] +name = "cargo-masterror" +path = "src/main.rs" + +[features] +default = ["show-why", "show-fix", "show-link", "show-translation"] + +# Display sections +show-why = [] +show-fix = [] +show-link = [] +show-translation = [] + +# Show original compiler output before masterror block +show-original = [] + +[dependencies] +masterror-knowledge = { version = "0.1", path = "../masterror-knowledge" } + +# CLI framework +clap = { version = "4", features = ["derive", "env", "wrap_help"] } + +# Colored output +owo-colors = { version = "4", features = ["supports-colors"] } + +# Serialization +serde = { version = "1", features = ["derive"] } +serde_json = "1" +toml = "0.9" + +# Config paths +dirs = "6" + +[dev-dependencies] +assert_cmd = "2" +predicates = "3" diff --git a/masterror-cli/src/commands.rs b/masterror-cli/src/commands.rs new file mode 100644 index 0000000..7f2c260 --- /dev/null +++ b/masterror-cli/src/commands.rs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! CLI commands. + +mod check; +mod explain; +pub mod init; +mod list; +pub mod practice; + +pub use check::run as check; +pub use explain::run as explain; +pub use init::run as init; +pub use list::run as list; diff --git a/masterror-cli/src/commands/check.rs b/masterror-cli/src/commands/check.rs new file mode 100644 index 0000000..d84bbb3 --- /dev/null +++ b/masterror-cli/src/commands/check.rs @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Check command - run cargo check and explain errors. + +use std::{ + io::{BufRead, BufReader}, + process::{Command, Stdio} +}; + +use masterror_knowledge::Lang; + +use crate::{ + error::{AppError, Result}, + options::DisplayOptions, + output, + parser::CargoMessage +}; + +/// Allowed cargo arguments whitelist. +const ALLOWED_ARGS: &[&str] = &[ + "--release", + "--all-targets", + "--all-features", + "--no-default-features", + "-p", + "--package", + "--workspace", + "--lib", + "--bins", + "--bin", + "--examples", + "--example", + "--tests", + "--test", + "--benches", + "--bench", + "--features", + "-F", + "--target", + "--profile", + "-j", + "--jobs", + "-v", + "--verbose", + "-q", + "--quiet", + "--locked", + "--frozen", + "--offline" +]; + +/// Validate cargo arguments against whitelist. +fn validate_args(args: &[String]) -> Result<()> { + for arg in args { + if arg.starts_with('-') { + let is_allowed = ALLOWED_ARGS + .iter() + .any(|allowed| arg == *allowed || arg.starts_with(&format!("{allowed}="))); + if !is_allowed { + return Err(AppError::InvalidArgument { + arg: arg.clone() + }); + } + } + } + Ok(()) +} + +/// Run cargo check and explain errors. +pub fn run(lang: Lang, args: &[String], opts: &DisplayOptions) -> Result<()> { + validate_args(args)?; + + let msg_format = if opts.colored { + "--message-format=json-diagnostic-rendered-ansi" + } else { + "--message-format=json" + }; + + let mut cmd = Command::new("cargo") + .arg("check") + .arg(msg_format) + .args(args) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn()?; + + let stdout = cmd + .stdout + .take() + .ok_or_else(|| AppError::Io(std::io::Error::other("failed to capture stdout")))?; + let reader = BufReader::new(stdout); + + let mut error_count = 0; + + for line in reader.lines() { + let line = line?; + if let Ok(msg) = serde_json::from_str::(&line) + && msg.is_error() + { + error_count += 1; + output::print_error(lang, &msg, opts); + println!(); + } + } + + let status = cmd.wait()?; + + if error_count > 0 { + println!("Found {error_count} error(s). Run `masterror explain ` for details."); + } + + if !status.success() { + match status.code() { + Some(code) => { + return Err(AppError::CargoFailed { + code + }); + } + None => return Err(AppError::CargoSignaled) + } + } + + Ok(()) +} diff --git a/masterror-cli/src/commands/explain.rs b/masterror-cli/src/commands/explain.rs new file mode 100644 index 0000000..0a6dcf7 --- /dev/null +++ b/masterror-cli/src/commands/explain.rs @@ -0,0 +1,174 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Explain command - explain a specific error code or best practice. + +use masterror_knowledge::{ + BestPractice, ErrorEntry, ErrorRegistry, Lang, PracticeRegistry, UiMsg +}; +use owo_colors::OwoColorize; + +use crate::{ + error::{AppError, Result}, + options::DisplayOptions +}; + +/// Explain a specific error code (E0382) or best practice (RA001). +pub fn run(lang: Lang, code: &str, opts: &DisplayOptions) -> Result<()> { + let upper = code.to_uppercase(); + + if upper.starts_with("RA") { + let registry = PracticeRegistry::new(); + if let Some(practice) = registry.find(&upper) { + print_practice(lang, practice, opts); + return Ok(()); + } + } + + let registry = ErrorRegistry::new(); + if let Some(entry) = registry.find(code) { + print_error(lang, entry, opts); + return Ok(()); + } + + Err(AppError::UnknownErrorCode { + code: code.to_string() + }) +} + +fn print_error(lang: Lang, entry: &ErrorEntry, opts: &DisplayOptions) { + println!(); + + let title = entry.title.get(lang.code()); + if opts.colored { + println!("{} - {}", entry.code.yellow().bold(), title.bold()); + } else { + println!("{} - {title}", entry.code); + } + + let category = entry.category.name(lang.code()); + if opts.colored { + println!("{}: {}", UiMsg::Category.get(lang), category.dimmed()); + } else { + println!("{}: {category}", UiMsg::Category.get(lang)); + } + + println!(); + let why_label = UiMsg::LabelWhy.get(lang); + if opts.colored { + println!("{}", why_label.green().bold()); + } else { + println!("{why_label}"); + } + println!("{}", entry.explanation.get(lang.code())); + + if !entry.fixes.is_empty() { + println!(); + let fix_label = UiMsg::LabelFix.get(lang); + if opts.colored { + println!("{}", fix_label.green().bold()); + } else { + println!("{fix_label}"); + } + for (i, fix) in entry.fixes.iter().enumerate() { + println!(); + println!("{}. {}", i + 1, fix.description.get(lang.code())); + println!("```rust"); + println!("{}", fix.code); + println!("```"); + } + } + + if !entry.links.is_empty() { + println!(); + let link_label = UiMsg::LabelLink.get(lang); + if opts.colored { + println!("{}", link_label.cyan().bold()); + } else { + println!("{link_label}"); + } + for link in entry.links { + if opts.colored { + println!(" - {} {}", link.title, link.url.dimmed()); + } else { + println!(" - {} {}", link.title, link.url); + } + } + } + + println!(); +} + +/// Print best practice details. +pub fn print_practice(lang: Lang, practice: &BestPractice, opts: &DisplayOptions) { + println!(); + + let title = practice.title.get(lang.code()); + if opts.colored { + println!("{} - {}", practice.code.yellow().bold(), title.bold()); + } else { + println!("{} - {title}", practice.code); + } + + let category = practice.category.name(lang.code()); + if opts.colored { + println!("{}: {}", UiMsg::Category.get(lang), category.dimmed()); + } else { + println!("{}: {category}", UiMsg::Category.get(lang)); + } + + println!(); + let why_label = UiMsg::LabelWhyMatters.get(lang); + if opts.colored { + println!("{}", why_label.green().bold()); + } else { + println!("{why_label}"); + } + println!("{}", practice.explanation.get(lang.code())); + + println!(); + let how_label = UiMsg::LabelHowToApply.get(lang); + if opts.colored { + println!("{}", how_label.green().bold()); + } else { + println!("{how_label}"); + } + + println!(); + let avoid_label = UiMsg::LabelAvoid.get(lang); + if opts.colored { + println!("{}. {}", "1".cyan(), avoid_label.red()); + } else { + println!("1. {avoid_label}"); + } + println!("```rust"); + println!("{}", practice.bad_example); + println!("```"); + + println!(); + let prefer_label = UiMsg::LabelPrefer.get(lang); + if opts.colored { + println!("{}. {}", "2".cyan(), prefer_label.green()); + } else { + println!("2. {prefer_label}"); + } + println!("```rust"); + println!("{}", practice.good_example); + println!("```"); + + println!(); + let link_label = UiMsg::LabelLink.get(lang); + if opts.colored { + println!("{}", link_label.cyan().bold()); + } else { + println!("{link_label}"); + } + if opts.colored { + println!(" - RustManifest {}", practice.source.dimmed()); + } else { + println!(" - RustManifest {}", practice.source); + } + + println!(); +} diff --git a/masterror-cli/src/commands/init.rs b/masterror-cli/src/commands/init.rs new file mode 100644 index 0000000..59d9d0e --- /dev/null +++ b/masterror-cli/src/commands/init.rs @@ -0,0 +1,295 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Init command - create configuration file interactively. + +use std::io::{self, Write}; + +use masterror_knowledge::{Lang, UiMsg}; +use owo_colors::OwoColorize; + +use crate::{ + config::{Config, DisplayConfig, GeneralConfig}, + error::Result +}; + +/// Run init command - create configuration interactively. +pub fn run(_lang: Lang, colored: bool) -> Result<()> { + println!(); + print_welcome(colored); + println!(); + + // First ask language - this affects all subsequent prompts + let lang_value = prompt_language(colored)?; + let lang = masterror_knowledge::Lang::from_code(&lang_value); + + let color_value = prompt_colors(lang, colored)?; + let display = prompt_display(lang, colored)?; + let save_location = prompt_save_location(lang, colored)?; + + let config = Config { + general: GeneralConfig { + lang: lang_value, + colored: color_value + }, + display, + aliases: default_aliases() + }; + + let saved_path = match save_location { + SaveLocation::Global => { + config.save()?; + Config::path() + .map(|p| p.display().to_string()) + .unwrap_or_else(|| "~/.config/masterror/config.toml".to_string()) + } + SaveLocation::Local => { + let path = config.save_local()?; + path.display().to_string() + } + }; + + println!(); + print_success(lang, colored, &saved_path); + print_tips(lang, colored, &save_location); + + Ok(()) +} + +/// Check if first run and prompt for setup. +pub fn check_first_run(colored: bool) -> Result { + if !Config::is_first_run() { + return Ok(false); + } + + println!(); + if colored { + println!( + "{}", + "Welcome to masterror! Let's set up your preferences.".cyan() + ); + println!( + "{}", + "(This only happens once. Run `masterror init` to reconfigure later.)".dimmed() + ); + } else { + println!("Welcome to masterror! Let's set up your preferences."); + println!("(This only happens once. Run `masterror init` to reconfigure later.)"); + } + println!(); + + run(Lang::En, colored)?; + Ok(true) +} + +#[derive(Clone, Copy)] +enum SaveLocation { + Global, + Local +} + +fn print_welcome(colored: bool) { + let title = "masterror - Rust compiler error explainer"; + let subtitle = "Let's configure your preferences"; + + if colored { + println!("{}", title.bold().cyan()); + println!("{}", subtitle.dimmed()); + } else { + println!("{title}"); + println!("{subtitle}"); + } +} + +fn prompt_language(colored: bool) -> Result { + println!(); + if colored { + println!( + "{}", + "Select your language / Выберите язык / 언어 선택".bold() + ); + println!(" {} - English", "en".cyan()); + println!(" {} - Русский", "ru".cyan()); + println!(" {} - 한국어", "ko".cyan()); + } else { + println!("Select your language / Выберите язык / 언어 선택"); + println!(" en - English"); + println!(" ru - Русский"); + println!(" ko - 한국어"); + } + + if colored { + print!("{} [en/ru/ko] ({}): ", "Choice".bold(), "en".dimmed()); + } else { + print!("Choice [en/ru/ko] (en): "); + } + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + let choice = input.trim().to_lowercase(); + + Ok( + if choice.is_empty() || !["en", "ru", "ko"].contains(&choice.as_str()) { + "en".to_string() + } else { + choice + } + ) +} + +fn prompt_colors(lang: Lang, colored: bool) -> Result { + let prompt = UiMsg::InitColorPrompt.get(lang); + + if colored { + print!("{} [y/n] ({}): ", prompt.bold(), "y".dimmed()); + } else { + print!("{prompt} [y/n] (y): "); + } + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + Ok(!matches!(input.trim().to_lowercase().as_str(), "n" | "no")) +} + +fn prompt_display(lang: Lang, colored: bool) -> Result { + let prompt = UiMsg::InitDisplayPrompt.get(lang); + println!(); + if colored { + println!("{}", prompt.bold()); + } else { + println!("{prompt}"); + } + + let translation = prompt_bool(lang, colored, UiMsg::InitShowTranslation, true)?; + let why = prompt_bool(lang, colored, UiMsg::InitShowWhy, true)?; + let fix = prompt_bool(lang, colored, UiMsg::InitShowFix, true)?; + let links = prompt_bool(lang, colored, UiMsg::InitShowLinks, true)?; + let original = prompt_bool(lang, colored, UiMsg::InitShowOriginal, false)?; + + Ok(DisplayConfig { + translation, + why, + fix, + links, + original + }) +} + +fn prompt_save_location(lang: Lang, colored: bool) -> Result { + println!(); + let global_label = UiMsg::InitSaveGlobal.get(lang); + let local_label = UiMsg::InitSaveLocal.get(lang); + + if colored { + println!("{}", UiMsg::InitSavePrompt.get(lang).bold()); + println!(" {} - {}", "1".cyan(), global_label); + println!(" {} - {}", "2".cyan(), local_label); + } else { + println!("{}", UiMsg::InitSavePrompt.get(lang)); + println!(" 1 - {global_label}"); + println!(" 2 - {local_label}"); + } + + if colored { + print!("{} [1/2] ({}): ", "Choice".bold(), "1".dimmed()); + } else { + print!("Choice [1/2] (1): "); + } + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + + Ok(match input.trim() { + "2" => SaveLocation::Local, + _ => SaveLocation::Global + }) +} + +fn prompt_bool(lang: Lang, colored: bool, msg: UiMsg, default: bool) -> Result { + let label = msg.get(lang); + let default_str = if default { "y" } else { "n" }; + + if colored { + print!(" {} [y/n] ({}): ", label, default_str.dimmed()); + } else { + print!(" {label} [y/n] ({default_str}): "); + } + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + let trimmed = input.trim().to_lowercase(); + + Ok(if trimmed.is_empty() { + default + } else { + matches!(trimmed.as_str(), "y" | "yes" | "д" | "да") + }) +} + +fn print_success(lang: Lang, colored: bool, path: &str) { + let msg = UiMsg::InitSuccess.get(lang); + + if colored { + println!("{} {}", msg.green(), path.dimmed()); + } else { + println!("{msg} {path}"); + } +} + +fn print_tips(lang: Lang, colored: bool, location: &SaveLocation) { + println!(); + let tip = UiMsg::InitTip.get(lang); + + if colored { + println!("{}", tip.dimmed()); + } else { + println!("{tip}"); + } + + match location { + SaveLocation::Global => { + let global_path = Config::path() + .map(|p| p.display().to_string()) + .unwrap_or_else(|| "~/.config/masterror/config.toml".to_string()); + if colored { + println!(" {} {}", "Global:".dimmed(), global_path.dimmed()); + } else { + println!(" Global: {global_path}"); + } + } + SaveLocation::Local => { + if colored { + println!(" {} .masterror.toml", "Local:".dimmed()); + } else { + println!(" Local: .masterror.toml"); + } + } + } + + println!(); + let usage = UiMsg::InitUsage.get(lang); + if colored { + println!("{}", usage.cyan()); + println!(" {} cargo masterror check", "$".dimmed()); + println!(" {} masterror explain E0382", "$".dimmed()); + } else { + println!("{usage}"); + println!(" $ cargo masterror check"); + println!(" $ masterror explain E0382"); + } + println!(); +} + +fn default_aliases() -> std::collections::HashMap { + let mut aliases = std::collections::HashMap::new(); + aliases.insert("c".to_string(), "check".to_string()); + aliases.insert("e".to_string(), "explain".to_string()); + aliases.insert("l".to_string(), "list".to_string()); + aliases.insert("p".to_string(), "practice".to_string()); + aliases +} diff --git a/masterror-cli/src/commands/list.rs b/masterror-cli/src/commands/list.rs new file mode 100644 index 0000000..3d67f53 --- /dev/null +++ b/masterror-cli/src/commands/list.rs @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! List command - list all known error codes. + +use masterror_knowledge::{Category, ErrorRegistry, Lang}; + +use crate::{ + error::{AppError, Result}, + options::DisplayOptions, + output::{print_category_header, print_code_title, print_title} +}; + +/// List all known error codes. +pub fn run(lang: Lang, category: Option<&str>, opts: &DisplayOptions) -> Result<()> { + let registry = ErrorRegistry::new(); + + println!(); + print_title("Known Rust Compiler Errors", opts.colored); + println!(); + + let mut entries: Vec<_> = if let Some(cat) = category { + let cat = parse_category(cat); + if let Some(c) = cat { + registry.by_category(c) + } else { + return Err(AppError::InvalidCategory { + name: category.unwrap_or("").to_string() + }); + } + } else { + registry.all().collect() + }; + + if entries.is_empty() { + println!(" No errors found."); + return Ok(()); + } + + entries.sort_by_key(|e| e.code); + + let mut current_cat: Option = None; + for entry in &entries { + if current_cat != Some(entry.category) { + current_cat = Some(entry.category); + println!(); + print_category_header(entry.category.name(lang.code()), opts.colored); + println!(); + } + print_code_title(entry.code, entry.title.get(lang.code()), opts.colored); + } + + println!(); + println!("Total: {} errors", entries.len()); + println!(); + println!("Use `masterror explain ` to see details."); + println!("Use `masterror practice` to see best practices."); + println!(); + + Ok(()) +} + +fn parse_category(s: &str) -> Option { + match s.to_lowercase().as_str() { + "ownership" | "own" => Some(Category::Ownership), + "borrowing" | "borrow" => Some(Category::Borrowing), + "lifetimes" | "lifetime" | "life" => Some(Category::Lifetimes), + "types" | "type" => Some(Category::Types), + "traits" | "trait" => Some(Category::Traits), + "resolution" | "resolve" | "names" => Some(Category::Resolution), + _ => None + } +} diff --git a/masterror-cli/src/commands/practice.rs b/masterror-cli/src/commands/practice.rs new file mode 100644 index 0000000..b651b04 --- /dev/null +++ b/masterror-cli/src/commands/practice.rs @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Practice command - show best practices from RustManifest. + +use masterror_knowledge::{Lang, PracticeCategory, PracticeRegistry}; + +use super::explain::print_practice; +use crate::{ + error::{AppError, Result}, + options::DisplayOptions, + output::{print_category_header, print_code_title, print_title} +}; + +/// List all best practices or filter by category. +pub fn list(lang: Lang, category: Option<&str>, opts: &DisplayOptions) -> Result<()> { + let registry = PracticeRegistry::new(); + + println!(); + print_title("RustManifest Best Practices", opts.colored); + println!(); + + let practices: Vec<_> = if let Some(cat) = category { + let cat = parse_category(cat); + if let Some(c) = cat { + registry.by_category(c) + } else { + return Err(AppError::InvalidCategory { + name: category.unwrap_or("").to_string() + }); + } + } else { + registry.all().collect() + }; + + if practices.is_empty() { + println!(" No practices found."); + return Ok(()); + } + + let mut sorted = practices; + sorted.sort_by_key(|p| p.code); + + let mut current_cat: Option = None; + for practice in &sorted { + if current_cat != Some(practice.category) { + current_cat = Some(practice.category); + println!(); + print_category_header(practice.category.name(lang.code()), opts.colored); + println!(); + } + print_code_title(practice.code, practice.title.get(lang.code()), opts.colored); + } + + println!(); + println!("Total: {} practices", sorted.len()); + println!(); + println!("Use `masterror practice ` to see details."); + println!(); + + Ok(()) +} + +/// Show a specific best practice. +pub fn show(lang: Lang, code: &str, opts: &DisplayOptions) -> Result<()> { + let registry = PracticeRegistry::new(); + + let Some(practice) = registry.find(code) else { + return Err(AppError::UnknownPracticeCode { + code: code.to_string() + }); + }; + + print_practice(lang, practice, opts); + Ok(()) +} + +fn parse_category(s: &str) -> Option { + match s.to_lowercase().as_str() { + "error-handling" | "error_handling" | "errorhandling" | "errors" => { + Some(PracticeCategory::ErrorHandling) + } + "performance" | "perf" => Some(PracticeCategory::Performance), + "naming" | "names" => Some(PracticeCategory::Naming), + "documentation" | "docs" | "doc" => Some(PracticeCategory::Documentation), + "design" | "architecture" | "arch" => Some(PracticeCategory::Design), + "testing" | "tests" | "test" => Some(PracticeCategory::Testing), + "security" | "sec" => Some(PracticeCategory::Security), + _ => None + } +} diff --git a/masterror-cli/src/config.rs b/masterror-cli/src/config.rs new file mode 100644 index 0000000..b9b0cb0 --- /dev/null +++ b/masterror-cli/src/config.rs @@ -0,0 +1,203 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Configuration management for masterror-cli. +//! +//! Supports layered configuration (highest priority first): +//! 1. CLI arguments +//! 2. Environment variables +//! 3. Local project config (.masterror.toml in current directory) +//! 4. Global config (~/.config/masterror/config.toml) +//! 5. Default values + +use std::{collections::HashMap, env, fs, path::PathBuf}; + +use serde::{Deserialize, Serialize}; + +use crate::error::{AppError, Result}; + +/// Global config file name. +const CONFIG_FILE: &str = "config.toml"; + +/// Local project config file name. +const LOCAL_CONFIG_FILE: &str = ".masterror.toml"; + +/// Config directory name. +const CONFIG_DIR: &str = "masterror"; + +/// Application configuration. +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(default)] +pub struct Config { + /// General settings. + pub general: GeneralConfig, + /// Display settings. + pub display: DisplayConfig, + /// Command aliases. + pub aliases: HashMap +} + +/// General configuration options. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(default)] +pub struct GeneralConfig { + /// Language code (en, ru, ko). + pub lang: String, + /// Enable colored output. + pub colored: bool +} + +/// Display section toggles. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(default)] +pub struct DisplayConfig { + /// Show translated error message. + pub translation: bool, + /// Show "why this happens" explanation. + pub why: bool, + /// Show fix suggestions. + pub fix: bool, + /// Show documentation links. + pub links: bool, + /// Show original compiler output. + pub original: bool +} + +impl Default for GeneralConfig { + fn default() -> Self { + Self { + lang: "en".to_string(), + colored: true + } + } +} + +impl Default for DisplayConfig { + fn default() -> Self { + Self { + translation: true, + why: true, + fix: true, + links: true, + original: false + } + } +} + +impl Config { + /// Get global config directory path. + pub fn dir() -> Option { + dirs::config_dir().map(|p| p.join(CONFIG_DIR)) + } + + /// Get global config file path. + pub fn path() -> Option { + Self::dir().map(|p| p.join(CONFIG_FILE)) + } + + /// Get local project config path (.masterror.toml in current directory). + pub fn local_path() -> Option { + env::current_dir().ok().map(|p| p.join(LOCAL_CONFIG_FILE)) + } + + /// Check if this is the first run (no global config exists). + pub fn is_first_run() -> bool { + Self::path().is_none_or(|p| !p.exists()) + } + + /// Load config with layered priority: + /// 1. Local .masterror.toml (if exists) + /// 2. Global ~/.config/masterror/config.toml + /// 3. Defaults + pub fn load() -> Result { + // Try local config first + if let Some(local_path) = Self::local_path() + && local_path.exists() + { + let content = fs::read_to_string(&local_path)?; + let config: Config = toml::from_str(&content).map_err(|e| AppError::ConfigParse { + path: local_path.clone(), + message: e.message().to_string() + })?; + return Ok(config); + } + + // Try global config + let Some(path) = Self::path() else { + return Ok(Self::default()); + }; + + if !path.exists() { + return Ok(Self::default()); + } + + let content = fs::read_to_string(&path)?; + let config: Config = toml::from_str(&content).map_err(|e| AppError::ConfigParse { + path: path.clone(), + message: e.message().to_string() + })?; + + Ok(config) + } + + /// Save config to global file. + pub fn save(&self) -> Result<()> { + let Some(dir) = Self::dir() else { + return Err(AppError::Io(std::io::Error::other( + "could not determine config directory" + ))); + }; + + fs::create_dir_all(&dir)?; + + let path = dir.join(CONFIG_FILE); + let content = toml::to_string_pretty(self).map_err(|e| AppError::ConfigParse { + path: path.clone(), + message: e.to_string() + })?; + + fs::write(&path, content)?; + Ok(()) + } + + /// Save config to local project file (.masterror.toml). + pub fn save_local(&self) -> Result { + let path = env::current_dir()?.join(LOCAL_CONFIG_FILE); + let content = toml::to_string_pretty(self).map_err(|e| AppError::ConfigParse { + path: path.clone(), + message: e.to_string() + })?; + + fs::write(&path, &content)?; + Ok(path) + } + + /// Resolve command alias. + #[allow(dead_code)] + pub fn resolve_alias<'a>(&'a self, cmd: &'a str) -> &'a str { + self.aliases.get(cmd).map(String::as_str).unwrap_or(cmd) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_default_config() { + let config = Config::default(); + assert_eq!(config.general.lang, "en"); + assert!(config.general.colored); + assert!(config.display.why); + assert!(config.display.fix); + } + + #[test] + fn test_toml_roundtrip() { + let config = Config::default(); + let toml = toml::to_string_pretty(&config).unwrap(); + let parsed: Config = toml::from_str(&toml).unwrap(); + assert_eq!(parsed.general.lang, config.general.lang); + } +} diff --git a/masterror-cli/src/error.rs b/masterror-cli/src/error.rs new file mode 100644 index 0000000..bfeb345 --- /dev/null +++ b/masterror-cli/src/error.rs @@ -0,0 +1,169 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Application error types for masterror-cli. + +use std::{fmt, io, path::PathBuf}; + +/// Application-wide error type. +#[derive(Debug)] +pub enum AppError { + /// I/O error (file operations, process spawning). + Io(io::Error), + /// JSON parsing error from cargo output. + Json(serde_json::Error), + /// Cargo check process failed with exit code. + CargoFailed { + /// Exit code from cargo process. + code: i32 + }, + /// Cargo check process was terminated by signal. + CargoSignaled, + /// Unknown error code requested. + UnknownErrorCode { + /// The requested error code. + code: String + }, + /// Unknown practice code requested. + UnknownPracticeCode { + /// The requested practice code. + code: String + }, + /// Invalid category name. + InvalidCategory { + /// The invalid category name. + name: String + }, + /// Invalid command-line argument. + InvalidArgument { + /// The invalid argument. + arg: String + }, + /// Config file parse error. + ConfigParse { + /// Path to config file. + path: PathBuf, + /// Error message. + message: String + }, + /// Error with additional context. + #[allow(dead_code)] + WithContext { + /// Context message. + context: String, + /// Original error. + source: Box + } +} + +impl fmt::Display for AppError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Io(e) => write!(f, "I/O error: {e}"), + Self::Json(e) => write!(f, "JSON parse error: {e}"), + Self::CargoFailed { + code + } => write!(f, "cargo check failed with exit code {code}"), + Self::CargoSignaled => write!(f, "cargo check was terminated by signal"), + Self::UnknownErrorCode { + code + } => write!(f, "unknown error code: {code}"), + Self::UnknownPracticeCode { + code + } => write!(f, "unknown practice code: {code}"), + Self::InvalidCategory { + name + } => write!(f, "invalid category: {name}"), + Self::InvalidArgument { + arg + } => write!(f, "invalid argument: {arg}"), + Self::ConfigParse { + path, + message + } => write!(f, "config error in {}: {message}", path.display()), + Self::WithContext { + context, + source + } => write!(f, "{context}: {source}") + } + } +} + +impl std::error::Error for AppError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Io(e) => Some(e), + Self::Json(e) => Some(e), + Self::WithContext { + source, .. + } => Some(source.as_ref()), + _ => None + } + } +} + +impl From for AppError { + fn from(err: io::Error) -> Self { + Self::Io(err) + } +} + +impl From for AppError { + fn from(err: serde_json::Error) -> Self { + Self::Json(err) + } +} + +/// Result type alias for AppError. +pub type Result = std::result::Result; + +/// Extension trait for adding context to Results. +/// +/// # Example +/// +/// ```ignore +/// use masterror::error::ResultExt; +/// +/// fs::read_to_string(path).context("reading config")?; +/// ``` +#[allow(dead_code)] +pub trait ResultExt { + /// Add static context to an error. + fn context(self, ctx: &'static str) -> Result; + + /// Add dynamic context to an error. + fn with_context(self, f: F) -> Result + where + F: FnOnce() -> S, + S: Into; +} + +impl ResultExt for std::result::Result +where + E: Into +{ + fn context(self, ctx: &'static str) -> Result { + self.map_err(|e| { + let inner = e.into(); + AppError::WithContext { + context: ctx.to_string(), + source: Box::new(inner) + } + }) + } + + fn with_context(self, f: F) -> Result + where + F: FnOnce() -> S, + S: Into + { + self.map_err(|e| { + let inner = e.into(); + AppError::WithContext { + context: f().into(), + source: Box::new(inner) + } + }) + } +} diff --git a/masterror-cli/src/main.rs b/masterror-cli/src/main.rs new file mode 100644 index 0000000..47b006a --- /dev/null +++ b/masterror-cli/src/main.rs @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! masterror CLI - Rust compiler error explainer. + +mod commands; +mod config; +mod error; +mod options; +mod output; +mod parser; +mod sections; + +use clap::{Parser, Subcommand}; +use masterror_knowledge::Lang; + +use crate::{config::Config, options::DisplayOptions}; + +#[derive(Parser)] +#[command(name = "masterror")] +#[command(author, version, about = "Rust compiler error explainer")] +struct Cli { + /// Language for explanations (en, ru, ko) + #[arg(short, long, env = "MASTERROR_LANG")] + lang: Option, + + /// Disable colored output + #[arg(long, env = "NO_COLOR")] + no_color: bool, + + #[command(subcommand)] + command: Commands +} + +#[derive(Subcommand)] +enum Commands { + /// Initialize configuration file + Init, + /// Run cargo check and explain errors + #[command(visible_alias = "c")] + Check { + #[arg(trailing_var_arg = true)] + args: Vec + }, + /// Explain a specific error code (E0382) or best practice (RA001) + #[command(visible_alias = "e")] + Explain { code: String }, + /// List all known error codes + #[command(visible_alias = "l")] + List { + #[arg(short, long)] + category: Option + }, + /// Show RustManifest best practices + #[command(visible_alias = "p")] + Practice { + /// Practice code (RA001-RA015) or empty for list + code: Option, + /// Filter by category + #[arg(short, long)] + category: Option + } +} + +fn main() { + let args: Vec = std::env::args().collect(); + let cli = if args.get(1).is_some_and(|a| a == "masterror") { + Cli::parse_from( + args.into_iter() + .enumerate() + .filter_map(|(i, a)| if i == 1 { None } else { Some(a) }) + ) + } else { + Cli::parse() + }; + + // Check for first run and run setup if needed (except for init command) + if !matches!(cli.command, Commands::Init) + && let Err(e) = commands::init::check_first_run(true) + { + eprintln!("Setup failed: {e}"); + std::process::exit(1); + } + + let config = Config::load().unwrap_or_default(); + let lang_str = cli.lang.as_deref().unwrap_or(&config.general.lang); + let lang = Lang::from_code(lang_str); + let colored = if cli.no_color { + false + } else { + config.general.colored + }; + + let opts = DisplayOptions { + colored, + show_translation: config.display.translation, + show_why: config.display.why, + show_fix: config.display.fix, + show_links: config.display.links, + show_original: config.display.original + }; + + let result = match &cli.command { + Commands::Init => commands::init(lang, opts.colored), + Commands::Check { + args + } => commands::check(lang, args, &opts), + Commands::Explain { + code + } => commands::explain(lang, code, &opts), + Commands::List { + category + } => commands::list(lang, category.as_deref(), &opts), + Commands::Practice { + code, + category + } => { + if let Some(c) = code { + commands::practice::show(lang, c, &opts) + } else { + commands::practice::list(lang, category.as_deref(), &opts) + } + } + }; + + if let Err(e) = result { + eprintln!("Error: {e}"); + std::process::exit(1); + } +} diff --git a/masterror-cli/src/options.rs b/masterror-cli/src/options.rs new file mode 100644 index 0000000..8256a87 --- /dev/null +++ b/masterror-cli/src/options.rs @@ -0,0 +1,138 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Display options for masterror output. + +/// What sections to show in masterror block. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct DisplayOptions { + /// Enable colored output. + pub colored: bool, + /// Show translated error message. + pub show_translation: bool, + /// Show "why this happens" explanation. + pub show_why: bool, + /// Show fix suggestions. + pub show_fix: bool, + /// Show documentation links. + pub show_links: bool, + /// Show original compiler output. + pub show_original: bool +} + +impl DisplayOptions { + /// Default options as const value. + pub const DEFAULT: Self = Self { + colored: true, + show_translation: true, + show_why: true, + show_fix: true, + show_links: true, + show_original: false + }; + + /// Create new builder for constructing DisplayOptions. + #[allow(dead_code)] + pub const fn builder() -> DisplayOptionsBuilder { + DisplayOptionsBuilder::new() + } +} + +impl Default for DisplayOptions { + fn default() -> Self { + Self::DEFAULT + } +} + +/// Builder for constructing DisplayOptions with const support. +/// +/// # Example +/// +/// ```ignore +/// use masterror_cli::options::DisplayOptions; +/// +/// const OPTS: DisplayOptions = DisplayOptions::builder() +/// .colored(false) +/// .show_original(true) +/// .build(); +/// ``` +#[derive(Clone, Copy, Debug)] +#[allow(dead_code)] +pub struct DisplayOptionsBuilder { + colored: bool, + show_translation: bool, + show_why: bool, + show_fix: bool, + show_links: bool, + show_original: bool +} + +#[allow(dead_code)] +impl DisplayOptionsBuilder { + /// Create new builder with default values. + pub const fn new() -> Self { + Self { + colored: true, + show_translation: true, + show_why: true, + show_fix: true, + show_links: true, + show_original: false + } + } + + /// Set colored output. + pub const fn colored(mut self, value: bool) -> Self { + self.colored = value; + self + } + + /// Set show translation. + pub const fn show_translation(mut self, value: bool) -> Self { + self.show_translation = value; + self + } + + /// Set show why explanation. + pub const fn show_why(mut self, value: bool) -> Self { + self.show_why = value; + self + } + + /// Set show fix suggestions. + pub const fn show_fix(mut self, value: bool) -> Self { + self.show_fix = value; + self + } + + /// Set show documentation links. + pub const fn show_links(mut self, value: bool) -> Self { + self.show_links = value; + self + } + + /// Set show original compiler output. + pub const fn show_original(mut self, value: bool) -> Self { + self.show_original = value; + self + } + + /// Build the DisplayOptions. + pub const fn build(self) -> DisplayOptions { + DisplayOptions { + colored: self.colored, + show_translation: self.show_translation, + show_why: self.show_why, + show_fix: self.show_fix, + show_links: self.show_links, + show_original: self.show_original + } + } +} + +impl Default for DisplayOptionsBuilder { + fn default() -> Self { + Self::new() + } +} diff --git a/masterror-cli/src/output.rs b/masterror-cli/src/output.rs new file mode 100644 index 0000000..55f9c58 --- /dev/null +++ b/masterror-cli/src/output.rs @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Terminal output formatting for errors. + +use masterror_knowledge::{ErrorEntry, ErrorRegistry, Lang, UiMsg}; +use owo_colors::OwoColorize; + +use crate::{options::DisplayOptions, parser::CargoMessage, sections}; + +// ───────────────────────────────────────────────────────────────────────────── +// Colored output helpers +// ───────────────────────────────────────────────────────────────────────────── + +/// Print text as bold title. +pub fn print_title(text: &str, colored: bool) { + if colored { + println!("{}", text.bold()); + } else { + println!("{text}"); + } +} + +/// Print category header (yellow bold). +pub fn print_category_header(text: &str, colored: bool) { + if colored { + println!(" {}", text.yellow().bold()); + } else { + println!(" {text}"); + } +} + +/// Print code with title (code in cyan). +pub fn print_code_title(code: &str, title: &str, colored: bool) { + if colored { + println!(" {} - {title}", code.cyan()); + } else { + println!(" {code} - {title}"); + } +} + +/// Print section label (green bold). +pub fn print_label(label: &str, colored: bool) { + if colored { + println!("{}", label.green().bold()); + } else { + println!("{label}"); + } +} + +/// Print dimmed text. +pub fn print_dimmed(text: &str, colored: bool) { + if colored { + println!("{}", text.dimmed()); + } else { + println!("{text}"); + } +} + +const SEPARATOR: &str = "--- masterror ----------------------------------------"; +const SEPARATOR_END: &str = "------------------------------------------------------"; + +/// Print error with masterror explanation. +pub fn print_error(lang: Lang, msg: &CargoMessage, opts: &DisplayOptions) { + let rendered = msg.rendered_output(); + + if opts.show_original + && let Some(r) = rendered + { + print!("{}", r.trim_end()); + } + + let Some(code) = msg.error_code() else { + if opts.show_original { + println!(); + } + return; + }; + + let registry = ErrorRegistry::new(); + let Some(entry) = registry.find(code) else { + if opts.show_original { + println!(); + } + return; + }; + + println!(); + print_block(lang, entry, rendered, opts); +} + +fn print_block(lang: Lang, entry: &ErrorEntry, rendered: Option<&str>, opts: &DisplayOptions) { + print_dimmed(SEPARATOR, opts.colored); + + if opts.show_translation { + sections::translation::print(lang, rendered, opts.colored); + } + + if opts.show_why { + print_label(UiMsg::LabelWhy.get(lang), opts.colored); + println!("{}", entry.explanation.get(lang.code())); + } + + if opts.show_fix { + sections::fix::print(lang, entry.fixes, opts.colored); + } + + if opts.show_links { + sections::link::print(lang, entry.links, opts.colored); + } + + print_dimmed(SEPARATOR_END, opts.colored); +} diff --git a/masterror-cli/src/parser.rs b/masterror-cli/src/parser.rs new file mode 100644 index 0000000..6b25c8f --- /dev/null +++ b/masterror-cli/src/parser.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Cargo JSON output parser. + +use serde::Deserialize; + +/// Top-level cargo message. +#[derive(Deserialize)] +pub struct CargoMessage { + pub reason: String, + pub message: Option, + /// Full rendered compiler output. + pub rendered: Option +} + +/// Compiler diagnostic message. +#[derive(Deserialize)] +pub struct DiagnosticMessage { + pub level: String, + #[allow(dead_code)] + pub message: String, + pub code: Option, + pub rendered: Option +} + +/// Error code info. +#[derive(Deserialize)] +pub struct DiagnosticCode { + pub code: String +} + +impl CargoMessage { + /// Check if this is a compiler error message. + pub fn is_error(&self) -> bool { + self.reason == "compiler-message" + && self.message.as_ref().is_some_and(|m| m.level == "error") + } + + /// Get the error code if present. + pub fn error_code(&self) -> Option<&str> { + self.message + .as_ref() + .and_then(|m| m.code.as_ref()) + .map(|c| c.code.as_str()) + } + + /// Get the error message. + #[allow(dead_code)] + pub fn error_message(&self) -> Option<&str> { + self.message.as_ref().map(|m| m.message.as_str()) + } + + /// Get rendered output (from message or top-level). + pub fn rendered_output(&self) -> Option<&str> { + self.message + .as_ref() + .and_then(|m| m.rendered.as_deref()) + .or(self.rendered.as_deref()) + } +} diff --git a/masterror-cli/src/sections.rs b/masterror-cli/src/sections.rs new file mode 100644 index 0000000..82c32d3 --- /dev/null +++ b/masterror-cli/src/sections.rs @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Output sections for masterror block. + +pub mod fix; +pub mod link; +pub mod translation; diff --git a/masterror-cli/src/sections/fix.rs b/masterror-cli/src/sections/fix.rs new file mode 100644 index 0000000..113c62d --- /dev/null +++ b/masterror-cli/src/sections/fix.rs @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Fix section - shows fix suggestions with code examples. + +use masterror_knowledge::{FixSuggestion, Lang, UiMsg}; +use owo_colors::OwoColorize; + +/// Print fix suggestions with code examples. +pub fn print(lang: Lang, fixes: &[FixSuggestion], colored: bool) { + if fixes.is_empty() { + return; + } + + let label = UiMsg::LabelFix.get(lang); + + if colored { + println!("{}", label.green().bold()); + } else { + println!("{label}"); + } + + for (i, fix) in fixes.iter().enumerate() { + let desc = fix.description.get(lang.code()); + let num = i + 1; + if colored { + println!(" {}. {}", num.cyan(), desc); + println!(" {}", fix.code.dimmed()); + } else { + println!(" {num}. {desc}"); + println!(" {}", fix.code); + } + } +} diff --git a/masterror-cli/src/sections/link.rs b/masterror-cli/src/sections/link.rs new file mode 100644 index 0000000..d8e8843 --- /dev/null +++ b/masterror-cli/src/sections/link.rs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Link section - shows documentation URLs. + +use masterror_knowledge::{DocLink, Lang, UiMsg}; +use owo_colors::OwoColorize; + +/// Print documentation links with titles. +pub fn print(lang: Lang, links: &[DocLink], colored: bool) { + if links.is_empty() { + return; + } + + let label = UiMsg::LabelLink.get(lang); + + if colored { + println!("{}", label.blue().bold()); + } else { + println!("{label}"); + } + + for link in links { + if colored { + println!(" {} {}", link.title.cyan(), link.url.underline().dimmed()); + } else { + println!(" {} {}", link.title, link.url); + } + } +} diff --git a/masterror-cli/src/sections/translation.rs b/masterror-cli/src/sections/translation.rs new file mode 100644 index 0000000..c9a4758 --- /dev/null +++ b/masterror-cli/src/sections/translation.rs @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Translation section - shows full translated compiler error. + +use masterror_knowledge::{Lang, UiMsg, phrases::translate_rendered}; +use owo_colors::OwoColorize; + +/// Print full translated copy of compiler error. +pub fn print(lang: Lang, rendered: Option<&str>, colored: bool) { + if matches!(lang, Lang::En) { + return; + } + + let Some(rendered) = rendered else { + return; + }; + + let translated = translate_rendered(rendered, lang); + + let label = UiMsg::LabelTranslation.get(lang); + + if colored { + println!("{}", label.cyan().bold()); + } else { + println!("{label}"); + } + + for line in translated.lines() { + println!(" {line}"); + } +} diff --git a/masterror-derive/src/app_error_impl.rs b/masterror-derive/src/app_error_impl.rs index c9a944c..b5f7b49 100644 --- a/masterror-derive/src/app_error_impl.rs +++ b/masterror-derive/src/app_error_impl.rs @@ -170,20 +170,26 @@ fn enum_app_code_impl(input: &ErrorInput, variants: &[VariantData]) -> TokenStre } } -fn variant_app_error_pattern(enum_ident: &syn::Ident, variant: &VariantData) -> TokenStream { +fn variant_pattern( + enum_ident: &syn::Ident, + variant: &VariantData, + with_binding: bool +) -> TokenStream { let ident = &variant.ident; - match &variant.fields { - Fields::Unit => quote! { err @ #enum_ident::#ident }, - Fields::Named(_) => quote! { err @ #enum_ident::#ident { .. } }, - Fields::Unnamed(_) => quote! { err @ #enum_ident::#ident(..) } + match (&variant.fields, with_binding) { + (Fields::Unit, true) => quote! { err @ #enum_ident::#ident }, + (Fields::Unit, false) => quote! { #enum_ident::#ident }, + (Fields::Named(_), true) => quote! { err @ #enum_ident::#ident { .. } }, + (Fields::Named(_), false) => quote! { #enum_ident::#ident { .. } }, + (Fields::Unnamed(_), true) => quote! { err @ #enum_ident::#ident(..) }, + (Fields::Unnamed(_), false) => quote! { #enum_ident::#ident(..) } } } +fn variant_app_error_pattern(enum_ident: &syn::Ident, variant: &VariantData) -> TokenStream { + variant_pattern(enum_ident, variant, true) +} + fn variant_app_code_pattern(enum_ident: &syn::Ident, variant: &VariantData) -> TokenStream { - let ident = &variant.ident; - match &variant.fields { - Fields::Unit => quote! { #enum_ident::#ident }, - Fields::Named(_) => quote! { #enum_ident::#ident { .. } }, - Fields::Unnamed(_) => quote! { #enum_ident::#ident(..) } - } + variant_pattern(enum_ident, variant, false) } diff --git a/masterror-derive/src/input/parse_attr.rs b/masterror-derive/src/input/parse_attr.rs index 6e2f53a..6fa9094 100644 --- a/masterror-derive/src/input/parse_attr.rs +++ b/masterror-derive/src/input/parse_attr.rs @@ -25,26 +25,28 @@ use super::{ }; use crate::template_support::parse_display_template; -/// Extracts masterror specification from attributes. -pub(crate) fn extract_masterror_spec( +/// Generic attribute extraction with duplicate detection. +fn extract_single_attr( attrs: &[Attribute], + attr_name: &str, + parse_fn: impl Fn(&Attribute) -> syn::Result, errors: &mut Vec -) -> Result, ()> { +) -> Result, ()> { let mut spec = None; let mut had_error = false; for attr in attrs { - if !path_is(attr, "masterror") { + if !path_is(attr, attr_name) { continue; } if spec.is_some() { errors.push(Error::new_spanned( attr, - "duplicate #[masterror(...)] attribute" + format!("duplicate #[{attr_name}(...)] attribute") )); had_error = true; continue; } - match parse_masterror_attribute(attr) { + match parse_fn(attr) { Ok(parsed) => spec = Some(parsed), Err(err) => { errors.push(err); @@ -55,34 +57,20 @@ pub(crate) fn extract_masterror_spec( if had_error { Err(()) } else { Ok(spec) } } +/// Extracts masterror specification from attributes. +pub(crate) fn extract_masterror_spec( + attrs: &[Attribute], + errors: &mut Vec +) -> Result, ()> { + extract_single_attr(attrs, "masterror", parse_masterror_attribute, errors) +} + /// Extracts app_error specification from attributes. pub(crate) fn extract_app_error_spec( attrs: &[Attribute], errors: &mut Vec ) -> Result, ()> { - let mut spec = None; - let mut had_error = false; - for attr in attrs { - if !path_is(attr, "app_error") { - continue; - } - if spec.is_some() { - errors.push(Error::new_spanned( - attr, - "duplicate #[app_error(...)] attribute" - )); - had_error = true; - continue; - } - match parse_app_error_attribute(attr) { - Ok(parsed) => spec = Some(parsed), - Err(err) => { - errors.push(err); - had_error = true; - } - } - } - if had_error { Err(()) } else { Ok(spec) } + extract_single_attr(attrs, "app_error", parse_app_error_attribute, errors) } /// Extracts display specification from error attributes. diff --git a/masterror-knowledge/Cargo.toml b/masterror-knowledge/Cargo.toml new file mode 100644 index 0000000..fce37d1 --- /dev/null +++ b/masterror-knowledge/Cargo.toml @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2025-2026 RAprogramm +# +# SPDX-License-Identifier: MIT + +[package] +name = "masterror-knowledge" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +description = "Knowledge base for Rust compiler errors and best practices" +keywords = ["rust", "compiler", "errors", "explain", "learning"] +categories = ["development-tools", "command-line-utilities"] + +[features] +default = ["lang-ru", "lang-ko"] + +# Languages +lang-ru = [] +lang-ko = [] + +[dependencies] +arrayvec = "0.7" +aho-corasick = "1" diff --git a/masterror-knowledge/README.md b/masterror-knowledge/README.md new file mode 100644 index 0000000..bf83138 --- /dev/null +++ b/masterror-knowledge/README.md @@ -0,0 +1,88 @@ + + +
+ masterror-knowledge + +

masterror-knowledge

+

Knowledge base for Rust compiler errors and best practices

+ + [![Crates.io](https://img.shields.io/crates/v/masterror-knowledge)](https://crates.io/crates/masterror-knowledge) + [![docs.rs](https://img.shields.io/docsrs/masterror-knowledge)](https://docs.rs/masterror-knowledge) + ![License](https://img.shields.io/badge/License-MIT-informational) +
+ +--- + +## Overview + +`masterror-knowledge` provides a comprehensive knowledge base of Rust compiler error explanations and best practices. It powers the [masterror-cli](https://github.com/RAprogramm/masterror-cli) tool, enabling developers to quickly understand and fix compiler errors. + +## Features + +- **31+ Error Explanations** — Detailed explanations for common Rust compiler errors (E0001-E0792) +- **15 RustManifest Best Practices** — Guidelines for writing idiomatic Rust code +- **Multi-language Support** — Available in English, Russian, and Korean +- **Zero Dependencies** — Lightweight, no runtime overhead +- **Compile-time Lookup** — Fast pattern matching using Aho-Corasick algorithm + +## Supported Languages + +| Feature | Language | +|---------|----------| +| (default) | English | +| `lang-ru` | Russian | +| `lang-ko` | Korean | + +## Installation + +```toml +[dependencies] +masterror-knowledge = "0.1" +``` + +With additional languages: + +```toml +[dependencies] +masterror-knowledge = { version = "0.1", features = ["lang-ru", "lang-ko"] } +``` + +## Usage + +```rust +use masterror_knowledge::{Lang, lookup_error, lookup_practice}; + +// Get explanation for error E0382 (borrow of moved value) +if let Some(explanation) = lookup_error("E0382", Lang::En) { + println!("{}", explanation); +} + +// Get best practice by ID +if let Some(practice) = lookup_practice("RM001", Lang::En) { + println!("{}", practice); +} +``` + +## Error Codes Covered + +The knowledge base includes explanations for errors related to: + +- **Ownership & Borrowing** — E0382, E0499, E0502, E0505, E0507 +- **Lifetimes** — E0106, E0621, E0759, E0792 +- **Type System** — E0277, E0308, E0412, E0425 +- **Traits** — E0046, E0119, E0277 +- **Patterns** — E0004, E0005, E0026, E0027 +- **And more...** + +## Related + +- [masterror](https://github.com/RAprogramm/masterror) — Framework-agnostic application error types +- [masterror-cli](https://github.com/RAprogramm/masterror-cli) — CLI tool using this knowledge base + +## License + +MIT diff --git a/masterror-knowledge/src/errors.rs b/masterror-knowledge/src/errors.rs new file mode 100644 index 0000000..1e1deed --- /dev/null +++ b/masterror-knowledge/src/errors.rs @@ -0,0 +1,325 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Rust compiler error explanations organized by category. + +pub mod abi; +pub mod attributes; +pub mod borrowing; +pub mod const_eval; +pub mod consts; +pub mod features; +pub mod generics; +pub mod lifetimes; +pub mod linking; +pub mod ownership; +pub mod patterns; +pub mod raprogramm; +pub mod resolution; +pub mod simd; +pub mod structs; +pub mod syntax; +pub mod traits; +pub mod types; +pub mod unsafe_code; +pub mod visibility; + +use std::{collections::HashMap, sync::LazyLock}; + +use arrayvec::ArrayString; + +/// Global error registry singleton. +static ERROR_REGISTRY: LazyLock = LazyLock::new(ErrorRegistry::build); + +/// Link with title for documentation. +#[derive(Debug, Clone, Copy)] +pub struct DocLink { + /// Link display title. + pub title: &'static str, + /// URL to documentation. + pub url: &'static str +} + +/// Fix suggestion with code example. +#[derive(Debug, Clone, Copy)] +pub struct FixSuggestion { + /// Description of the fix approach. + pub description: LocalizedText, + /// Code example showing the fix. + pub code: &'static str +} + +/// Localized text with translations. +/// +/// All fields are `&'static str` for zero-copy access. +#[derive(Debug, Clone, Copy)] +pub struct LocalizedText { + /// English text (always present). + pub en: &'static str, + /// Russian translation. + pub ru: &'static str, + /// Korean translation. + pub ko: &'static str +} + +impl LocalizedText { + pub const fn new(en: &'static str, ru: &'static str, ko: &'static str) -> Self { + Self { + en, + ru, + ko + } + } + + pub fn get(&self, lang: &str) -> &'static str { + match lang { + "ru" => self.ru, + "ko" => self.ko, + _ => self.en + } + } +} + +/// Error category. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Category { + Ownership, + Borrowing, + Lifetimes, + Types, + Traits, + Resolution, + Generics, + Syntax, + Patterns, + UnsafeCode, + Abi, + Structs, + Simd, + Consts, + Attributes, + ConstEval, + Linking, + Visibility +} + +impl Category { + pub fn name(&self, lang: &str) -> &'static str { + match (self, lang) { + (Self::Ownership, "ru") => "Владение", + (Self::Ownership, "ko") => "소유권", + (Self::Ownership, _) => "Ownership", + + (Self::Borrowing, "ru") => "Заимствование", + (Self::Borrowing, "ko") => "빌림", + (Self::Borrowing, _) => "Borrowing", + + (Self::Lifetimes, "ru") => "Времена жизни", + (Self::Lifetimes, "ko") => "라이프타임", + (Self::Lifetimes, _) => "Lifetimes", + + (Self::Types, "ru") => "Типы", + (Self::Types, "ko") => "타입", + (Self::Types, _) => "Types", + + (Self::Traits, "ru") => "Трейты", + (Self::Traits, "ko") => "트레이트", + (Self::Traits, _) => "Traits", + + (Self::Resolution, "ru") => "Разрешение имён", + (Self::Resolution, "ko") => "이름 확인", + (Self::Resolution, _) => "Name Resolution", + + (Self::Generics, "ru") => "Обобщения", + (Self::Generics, "ko") => "제네릭", + (Self::Generics, _) => "Generics", + + (Self::Syntax, "ru") => "Синтаксис", + (Self::Syntax, "ko") => "문법", + (Self::Syntax, _) => "Syntax", + + (Self::Patterns, "ru") => "Паттерны", + (Self::Patterns, "ko") => "패턴", + (Self::Patterns, _) => "Patterns", + + (Self::UnsafeCode, "ru") => "Небезопасный код", + (Self::UnsafeCode, "ko") => "unsafe 코드", + (Self::UnsafeCode, _) => "Unsafe Code", + + (Self::Abi, "ru") => "ABI", + (Self::Abi, "ko") => "ABI", + (Self::Abi, _) => "ABI", + + (Self::Structs, "ru") => "Структуры", + (Self::Structs, "ko") => "구조체", + (Self::Structs, _) => "Structs", + + (Self::Simd, "ru") => "SIMD", + (Self::Simd, "ko") => "SIMD", + (Self::Simd, _) => "SIMD", + + (Self::Consts, "ru") => "Константы", + (Self::Consts, "ko") => "상수", + (Self::Consts, _) => "Constants", + + (Self::Attributes, "ru") => "Атрибуты", + (Self::Attributes, "ko") => "속성", + (Self::Attributes, _) => "Attributes", + + (Self::ConstEval, "ru") => "Вычисление констант", + (Self::ConstEval, "ko") => "상수 평가", + (Self::ConstEval, _) => "Const Evaluation", + + (Self::Linking, "ru") => "Связывание", + (Self::Linking, "ko") => "링킹", + (Self::Linking, _) => "Linking", + + (Self::Visibility, "ru") => "Видимость", + (Self::Visibility, "ko") => "가시성", + (Self::Visibility, _) => "Visibility" + } + } +} + +/// Complete error entry. +/// +/// Fields ordered by size (largest first) to minimize padding. +#[derive(Debug, Clone)] +pub struct ErrorEntry { + /// Error explanation text. + pub explanation: LocalizedText, + /// Short error title. + pub title: LocalizedText, + /// Suggested fixes. + pub fixes: &'static [FixSuggestion], + /// Documentation links. + pub links: &'static [DocLink], + /// Error code (E0382). + pub code: &'static str, + /// Error category. + pub category: Category +} + +/// Registry of all known errors. +pub struct ErrorRegistry { + errors: HashMap<&'static str, &'static ErrorEntry> +} + +impl ErrorRegistry { + /// Get the global registry instance. + pub fn new() -> &'static Self { + &ERROR_REGISTRY + } + + /// Build registry from all modules. + fn build() -> Self { + let mut errors = HashMap::with_capacity(400); + + for entry in abi::entries() { + errors.insert(entry.code, *entry); + } + for entry in borrowing::entries() { + errors.insert(entry.code, *entry); + } + for entry in consts::entries() { + errors.insert(entry.code, *entry); + } + for entry in features::entries() { + errors.insert(entry.code, *entry); + } + for entry in generics::entries() { + errors.insert(entry.code, *entry); + } + for entry in lifetimes::entries() { + errors.insert(entry.code, *entry); + } + for entry in ownership::entries() { + errors.insert(entry.code, *entry); + } + for entry in patterns::entries() { + errors.insert(entry.code, *entry); + } + for entry in resolution::entries() { + errors.insert(entry.code, *entry); + } + for entry in simd::entries() { + errors.insert(entry.code, *entry); + } + for entry in structs::entries() { + errors.insert(entry.code, *entry); + } + for entry in syntax::entries() { + errors.insert(entry.code, *entry); + } + for entry in traits::entries() { + errors.insert(entry.code, *entry); + } + for entry in types::entries() { + errors.insert(entry.code, *entry); + } + for entry in unsafe_code::entries() { + errors.insert(entry.code, *entry); + } + for entry in attributes::entries() { + errors.insert(entry.code, *entry); + } + for entry in const_eval::entries() { + errors.insert(entry.code, *entry); + } + for entry in linking::entries() { + errors.insert(entry.code, *entry); + } + for entry in visibility::entries() { + errors.insert(entry.code, *entry); + } + + Self { + errors + } + } + + /// Find error by code. + /// + /// Accepts formats: "E0382", "e0382", "0382". + /// Uses stack-allocated buffer to avoid heap allocation. + pub fn find(&self, code: &str) -> Option<&'static ErrorEntry> { + // Fast path: try exact match first (covers "E0382" case) + if let Some(entry) = self.errors.get(code) { + return Some(*entry); + } + + // Normalize to uppercase with 'E' prefix using stack buffer + let mut buf: ArrayString<8> = ArrayString::new(); + + if !code.starts_with('E') && !code.starts_with('e') { + buf.push('E'); + } + + for c in code.chars().take(7) { + buf.push(c.to_ascii_uppercase()); + } + + self.errors.get(buf.as_str()).copied() + } + + /// Get all errors. + pub fn all(&self) -> impl Iterator + '_ { + self.errors.values().copied() + } + + /// Get errors by category. + pub fn by_category(&self, cat: Category) -> Vec<&'static ErrorEntry> { + self.errors + .values() + .filter(|e| e.category == cat) + .copied() + .collect() + } +} + +impl Default for &'static ErrorRegistry { + fn default() -> Self { + ErrorRegistry::new() + } +} diff --git a/masterror-knowledge/src/errors/abi.rs b/masterror-knowledge/src/errors/abi.rs new file mode 100644 index 0000000..17eca72 --- /dev/null +++ b/masterror-knowledge/src/errors/abi.rs @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! ABI and FFI related errors. + +mod e0044; +mod e0045; +mod e0060; +mod e0130; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[&e0044::ENTRY, &e0045::ENTRY, &e0060::ENTRY, &e0130::ENTRY]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/abi/e0044.rs b/masterror-knowledge/src/errors/abi/e0044.rs new file mode 100644 index 0000000..a221a09 --- /dev/null +++ b/masterror-knowledge/src/errors/abi/e0044.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0044: foreign items cannot have type/const parameters + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0044", + title: LocalizedText::new( + "Foreign items cannot have type parameters", + "Внешние элементы не могут иметь параметры типа", + "외부 항목은 타입 매개변수를 가질 수 없음" + ), + category: Category::Abi, + explanation: LocalizedText::new( + "\ +Foreign items declared in `extern` blocks cannot have generic type or const +parameters. Foreign functions (from C libraries) have concrete signatures. + +Example: + extern \"C\" { + fn some_func(x: T); // Error: generic not allowed + }", + "\ +Внешние элементы, объявленные в блоках `extern`, не могут иметь обобщённые +параметры типа или константы. Внешние функции имеют конкретные сигнатуры.", + "\ +`extern` 블록에 선언된 외부 항목은 제네릭 타입이나 const 매개변수를 가질 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Create separate declarations for each type", + "Создать отдельные объявления для каждого типа", + "각 타입에 대해 별도의 선언 생성" + ), + code: "extern \"C\" {\n fn some_func_i32(x: i32);\n fn some_func_i64(x: i64);\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: External blocks", + url: "https://doc.rust-lang.org/reference/items/external-blocks.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0044.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/abi/e0045.rs b/masterror-knowledge/src/errors/abi/e0045.rs new file mode 100644 index 0000000..95d8005 --- /dev/null +++ b/masterror-knowledge/src/errors/abi/e0045.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0045: variadic parameters on non-C ABI function + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0045", + title: LocalizedText::new( + "Variadic parameters on non-C ABI", + "Вариативные параметры с не-C ABI", + "비 C ABI에서 가변 매개변수" + ), + category: Category::Abi, + explanation: LocalizedText::new( + "\ +Variadic parameters (`...`) can only be used with functions using the C ABI. +Rust only supports variadic parameters for FFI interoperability with C. + +Example: + extern \"Rust\" { + fn foo(x: u8, ...); // Error: variadic not allowed + }", + "\ +Вариативные параметры (`...`) можно использовать только с функциями, +использующими C ABI. Rust поддерживает вариативные параметры только для +взаимодействия с C через FFI.", + "\ +가변 매개변수(`...`)는 C ABI를 사용하는 함수에서만 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use extern \"C\" for variadic functions", + "Использовать extern \"C\" для вариативных функций", + "가변 함수에 extern \"C\" 사용" + ), + code: "extern \"C\" {\n fn foo(x: u8, ...);\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0045.html" + }] +}; diff --git a/masterror-knowledge/src/errors/abi/e0060.rs b/masterror-knowledge/src/errors/abi/e0060.rs new file mode 100644 index 0000000..189b030 --- /dev/null +++ b/masterror-knowledge/src/errors/abi/e0060.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0060: variadic function called with insufficient arguments + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0060", + title: LocalizedText::new( + "Variadic function called with insufficient arguments", + "Вариативная функция вызвана с недостаточным количеством аргументов", + "가변 함수가 불충분한 인수로 호출됨" + ), + category: Category::Abi, + explanation: LocalizedText::new( + "\ +Variadic external C functions still require their minimum fixed arguments. +You cannot call a variadic function with fewer arguments than the non-variadic +part requires. + +Example: + extern \"C\" { + fn printf(fmt: *const c_char, ...) -> c_int; + } + unsafe { printf(); } // Error: missing format string argument", + "\ +Вариативные внешние C функции по-прежнему требуют минимальные фиксированные +аргументы. Нельзя вызвать вариативную функцию с меньшим количеством аргументов, +чем требует невариативная часть.", + "\ +가변 외부 C 함수는 여전히 최소한의 고정 인수가 필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Provide required arguments", + "Предоставить обязательные аргументы", + "필수 인수 제공" + ), + code: "unsafe {\n printf(c\"test\\n\".as_ptr());\n printf(c\"%d\\n\".as_ptr(), 42);\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0060.html" + }] +}; diff --git a/masterror-knowledge/src/errors/abi/e0130.rs b/masterror-knowledge/src/errors/abi/e0130.rs new file mode 100644 index 0000000..e42e8a6 --- /dev/null +++ b/masterror-knowledge/src/errors/abi/e0130.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0130: patterns aren't allowed in foreign function declarations + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0130", + title: LocalizedText::new( + "Patterns aren't allowed in foreign function declarations", + "Паттерны не разрешены в объявлениях внешних функций", + "외부 함수 선언에서 패턴이 허용되지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A pattern (like tuple destructuring) was used as an argument in a foreign +function declaration. Foreign functions (declared with extern \"C\") must +use simple identifiers with explicit type annotations rather than patterns.", + "\ +Паттерн (например, деструктуризация кортежа) был использован как аргумент +в объявлении внешней функции. Внешние функции (объявленные с extern \"C\") +должны использовать простые идентификаторы с явными аннотациями типов.", + "\ +외부 함수 선언에서 패턴(튜플 구조 분해 등)이 인수로 사용되었습니다. +외부 함수(extern \"C\"로 선언)는 패턴 대신 명시적 타입 주석이 있는 +간단한 식별자를 사용해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a struct instead of tuple destructuring", + "Использовать структуру вместо деструктуризации кортежа", + "튜플 구조 분해 대신 구조체 사용" + ), + code: "struct SomeStruct {\n a: u32,\n b: u32,\n}\n\nextern \"C\" {\n fn foo(s: SomeStruct);\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a simple identifier with the tuple type", + "Использовать простой идентификатор с типом кортежа", + "튜플 타입과 함께 간단한 식별자 사용" + ), + code: "extern \"C\" {\n fn foo(a: (u32, u32));\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: FFI", + url: "https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0130.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0706.rs b/masterror-knowledge/src/errors/async/e0706.rs new file mode 100644 index 0000000..59109e5 --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0706.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0706: async fn in trait (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0706", + title: LocalizedText::new( + "Async fn not supported in traits", + "Async fn не поддерживается в трейтах", + "트레이트에서 async fn 지원되지 않음" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler. + +Previously, `async fn`s were not supported in traits because they return +`impl Future`, which requires Generic Associated Types (GATs). + +Modern Rust now supports async functions in traits natively.", + "\ +Примечание: Эта ошибка больше не выдаётся компилятором. + +Ранее `async fn` не поддерживались в трейтах, так как они возвращают +`impl Future`, что требовало GATs. Современный Rust поддерживает это.", + "\ +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다. + +이전에는 `async fn`이 트레이트에서 지원되지 않았습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use native async trait (modern Rust)", + "Используйте встроенную поддержку async trait", + "네이티브 async 트레이트 사용" + ), + code: "trait MyTrait {\n async fn foo(&self);\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use async-trait crate (legacy)", + "Используйте крейт async-trait", + "async-trait 크레이트 사용" + ), + code: "#[async_trait]\ntrait MyTrait {\n async fn foo(&self);\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0706.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0708.rs b/masterror-knowledge/src/errors/async/e0708.rs new file mode 100644 index 0000000..c50855d --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0708.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0708: async non-move closure with parameters (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0708", + title: LocalizedText::new( + "Async non-move closure with parameters", + "Async замыкание без move с параметрами", + "매개변수가 있는 async non-move 클로저" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler. + +Previously, `async` closures with parameters required the `move` keyword. +Modern Rust has relaxed this restriction.", + "\ +Примечание: Эта ошибка больше не выдаётся компилятором. + +Ранее `async` замыкания с параметрами требовали ключевое слово `move`.", + "\ +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add move keyword (legacy fix)", + "Добавьте ключевое слово move", + "move 키워드 추가" + ), + code: "let add_one = async move |num: u8| {\n num + 1\n};" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0708.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0727.rs b/masterror-knowledge/src/errors/async/e0727.rs new file mode 100644 index 0000000..e3d7682 --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0727.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0727: `yield` used in async context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0727", + title: LocalizedText::new( + "yield clause used in async context", + "yield используется в асинхронном контексте", + "async 컨텍스트에서 yield 사용됨" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +A `yield` clause was used in an `async` context. The `yield` keyword is used +for coroutines/generators, but mixing it with async blocks is not supported. + +The async machinery handles its own suspension points via `.await`, and +coroutine yields are a separate mechanism that cannot be mixed.", + "\ +Ключевое слово `yield` было использовано в `async` контексте. +`yield` используется для корутин/генераторов, но смешивание с async блоками +не поддерживается.", + "\ +`async` 컨텍스트에서 `yield` 절이 사용되었습니다. `yield` 키워드는 +코루틴/제너레이터용이며 async 블록과 혼합할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Move yield outside async block", + "Переместите yield за пределы async блока", + "yield를 async 블록 밖으로 이동" + ), + code: "#[coroutine] || {\n yield;\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0727.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0728.rs b/masterror-knowledge/src/errors/async/e0728.rs new file mode 100644 index 0000000..84dd171 --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0728.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0728: await used outside async context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0728", + title: LocalizedText::new( + "await used outside async context", + "await используется вне асинхронного контекста", + "async 컨텍스트 외부에서 await 사용" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +The `await` keyword was used outside of an `async` function or `async` block. + +The `await` keyword is used to suspend the current computation until the +given future is ready to produce a value. It is only legal within an async +context, such as an `async fn` or an `async` block.", + "\ +Ключевое слово `await` используется вне `async` функции или `async` блока. + +`await` приостанавливает текущее вычисление до готовности future. +Оно допустимо только в async контексте.", + "\ +`await` 키워드가 `async` 함수나 `async` 블록 외부에서 사용되었습니다. + +`await`는 현재 계산을 일시 중지하며 async 컨텍스트 내에서만 유효합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use await inside async function", + "Используйте await внутри async функции", + "async 함수 내에서 await 사용" + ), + code: "async fn foo() {\n some_future().await;\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use await inside async block", + "Используйте await внутри async блока", + "async 블록 내에서 await 사용" + ), + code: "fn bar() -> impl Future {\n async {\n some_future().await\n }\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0728.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0733.rs b/masterror-knowledge/src/errors/async/e0733.rs new file mode 100644 index 0000000..3705968 --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0733.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0733: async recursion without boxing + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0733", + title: LocalizedText::new( + "Async recursion without boxing", + "Асинхронная рекурсия без упаковки", + "박싱 없는 async 재귀" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +An `async` function called itself recursively without boxing. + +When an async function calls itself recursively, the compiler cannot determine +the size of the future at compile time, because each recursive call creates +a new future. Without boxing, the compiler cannot allocate the necessary memory.", + "\ +Асинхронная функция вызывает себя рекурсивно без упаковки. + +Компилятор не может определить размер future во время компиляции, +так как каждый рекурсивный вызов создаёт новый future.", + "\ +`async` 함수가 박싱 없이 자신을 재귀적으로 호출했습니다. + +컴파일러가 컴파일 시점에 future 크기를 결정할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Box the recursive call", + "Упакуйте рекурсивный вызов", + "재귀 호출을 박싱" + ), + code: "async fn foo(n: usize) {\n if n > 0 {\n Box::pin(foo(n - 1)).await;\n }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Return boxed future", + "Верните упакованный future", + "박싱된 future 반환" + ), + code: "fn foo(n: usize) -> Pin>> {\n Box::pin(async move {\n if n > 0 { foo(n - 1).await; }\n })\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0733.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0744.rs b/masterror-knowledge/src/errors/async/e0744.rs new file mode 100644 index 0000000..94d6e2b --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0744.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0744: await in const context (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0744", + title: LocalizedText::new( + "Await used in const context", + "Await используется в const контексте", + "const 컨텍스트에서 await 사용" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler. + +Previously, `.await` was forbidden inside a `const`, `static`, or `const fn`. +This restriction may be lifted in future Rust versions.", + "\ +Примечание: Эта ошибка больше не выдаётся компилятором. + +Ранее `.await` был запрещён внутри `const`, `static` или `const fn`.", + "\ +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Move async code outside const context", + "Переместите async код за пределы const контекста", + "async 코드를 const 컨텍스트 밖으로 이동" + ), + code: "async fn compute() -> i32 {\n async { 0 }.await\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0744.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0752.rs b/masterror-knowledge/src/errors/async/e0752.rs new file mode 100644 index 0000000..35fcdf1 --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0752.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0752: async entry point not allowed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0752", + title: LocalizedText::new( + "Async entry point not allowed", + "Асинхронная точка входа не допускается", + "async 진입점 허용되지 않음" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +The entry point of the program was marked as `async`. The `fn main()` function +or the specified start function is not allowed to be `async`. + +The program entry point must be synchronous. To use async code, you need an +async runtime (like tokio or async-std) that will manage the async execution.", + "\ +Точка входа программы была помечена как `async`. Функция `fn main()` +не может быть асинхронной. + +Для использования async кода нужен runtime (tokio, async-std).", + "\ +프로그램 진입점이 `async`로 표시되었습니다. `fn main()` 함수는 +`async`일 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove async from main", + "Удалите async из main", + "main에서 async 제거" + ), + code: "fn main() -> Result<(), ()> {\n Ok(())\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use async runtime macro", + "Используйте макрос async runtime", + "async 런타임 매크로 사용" + ), + code: "#[tokio::main]\nasync fn main() {\n // async code\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0752.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/async/e0760.rs b/masterror-knowledge/src/errors/async/e0760.rs new file mode 100644 index 0000000..24dc87c --- /dev/null +++ b/masterror-knowledge/src/errors/async/e0760.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0760: async fn return type with Self referencing parent lifetime (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0760", + title: LocalizedText::new( + "Async fn return type references parent lifetime via Self", + "Возвращаемый тип async fn ссылается на родительское время жизни через Self", + "async fn 반환 타입이 Self를 통해 부모 수명 참조" + ), + category: Category::Async, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler. + +Previously, an `async fn` or `impl Trait` return type could not contain +a projection or `Self` that references lifetimes from a parent scope.", + "\ +Примечание: Эта ошибка больше не выдаётся компилятором. + +Ранее возвращаемый тип `async fn` не мог содержать проекцию или `Self`, +ссылающиеся на времена жизни из родительской области.", + "\ +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Spell out Self explicitly (legacy fix)", + "Явно укажите Self", + "Self를 명시적으로 작성" + ), + code: "impl<'a> S<'a> {\n async fn new(i: &'a i32) -> S<'a> {\n S(&22)\n }\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0760.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes.rs b/masterror-knowledge/src/errors/attributes.rs new file mode 100644 index 0000000..9f00f8c --- /dev/null +++ b/masterror-knowledge/src/errors/attributes.rs @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Attribute and linking related errors. + +mod e0452; +mod e0453; +mod e0454; +mod e0455; +mod e0457; +mod e0458; +mod e0459; +mod e0466; +mod e0468; +mod e0469; +mod e0517; +mod e0518; +mod e0522; +mod e0536; +mod e0537; +mod e0538; +mod e0539; +mod e0541; +mod e0552; +mod e0554; +mod e0556; +mod e0557; +mod e0565; +mod e0566; +mod e0587; +mod e0588; +mod e0589; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0452::ENTRY, + &e0453::ENTRY, + &e0454::ENTRY, + &e0455::ENTRY, + &e0457::ENTRY, + &e0458::ENTRY, + &e0459::ENTRY, + &e0466::ENTRY, + &e0468::ENTRY, + &e0469::ENTRY, + &e0517::ENTRY, + &e0518::ENTRY, + &e0522::ENTRY, + &e0536::ENTRY, + &e0537::ENTRY, + &e0538::ENTRY, + &e0539::ENTRY, + &e0541::ENTRY, + &e0552::ENTRY, + &e0554::ENTRY, + &e0556::ENTRY, + &e0557::ENTRY, + &e0565::ENTRY, + &e0566::ENTRY, + &e0587::ENTRY, + &e0588::ENTRY, + &e0589::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/attributes/e0452.rs b/masterror-knowledge/src/errors/attributes/e0452.rs new file mode 100644 index 0000000..c00fc66 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0452.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0452: malformed lint attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0452", + title: LocalizedText::new( + "Malformed lint attribute", + "Неправильный атрибут линта", + "잘못된 형식의 린트 속성" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +An invalid lint attribute has been given. Lint attributes must follow a +specific format and only accept a list of identifiers (lint names). +Assignments or string values are not allowed.", + "\ +Задан недопустимый атрибут линта. Атрибуты линтов должны следовать +определённому формату и принимают только список идентификаторов +(имён линтов). Присваивания или строковые значения не допускаются.", + "\ +유효하지 않은 린트 속성이 제공되었습니다. 린트 속성은 특정 형식을 +따라야 하며 식별자(린트 이름) 목록만 허용합니다. 할당이나 문자열 +값은 허용되지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use comma-separated lint identifiers", + "Использовать идентификаторы линтов через запятую", + "쉼표로 구분된 린트 식별자 사용" + ), + code: "#![allow(unused, dead_code)]" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0452.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0453.rs b/masterror-knowledge/src/errors/attributes/e0453.rs new file mode 100644 index 0000000..18590f2 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0453.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0453: forbid overruled by allow + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0453", + title: LocalizedText::new( + "Lint forbid overruled by inner attribute", + "Запрет линта нарушен внутренним атрибутом", + "내부 속성에 의해 린트 금지가 무시됨" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +An attempt was made to override a forbid lint directive using an inner +attribute like #[allow(...)]. The forbid lint setting is stricter than deny +because it prevents itself from being overridden by any inner attributes. + +- forbid: turns warning into error AND prevents overriding +- deny: turns warning into error BUT allows overriding", + "\ +Попытка переопределить директиву forbid с помощью внутреннего атрибута +#[allow(...)]. Настройка forbid строже чем deny, так как она запрещает +переопределение внутренними атрибутами. + +- forbid: превращает предупреждение в ошибку И запрещает переопределение +- deny: превращает предупреждение в ошибку НО позволяет переопределение", + "\ +#[allow(...)]와 같은 내부 속성을 사용하여 forbid 린트 지시문을 +재정의하려고 시도했습니다. forbid 린트 설정은 내부 속성에 의한 +재정의를 방지하므로 deny보다 엄격합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Replace forbid with deny to allow overriding", + "Заменить forbid на deny для разрешения переопределения", + "재정의를 허용하려면 forbid를 deny로 교체" + ), + code: "#![deny(non_snake_case)]\n\n#[allow(non_snake_case)]\nfn main() {\n let MyNumber = 2; // ok!\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Fix the code to comply with the lint", + "Исправить код для соответствия линту", + "린트에 맞게 코드 수정" + ), + code: "#![forbid(non_snake_case)]\n\nfn main() {\n let my_number = 2;\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0453.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0454.rs b/masterror-knowledge/src/errors/attributes/e0454.rs new file mode 100644 index 0000000..4d5535c --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0454.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0454: link with empty name + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0454", + title: LocalizedText::new( + "Link name given with empty name", + "Имя ссылки указано как пустая строка", + "링크 이름이 빈 문자열로 제공됨" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A link name was specified with an empty string. The Rust compiler requires +an actual library name to link to external C libraries. An empty name string +provides no valid target for the linker.", + "\ +Имя ссылки указано как пустая строка. Компилятор Rust требует реальное +имя библиотеки для связывания с внешними C библиотеками. Пустая строка +не предоставляет допустимую цель для компоновщика.", + "\ +링크 이름이 빈 문자열로 지정되었습니다. Rust 컴파일러는 외부 C +라이브러리에 연결하기 위해 실제 라이브러리 이름이 필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Provide a valid library name", + "Указать допустимое имя библиотеки", + "유효한 라이브러리 이름 제공" + ), + code: "#[link(name = \"some_lib\")] extern \"C\" {}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0454.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0455.rs b/masterror-knowledge/src/errors/attributes/e0455.rs new file mode 100644 index 0000000..9a17206 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0455.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0455: platform-specific link kind + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0455", + title: LocalizedText::new( + "Platform-specific link kind not supported on this target", + "Специфичный для платформы тип ссылки не поддерживается", + "이 타겟에서 플랫폼별 링크 종류가 지원되지 않음" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +Some linking kinds are target-specific and not supported on all platforms: +- kind=framework: only supported on macOS +- kind=raw-dylib: only supported on Windows-like platforms + +Using these on unsupported platforms will cause this error.", + "\ +Некоторые типы связывания специфичны для платформы: +- kind=framework: поддерживается только на macOS +- kind=raw-dylib: поддерживается только на Windows-подобных платформах + +Использование их на неподдерживаемых платформах вызовет эту ошибку.", + "\ +일부 링크 종류는 플랫폼별로 특정됩니다: +- kind=framework: macOS에서만 지원 +- kind=raw-dylib: Windows 유사 플랫폼에서만 지원" + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use conditional compilation", + "Использовать условную компиляцию", + "조건부 컴파일 사용" + ), + code: "#[cfg_attr(target_os = \"macos\", link(name = \"CoreServices\", kind = \"framework\"))]\nextern \"C\" {}" + }], + links: &[ + DocLink { + title: "Conditional Compilation", + url: "https://doc.rust-lang.org/reference/attributes.html#conditional-compilation" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0455.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0457.rs b/masterror-knowledge/src/errors/attributes/e0457.rs new file mode 100644 index 0000000..7350b6d --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0457.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0457: plugin only in rlib format + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0457", + title: LocalizedText::new( + "Plugin only found in rlib format, dylib required", + "Плагин найден только в формате rlib, требуется dylib", + "플러그인이 rlib 형식으로만 발견됨, dylib 필요" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A plugin crate was compiled to the statically-linked rlib format instead +of the required dynamically-linked dylib format. The Rust compiler's plugin +interface requires plugins to be compiled as dynamically-linked libraries. + +Note: This error is no longer emitted by modern compilers as the plugin +system has been deprecated in favor of procedural macros.", + "\ +Крейт плагина скомпилирован в статически связываемый формат rlib вместо +требуемого динамически связываемого формата dylib. Интерфейс плагинов +компилятора Rust требует компиляции плагинов как динамических библиотек. + +Примечание: эта ошибка больше не выдаётся, так как система плагинов +устарела в пользу процедурных макросов.", + "\ +플러그인 크레이트가 필요한 동적 링크 dylib 형식 대신 정적 링크 +rlib 형식으로 컴파일되었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Compile the plugin as dylib", + "Скомпилировать плагин как dylib", + "플러그인을 dylib로 컴파일" + ), + code: "# In Cargo.toml:\n[lib]\ncrate-type = [\"dylib\"]" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0457.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0458.rs b/masterror-knowledge/src/errors/attributes/e0458.rs new file mode 100644 index 0000000..a2c835c --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0458.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0458: unknown link kind + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0458", + title: LocalizedText::new( + "Unknown link kind in link attribute", + "Неизвестный тип ссылки в атрибуте link", + "link 속성의 알 수 없는 링크 종류" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +An invalid kind value was specified in a #[link] attribute. The kind +parameter only accepts specific valid values for linking strategies. + +Note: This error is no longer emitted by modern compilers.", + "\ +Недопустимое значение kind указано в атрибуте #[link]. Параметр kind +принимает только определённые допустимые значения для стратегий связывания. + +Примечание: эта ошибка больше не выдаётся современными компиляторами.", + "\ +#[link] 속성에 유효하지 않은 kind 값이 지정되었습니다. kind +매개변수는 링크 전략에 대한 특정 유효한 값만 허용합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a valid link kind", + "Использовать допустимый тип ссылки", + "유효한 링크 종류 사용" + ), + code: "// Valid kinds: static, dylib, framework (macOS), raw-dylib (Windows)\n#[link(kind = \"static\", name = \"foo\")] extern \"C\" {}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0458.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0459.rs b/masterror-knowledge/src/errors/attributes/e0459.rs new file mode 100644 index 0000000..2ba6a08 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0459.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0459: link without name parameter + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0459", + title: LocalizedText::new( + "Link specified without name parameter", + "Ссылка указана без параметра name", + "name 매개변수 없이 link가 지정됨" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +The #[link(...)] attribute was used in an extern block without specifying +the required name parameter. The Rust compiler needs the name parameter +to know which library to link against.", + "\ +Атрибут #[link(...)] использован в блоке extern без указания +обязательного параметра name. Компилятору Rust нужен параметр name, +чтобы знать, с какой библиотекой связываться.", + "\ +extern 블록에서 필수 name 매개변수를 지정하지 않고 #[link(...)] +속성이 사용되었습니다. Rust 컴파일러는 어떤 라이브러리에 연결할지 +알기 위해 name 매개변수가 필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add the name parameter", + "Добавить параметр name", + "name 매개변수 추가" + ), + code: "#[link(kind = \"dylib\", name = \"some_lib\")] extern \"C\" {}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0459.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0466.rs b/masterror-knowledge/src/errors/attributes/e0466.rs new file mode 100644 index 0000000..46881b0 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0466.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0466: malformed macro_use declaration + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0466", + title: LocalizedText::new( + "Malformed macro import declaration", + "Неправильное объявление импорта макросов", + "잘못된 형식의 매크로 임포트 선언" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +The syntax used in a #[macro_use] attribute declaration is incorrect. +The attribute expects a comma-separated list of macro names inside +parentheses, not function calls or key-value assignments. + +Note: This error is no longer emitted by modern compilers.", + "\ +Синтаксис в объявлении атрибута #[macro_use] неверен. Атрибут ожидает +список имён макросов через запятую в скобках, а не вызовы функций +или присваивания ключ-значение. + +Примечание: эта ошибка больше не выдаётся современными компиляторами.", + "\ +#[macro_use] 속성 선언에 사용된 구문이 올바르지 않습니다. 속성은 +괄호 안에 쉼표로 구분된 매크로 이름 목록을 기대하며, 함수 호출이나 +키-값 할당은 허용되지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use comma-separated macro names", + "Использовать имена макросов через запятую", + "쉼표로 구분된 매크로 이름 사용" + ), + code: "#[macro_use(macro1, macro2)]\nextern crate some_crate;" + }, + FixSuggestion { + description: LocalizedText::new( + "Import all macros from crate", + "Импортировать все макросы из крейта", + "크레이트에서 모든 매크로 임포트" + ), + code: "#[macro_use]\nextern crate some_crate;" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0466.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0468.rs b/masterror-knowledge/src/errors/attributes/e0468.rs new file mode 100644 index 0000000..694a562 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0468.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0468: macro import from non-root module + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0468", + title: LocalizedText::new( + "Non-root module tried to import macros from another crate", + "Нерневой модуль попытался импортировать макросы из другого крейта", + "비루트 모듈이 다른 크레이트에서 매크로를 임포트하려고 시도함" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +An attempt was made to use #[macro_use] with extern crate in a non-root +module. The Rust compiler only allows macro imports from external crates +when the extern crate declaration is at the crate root level.", + "\ +Попытка использовать #[macro_use] с extern crate в некорневом модуле. +Компилятор Rust разрешает импорт макросов из внешних крейтов только +когда объявление extern crate находится на корневом уровне крейта.", + "\ +비루트 모듈에서 extern crate와 함께 #[macro_use]를 사용하려고 +시도했습니다. Rust 컴파일러는 extern crate 선언이 크레이트 루트 +수준에 있을 때만 외부 크레이트에서 매크로 임포트를 허용합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Move macro import to crate root", + "Переместить импорт макросов в корень крейта", + "매크로 임포트를 크레이트 루트로 이동" + ), + code: "// In lib.rs or main.rs:\n#[macro_use]\nextern crate some_crate;\n\nmod foo {\n fn run_macro() { some_macro!(); }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0468.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0469.rs b/masterror-knowledge/src/errors/attributes/e0469.rs new file mode 100644 index 0000000..6665b99 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0469.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0469: imported macro not found + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0469", + title: LocalizedText::new( + "Imported macro not found in crate", + "Импортируемый макрос не найден в крейте", + "임포트된 매크로가 크레이트에서 찾을 수 없음" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A macro listed for import via #[macro_use(macro_name)] cannot be found +in the imported crate. The macro must: +1. Exist in the crate +2. Be exported with the #[macro_export] attribute +3. Be spelled correctly", + "\ +Макрос, указанный для импорта через #[macro_use(macro_name)], не найден +в импортируемом крейте. Макрос должен: +1. Существовать в крейте +2. Быть экспортирован с атрибутом #[macro_export] +3. Быть написан правильно", + "\ +#[macro_use(macro_name)]를 통해 임포트하려는 매크로를 임포트된 +크레이트에서 찾을 수 없습니다. 매크로는: +1. 크레이트에 존재해야 함 +2. #[macro_export] 속성으로 익스포트되어야 함 +3. 올바르게 철자되어야 함" + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Verify macro is exported in the crate", + "Проверить, что макрос экспортирован в крейте", + "매크로가 크레이트에서 익스포트되었는지 확인" + ), + code: "// In some_crate:\n#[macro_export]\nmacro_rules! my_macro { ... }\n\n// In your crate:\n#[macro_use(my_macro)]\nextern crate some_crate;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0469.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0517.rs b/masterror-knowledge/src/errors/attributes/e0517.rs new file mode 100644 index 0000000..8bf46df --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0517.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0517: repr attribute on unsupported item + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0517", + title: LocalizedText::new( + "`#[repr(..)]` attribute on unsupported item", + "Атрибут `#[repr(..)]` на неподдерживаемом элементе", + "지원되지 않는 항목에 `#[repr(..)]` 속성" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `#[repr(..)]` attribute was placed on an unsupported item. Each +representation attribute only works with specific item types: + +- `#[repr(C)]`: Only structs and enums +- `#[repr(packed)]` and `#[repr(simd)]`: Only structs +- `#[repr(u8)]`, `#[repr(i16)]`, etc.: Only field-less enums + +These attributes cannot be applied to type aliases or impl blocks.", + "\ +Атрибут `#[repr(..)]` был помещён на неподдерживаемый элемент. Каждый +атрибут представления работает только с определёнными типами элементов: + +- `#[repr(C)]`: Только структуры и перечисления +- `#[repr(packed)]` и `#[repr(simd)]`: Только структуры +- `#[repr(u8)]`, `#[repr(i16)]` и т.д.: Только перечисления без полей", + "\ +`#[repr(..)]` 속성이 지원되지 않는 항목에 배치되었습니다. 각 표현 속성은 +특정 항목 타입에서만 작동합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Apply repr(C) to struct or enum", + "Применить repr(C) к структуре или перечислению", + "repr(C)를 구조체 또는 열거형에 적용" + ), + code: "#[repr(C)]\nstruct Foo { bar: bool }" + }, + FixSuggestion { + description: LocalizedText::new( + "Apply repr(u8) to field-less enum", + "Применить repr(u8) к перечислению без полей", + "repr(u8)를 필드 없는 열거형에 적용" + ), + code: "#[repr(u8)]\nenum Color { Red, Green, Blue }" + } + ], + links: &[ + DocLink { + title: "Alternative Representations", + url: "https://doc.rust-lang.org/nomicon/other-reprs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0517.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0518.rs b/masterror-knowledge/src/errors/attributes/e0518.rs new file mode 100644 index 0000000..f658c6a --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0518.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0518: inline attribute incorrectly placed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0518", + title: LocalizedText::new( + "`#[inline(..)]` attribute incorrectly placed", + "Атрибут `#[inline(..)]` неправильно размещён", + "`#[inline(..)]` 속성이 잘못 배치됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An `#[inline(..)]` attribute was incorrectly placed on something other than a +function or method. The `#[inline]` attribute can only be applied to functions +and methods. + +It supports the following forms: +- `#[inline]` - hint to inline +- `#[inline(always)]` - force inlining +- `#[inline(never)]` - prevent inlining + +Note: This error code is no longer emitted by the compiler.", + "\ +Атрибут `#[inline(..)]` был неправильно размещён на чём-то, кроме функции +или метода. Атрибут `#[inline]` можно применять только к функциям и методам. + +Примечание: этот код ошибки больше не выдаётся компилятором.", + "\ +`#[inline(..)]` 속성이 함수나 메서드가 아닌 다른 것에 잘못 배치되었습니다. +`#[inline]` 속성은 함수와 메서드에만 적용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Apply inline to individual methods", + "Применить inline к отдельным методам", + "개별 메서드에 inline 적용" + ), + code: "impl Foo {\n #[inline(always)]\n fn method1() { }\n \n #[inline(never)]\n fn method2() { }\n}" + }], + links: &[ + DocLink { + title: "Inline Attribute", + url: "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0518.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0522.rs b/masterror-knowledge/src/errors/attributes/e0522.rs new file mode 100644 index 0000000..0fe14cc --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0522.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0522: lang attribute used in invalid context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0522", + title: LocalizedText::new( + "Unknown or invalid lang item", + "Неизвестный или недопустимый lang элемент", + "알 수 없거나 잘못된 lang 항목" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `#[lang]` attribute was used in an invalid context. This attribute is +intended exclusively for marking special items that are built-in to Rust, +including: + +- Special traits that affect compiler behavior (e.g., `Copy`, `Sized`) +- Special functions that may be automatically invoked (e.g., panic handlers) + +Using the `#[lang]` attribute with unknown or invalid lang items will result +in this error.", + "\ +Атрибут `#[lang]` был использован в недопустимом контексте. Этот атрибут +предназначен исключительно для пометки специальных элементов, встроенных +в Rust, включая: + +- Специальные трейты, влияющие на поведение компилятора +- Специальные функции, которые могут автоматически вызываться", + "\ +`#[lang]` 속성이 잘못된 컨텍스트에서 사용되었습니다. 이 속성은 Rust에 +내장된 특수 항목을 표시하기 위해서만 사용됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Only use valid compiler-recognized lang items", + "Использовать только допустимые lang элементы", + "유효한 컴파일러 인식 lang 항목만 사용" + ), + code: "// Don't use #[lang] with custom names\n// This is for internal compiler use only" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0522.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0536.rs b/masterror-knowledge/src/errors/attributes/e0536.rs new file mode 100644 index 0000000..9a955dd --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0536.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0536: malformed not cfg-predicate + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0536", + title: LocalizedText::new( + "The `not` cfg-predicate was malformed", + "cfg-предикат `not` был неправильно сформирован", + "`not` cfg 술어가 잘못 형성됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `not` cfg-predicate was malformed. The `not` predicate is used in +conditional compilation attributes and must be properly formatted. It expects +exactly one cfg-pattern as its argument. + +The `not()` cannot be empty - it requires a cfg-pattern argument.", + "\ +cfg-предикат `not` был неправильно сформирован. Предикат `not` используется +в атрибутах условной компиляции и должен быть правильно отформатирован. +Он ожидает ровно один cfg-шаблон в качестве аргумента.", + "\ +`not` cfg 술어가 잘못 형성되었습니다. `not` 술어는 조건부 컴파일 속성에서 +사용되며 올바르게 형식화되어야 합니다. 인수로 정확히 하나의 cfg 패턴이 +필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Provide a cfg-pattern inside not()", + "Указать cfg-шаблон внутри not()", + "not() 내부에 cfg 패턴 제공" + ), + code: "#[cfg(not(target_os = \"linux\"))]\npub fn main() { }" + }], + links: &[ + DocLink { + title: "Conditional Compilation", + url: "https://doc.rust-lang.org/reference/conditional-compilation.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0536.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0537.rs b/masterror-knowledge/src/errors/attributes/e0537.rs new file mode 100644 index 0000000..53f9c49 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0537.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0537: unknown predicate in cfg attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0537", + title: LocalizedText::new( + "Unknown predicate in `cfg` attribute", + "Неизвестный предикат в атрибуте `cfg`", + "`cfg` 속성에 알 수 없는 술어" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unknown predicate was used inside the `cfg` attribute. The `cfg` attribute +only supports three specific predicate types: +- `any` +- `all` +- `not` + +Using any other predicate name will result in an error.", + "\ +Неизвестный предикат был использован внутри атрибута `cfg`. Атрибут `cfg` +поддерживает только три типа предикатов: +- `any` +- `all` +- `not` + +Использование любого другого имени предиката приведёт к ошибке.", + "\ +`cfg` 속성 내부에서 알 수 없는 술어가 사용되었습니다. `cfg` 속성은 +세 가지 특정 술어 타입만 지원합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use valid cfg predicates: any, all, not", + "Использовать допустимые cfg предикаты: any, all, not", + "유효한 cfg 술어 사용: any, all, not" + ), + code: "#[cfg(not(target_os = \"linux\"))]\npub fn something() {}" + }], + links: &[ + DocLink { + title: "Conditional Compilation", + url: "https://doc.rust-lang.org/reference/conditional-compilation.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0537.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0538.rs b/masterror-knowledge/src/errors/attributes/e0538.rs new file mode 100644 index 0000000..1eb4e5b --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0538.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0538: duplicate meta item in attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0538", + title: LocalizedText::new( + "Duplicate meta item in attribute", + "Дублирующийся мета-элемент в атрибуте", + "속성에 중복된 메타 항목" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An attribute contains the same meta item more than once. Meta items are the +key-value pairs inside of an attribute, and each key may only be used once +in each attribute. + +If you specify the same meta item key multiple times, the compiler will raise +this error.", + "\ +Атрибут содержит один и тот же мета-элемент более одного раза. Мета-элементы - +это пары ключ-значение внутри атрибута, и каждый ключ может использоваться +только один раз в каждом атрибуте.", + "\ +속성에 동일한 메타 항목이 두 번 이상 포함되어 있습니다. 메타 항목은 +속성 내부의 키-값 쌍이며, 각 키는 각 속성에서 한 번만 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove duplicate meta items", + "Удалить дублирующиеся мета-элементы", + "중복된 메타 항목 제거" + ), + code: "#[deprecated(\n since=\"1.0.0\",\n note=\"First note only.\"\n)]\nfn deprecated_function() {}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0538.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0539.rs b/masterror-knowledge/src/errors/attributes/e0539.rs new file mode 100644 index 0000000..82750f2 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0539.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0539: invalid meta-item in attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0539", + title: LocalizedText::new( + "Invalid meta-item in attribute", + "Недопустимый мета-элемент в атрибуте", + "속성에 잘못된 메타 항목" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An invalid meta-item was used inside an attribute. This can happen when: + +1. Using `name = value` when a list is expected (e.g., `#[repr = \"C\"]`) +2. Using a list instead of `name = value` (e.g., `note(\"reason\")`) +3. Missing required values (e.g., `issue` without a value) +4. Providing unrecognized identifiers where specific keywords are required + +Review the attribute's documentation to ensure correct syntax.", + "\ +Недопустимый мета-элемент был использован внутри атрибута. Это может +произойти, когда: + +1. Используется `name = value` вместо списка +2. Используется список вместо `name = value` +3. Отсутствуют обязательные значения +4. Предоставлены нераспознанные идентификаторы", + "\ +속성 내부에서 잘못된 메타 항목이 사용되었습니다. 다음과 같은 경우에 +발생할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use correct syntax for repr attribute", + "Использовать правильный синтаксис для атрибута repr", + "repr 속성에 올바른 구문 사용" + ), + code: "#[repr(C)] // not #[repr = \"C\"]\nstruct Foo {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use name = value for deprecated note", + "Использовать name = value для note в deprecated", + "deprecated note에 name = value 사용" + ), + code: "#[deprecated(since = \"1.0.0\", note = \"reason\")]\nfn foo() {}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0539.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0541.rs b/masterror-knowledge/src/errors/attributes/e0541.rs new file mode 100644 index 0000000..9e11994 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0541.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0541: unknown meta item in attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0541", + title: LocalizedText::new( + "Unknown meta item in attribute", + "Неизвестный мета-элемент в атрибуте", + "속성에 알 수 없는 메타 항목" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unknown meta item was used in an attribute. Meta items are the key-value +pairs inside of attributes, and the keys provided must be one of the valid +keys for the specified attribute. + +Either remove the unknown meta item, or rename it to a correct one.", + "\ +Неизвестный мета-элемент был использован в атрибуте. Мета-элементы - это +пары ключ-значение внутри атрибутов, и предоставленные ключи должны быть +одним из допустимых ключей для указанного атрибута.", + "\ +속성에서 알 수 없는 메타 항목이 사용되었습니다. 메타 항목은 속성 내부의 +키-값 쌍이며, 제공된 키는 지정된 속성에 대한 유효한 키 중 하나여야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use correct meta item key (e.g., `note` not `reason`)", + "Использовать правильный ключ (например, `note` вместо `reason`)", + "올바른 메타 항목 키 사용 (예: `reason`이 아닌 `note`)" + ), + code: "#[deprecated(\n since=\"1.0.0\",\n note=\"explanation\" // not 'reason'\n)]\nfn deprecated_function() {}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0541.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0552.rs b/masterror-knowledge/src/errors/attributes/e0552.rs new file mode 100644 index 0000000..c26af87 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0552.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0552: unrecognized representation hint + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0552", + title: LocalizedText::new( + "Unrecognized representation hint", + "Нераспознанный атрибут представления", + "인식할 수 없는 표현 힌트" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unrecognized representation attribute was used. The `#[repr(...)]` +attribute is used to specify how the compiler should lay out a struct or enum +in memory. Only certain values are recognized. + +The `repr` attribute supports options like `C`, `transparent`, `packed`, +`align(N)`, and integer types like `u8`, `i32`, etc.", + "\ +Был использован нераспознанный атрибут представления. Атрибут `#[repr(...)]` +используется для указания, как компилятор должен размещать структуру или +перечисление в памяти. Распознаются только определённые значения.", + "\ +인식할 수 없는 표현 속성이 사용되었습니다. `#[repr(...)]` 속성은 컴파일러가 +구조체나 열거형을 메모리에 어떻게 배치해야 하는지 지정하는 데 사용됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a valid repr option", + "Использовать допустимую опцию repr", + "유효한 repr 옵션 사용" + ), + code: "#[repr(C)] // valid options: C, transparent, packed, align(N)\nstruct MyStruct {\n my_field: usize\n}" + }], + links: &[ + DocLink { + title: "Alternative Representations", + url: "https://doc.rust-lang.org/nomicon/other-reprs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0552.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0554.rs b/masterror-knowledge/src/errors/attributes/e0554.rs new file mode 100644 index 0000000..3ed7885 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0554.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0554: feature attributes require nightly + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0554", + title: LocalizedText::new( + "Feature attributes require nightly compiler", + "Атрибуты feature требуют nightly компилятор", + "기능 속성은 나이틀리 컴파일러 필요" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Feature attributes (using `#![feature(...)]`) can only be used when compiling +with the Rust nightly compiler. Stable or beta compilers will reject code +containing feature attributes, as they are experimental features that may +change or be removed in future releases. + +This error enforces Rust's stability guarantee by preventing unstable features +from being used in code compiled with stable or beta toolchains.", + "\ +Атрибуты feature (с использованием `#![feature(...)]`) могут использоваться +только при компиляции с nightly компилятором Rust. Стабильные или бета +компиляторы отклонят код с атрибутами feature, так как это экспериментальные +функции, которые могут измениться или быть удалены.", + "\ +기능 속성(`#![feature(...)]` 사용)은 Rust 나이틀리 컴파일러로 컴파일할 때만 +사용할 수 있습니다. 안정 또는 베타 컴파일러는 기능 속성이 포함된 코드를 +거부합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Switch to nightly Rust to use unstable features", + "Переключиться на nightly Rust для использования нестабильных функций", + "불안정 기능을 사용하려면 나이틀리 Rust로 전환" + ), + code: "// Run: rustup default nightly\n// Or: rustup run nightly cargo build" + }, + FixSuggestion { + description: LocalizedText::new( + "Remove the feature attribute for stable Rust", + "Удалить атрибут feature для стабильного Rust", + "안정 Rust를 위해 기능 속성 제거" + ), + code: "// Remove: #![feature(lang_items)]\n// Use stable alternatives instead" + } + ], + links: &[ + DocLink { + title: "Nightly Rust", + url: "https://doc.rust-lang.org/book/appendix-07-nightly-rust.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0554.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0556.rs b/masterror-knowledge/src/errors/attributes/e0556.rs new file mode 100644 index 0000000..2d56ee5 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0556.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0556: malformed feature attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0556", + title: LocalizedText::new( + "The `feature` attribute was malformed", + "Атрибут `feature` был неправильно сформирован", + "`feature` 속성이 잘못 형성됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `feature` attribute must be properly formatted. It only accepts feature +flag identifiers and can only be used on nightly Rust. + +Invalid syntax includes: +- Parenthesized expressions: `foo(bar)` +- Assignment syntax: `foo = \"baz\"` +- Duplicate flags +- Empty attribute: `#![feature]` +- String assignment: `#![feature = \"foo\"]`", + "\ +Атрибут `feature` должен быть правильно отформатирован. Он принимает только +идентификаторы флагов функций и может использоваться только в nightly Rust. + +Недопустимый синтаксис включает: +- Выражения в скобках: `foo(bar)` +- Синтаксис присваивания: `foo = \"baz\"` +- Дублирующиеся флаги", + "\ +`feature` 속성은 올바르게 형식화되어야 합니다. 기능 플래그 식별자만 허용하며 +나이틀리 Rust에서만 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use correct feature attribute syntax", + "Использовать правильный синтаксис атрибута feature", + "올바른 feature 속성 구문 사용" + ), + code: "#![feature(flag)]\n#![feature(flag1, flag2)] // multiple flags" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0556.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0557.rs b/masterror-knowledge/src/errors/attributes/e0557.rs new file mode 100644 index 0000000..8c3a408 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0557.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0557: feature has been removed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0557", + title: LocalizedText::new( + "Feature has been removed", + "Функция была удалена", + "기능이 제거됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A feature attribute named a feature that has been removed from Rust. Feature +gates are unstable Rust features that may be removed in future versions. + +When a feature is removed, any code using `#![feature(...)]` with that feature +name will fail to compile.", + "\ +Атрибут feature указал функцию, которая была удалена из Rust. Feature gates - +это нестабильные функции Rust, которые могут быть удалены в будущих версиях. + +Когда функция удаляется, любой код, использующий `#![feature(...)]` с этим +именем функции, не скомпилируется.", + "\ +기능 속성이 Rust에서 제거된 기능을 명명했습니다. 기능 게이트는 향후 버전에서 +제거될 수 있는 불안정한 Rust 기능입니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove the obsolete feature attribute", + "Удалить устаревший атрибут feature", + "사용되지 않는 기능 속성 제거" + ), + code: "// Remove: #![feature(managed_boxes)]\n// This feature no longer exists" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0557.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0565.rs b/masterror-knowledge/src/errors/attributes/e0565.rs new file mode 100644 index 0000000..d55d5f8 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0565.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0565: literal used in attribute that doesn't support literals + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0565", + title: LocalizedText::new( + "Literal used in attribute that doesn't support literals", + "Литерал использован в атрибуте, не поддерживающем литералы", + "리터럴을 지원하지 않는 속성에서 리터럴 사용" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A literal was used in a built-in attribute that doesn't support literals. +Not all attributes support literals in their input - some specifically require +identifiers. + +For example, `#[repr(\"C\")]` is incorrect because `repr` expects an +identifier, not a string literal.", + "\ +Литерал был использован во встроенном атрибуте, который не поддерживает +литералы. Не все атрибуты поддерживают литералы во входных данных - некоторые +требуют именно идентификаторы.", + "\ +리터럴을 지원하지 않는 내장 속성에서 리터럴이 사용되었습니다. 모든 속성이 +입력에서 리터럴을 지원하는 것은 아니며, 일부는 특별히 식별자를 요구합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use an identifier instead of a string literal", + "Использовать идентификатор вместо строкового литерала", + "문자열 리터럴 대신 식별자 사용" + ), + code: "#[repr(C)] // not #[repr(\"C\")]\nstruct Repr {}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0565.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0566.rs b/masterror-knowledge/src/errors/attributes/e0566.rs new file mode 100644 index 0000000..79c0113 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0566.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0566: conflicting representation hints + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0566", + title: LocalizedText::new( + "Conflicting representation hints", + "Конфликтующие атрибуты представления", + "충돌하는 표현 힌트" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Conflicting representation hints have been used on the same item. In most +cases, only one representation hint is needed. + +For example, `#[repr(u32, u64)]` is invalid because you cannot specify +multiple conflicting integer representation hints on the same enum.", + "\ +Конфликтующие атрибуты представления были использованы для одного элемента. +В большинстве случаев нужен только один атрибут представления. + +Например, `#[repr(u32, u64)]` недопустим, поскольку нельзя указать +несколько конфликтующих целочисленных представлений для одного перечисления.", + "\ +동일한 항목에 충돌하는 표현 힌트가 사용되었습니다. 대부분의 경우 +하나의 표현 힌트만 필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use cfg_attr for conditional repr", + "Использовать cfg_attr для условного repr", + "조건부 repr를 위해 cfg_attr 사용" + ), + code: "#[cfg_attr(linux, repr(u32))]\n#[cfg_attr(not(linux), repr(u64))]\nenum Repr { A }" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0566.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0587.rs b/masterror-knowledge/src/errors/attributes/e0587.rs new file mode 100644 index 0000000..2574711 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0587.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0587: packed and align on same type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0587", + title: LocalizedText::new( + "Cannot use both `packed` and `align` on same type", + "Нельзя использовать `packed` и `align` для одного типа", + "같은 타입에 `packed`와 `align`을 모두 사용할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type has both `packed` and `align` representation hints. You cannot use both +on the same type because they provide conflicting layout specifications. + +`packed` removes padding between fields to minimize size, while `align` +specifies a minimum alignment requirement.", + "\ +Тип имеет оба атрибута представления `packed` и `align`. Нельзя использовать +оба для одного типа, поскольку они задают конфликтующие спецификации +размещения. + +`packed` удаляет отступы между полями, а `align` указывает минимальное +требование выравнивания.", + "\ +타입에 `packed`와 `align` 표현 힌트가 모두 있습니다. 이들은 충돌하는 +레이아웃 사양을 제공하므로 같은 타입에 둘 다 사용할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use packed(N) to specify both packing and size", + "Использовать packed(N) для указания упаковки и размера", + "패킹과 크기를 지정하려면 packed(N) 사용" + ), + code: "#[repr(packed(8))] // not #[repr(packed, align(8))]\nstruct Umbrella(i32);" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0587.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0588.rs b/masterror-knowledge/src/errors/attributes/e0588.rs new file mode 100644 index 0000000..3d84d45 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0588.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0588: packed type contains aligned field + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0588", + title: LocalizedText::new( + "Packed type contains a field with align repr", + "Упакованный тип содержит поле с атрибутом align", + "패킹된 타입에 align repr이 있는 필드 포함" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type with `packed` representation hint has a field with the `align` +representation hint. These are incompatible when nested in this direction. + +However, the reverse is allowed: an `align` type can contain a `packed` type.", + "\ +Тип с атрибутом представления `packed` содержит поле с атрибутом `align`. +Эти атрибуты несовместимы при таком вложении. + +Однако обратное допустимо: тип с `align` может содержать тип с `packed`.", + "\ +`packed` 표현 힌트가 있는 타입에 `align` 표현 힌트가 있는 필드가 있습니다. +이 방향의 중첩에서는 호환되지 않습니다. + +그러나 반대는 허용됩니다: `align` 타입은 `packed` 타입을 포함할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Reverse the nesting: align can contain packed", + "Изменить вложение: align может содержать packed", + "중첩 반전: align이 packed를 포함할 수 있음" + ), + code: "#[repr(packed)]\nstruct Packed(i32);\n\n#[repr(align(16))] // align can wrap packed\nstruct Aligned(Packed);" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0588.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0589.rs b/masterror-knowledge/src/errors/attributes/e0589.rs new file mode 100644 index 0000000..a9d10ef --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0589.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0589: invalid repr(align) attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0589", + title: LocalizedText::new( + "Invalid `repr(align)`: not a power of two", + "Недопустимый `repr(align)`: не степень двойки", + "잘못된 `repr(align)`: 2의 거듭제곱이 아님" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The value of N specified for `repr(align(N))` must be a power of two and +cannot exceed 2^29. If you provide a value that doesn't meet these +requirements, the compiler will raise this error. + +Valid alignment values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, etc.", + "\ +Значение N, указанное для `repr(align(N))`, должно быть степенью двойки +и не может превышать 2^29. Если вы укажете значение, не соответствующее +этим требованиям, компилятор выдаст эту ошибку. + +Допустимые значения выравнивания: 1, 2, 4, 8, 16, 32, 64, 128, 256 и т.д.", + "\ +`repr(align(N))`에 지정된 N 값은 2의 거듭제곱이어야 하며 2^29를 초과할 수 +없습니다. 이러한 요구 사항을 충족하지 않는 값을 제공하면 컴파일러가 +이 오류를 발생시킵니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a power of two for alignment", + "Использовать степень двойки для выравнивания", + "정렬에 2의 거듭제곱 사용" + ), + code: "#[repr(align(16))] // not align(15)\nenum Foo { Bar(u64) }" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0589.html" + }] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0701.rs b/masterror-knowledge/src/errors/attributes/e0701.rs new file mode 100644 index 0000000..adf0d5f --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0701.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0701: #[non_exhaustive] misplaced (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0701", + title: LocalizedText::new( + "Non-exhaustive attribute misplaced", + "Атрибут non_exhaustive в неправильном месте", + "non_exhaustive 속성 잘못된 위치" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler. + +Previously, the `#[non_exhaustive]` attribute was incorrectly placed on +something other than a struct or enum. This attribute can only be applied +to structs and enums.", + "\ +Примечание: Эта ошибка больше не выдаётся компилятором. + +Атрибут `#[non_exhaustive]` может применяться только к структурам и enum.", + "\ +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Apply to struct or enum only", + "Применяйте только к struct или enum", + "struct 또는 enum에만 적용" + ), + code: "#[non_exhaustive]\nstruct Config {\n field: u32,\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0701.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0710.rs b/masterror-knowledge/src/errors/attributes/e0710.rs new file mode 100644 index 0000000..7df5952 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0710.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0710: unknown tool name in scoped lint + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0710", + title: LocalizedText::new( + "Unknown tool name in scoped lint", + "Неизвестное имя инструмента в lint", + "스코프 lint에서 알 수 없는 도구 이름" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +An unknown tool name was found in a scoped lint attribute. + +This typically happens when you misspell a linter tool name (such as `clippy`) +or forget to import it in your project.", + "\ +В атрибуте lint найдено неизвестное имя инструмента. + +Обычно это происходит при опечатке в имени линтера (например, `clippy`).", + "\ +스코프 lint 속성에서 알 수 없는 도구 이름이 발견되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Fix the tool name spelling", + "Исправьте написание имени инструмента", + "도구 이름 철자 수정" + ), + code: "#[allow(clippy::filter_map)] // correct spelling" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0710.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0714.rs b/masterror-knowledge/src/errors/attributes/e0714.rs new file mode 100644 index 0000000..0cb96ec --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0714.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0714: marker trait with associated items + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0714", + title: LocalizedText::new( + "Marker trait with associated items", + "Маркерный трейт с ассоциированными элементами", + "연관 항목이 있는 마커 트레이트" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A `#[marker]` trait contained an associated item. + +Marker traits cannot have associated items like constants, because the items +of marker traits cannot be overridden, making them unnecessary when they +cannot be changed per-type anyway.", + "\ +Маркерный трейт `#[marker]` содержит ассоциированный элемент. + +Маркерные трейты не могут иметь ассоциированных элементов, так как +их нельзя переопределить.", + "\ +`#[marker]` 트레이트에 연관 항목이 포함되었습니다. + +마커 트레이트는 연관 항목을 가질 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use extension trait for associated items", + "Используйте расширяющий трейт для элементов", + "연관 항목에 확장 트레이트 사용" + ), + code: "#[marker]\ntrait Marker {}\n\ntrait MarkerExt: Marker {\n const N: usize;\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0714.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0715.rs b/masterror-knowledge/src/errors/attributes/e0715.rs new file mode 100644 index 0000000..f438150 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0715.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0715: marker trait impl overrides associated item + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0715", + title: LocalizedText::new( + "Marker trait impl overrides item", + "Реализация маркерного трейта переопределяет элемент", + "마커 트레이트 impl이 항목 재정의" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +An `impl` for a `#[marker]` trait tried to override an associated item. + +Marker traits are allowed to have multiple implementations for the same type, +so it is not permitted to override anything in those implementations, as it +would be ambiguous which override should actually be used.", + "\ +Реализация `#[marker]` трейта пытается переопределить ассоциированный элемент. + +Маркерные трейты могут иметь несколько реализаций для одного типа, +поэтому переопределение запрещено из-за неоднозначности.", + "\ +`#[marker]` 트레이트의 `impl`이 연관 항목을 재정의하려 했습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove override from impl", + "Удалите переопределение из impl", + "impl에서 재정의 제거" + ), + code: "#[marker]\ntrait Marker {\n const N: usize = 0;\n}\n\nimpl Marker for MyType {} // no override" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0715.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0722.rs b/masterror-knowledge/src/errors/attributes/e0722.rs new file mode 100644 index 0000000..849ca76 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0722.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0722: malformed optimize attribute (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0722", + title: LocalizedText::new( + "Malformed optimize attribute", + "Неправильный атрибут optimize", + "잘못된 optimize 속성" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler (now E0539). + +The `#[optimize]` attribute was malformed. Valid arguments are: +- `#[optimize(size)]` - generate smaller code +- `#[optimize(speed)]` - generate faster code", + "\ +Примечание: Эта ошибка больше не выдаётся (теперь E0539). + +Атрибут `#[optimize]` был неправильно сформирован.", + "\ +참고: 이 오류 코드는 더 이상 발생하지 않습니다 (현재 E0539)." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use valid optimize argument", + "Используйте допустимый аргумент optimize", + "유효한 optimize 인수 사용" + ), + code: "#[optimize(size)]\npub fn small_fn() {}" + } + ], + links: &[ + DocLink { + title: "RFC 2412", + url: "https://rust-lang.github.io/rfcs/2412-optimize-attr.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0725.rs b/masterror-knowledge/src/errors/attributes/e0725.rs new file mode 100644 index 0000000..525e0fc --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0725.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0725: feature not in allowed list + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0725", + title: LocalizedText::new( + "Feature not in allowed list", + "Функция не в списке разрешённых", + "허용 목록에 없는 기능" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A feature attribute named a feature that was disallowed in the compiler +command line flags via `-Z allow_features`. + +The specified feature is not in the allowed features list.", + "\ +Атрибут feature указывает функцию, запрещённую флагами командной строки +компилятора через `-Z allow_features`.", + "\ +기능 속성이 `-Z allow_features`를 통해 컴파일러 명령줄 플래그에서 +허용되지 않은 기능을 지정했습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove disallowed feature or add to allow list", + "Удалите запрещённую функцию или добавьте в список", + "허용되지 않은 기능 제거 또는 목록에 추가" + ), + code: "// Remove: #![feature(disallowed_feature)]\n// Or add to -Z allow_features" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0725.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0734.rs b/masterror-knowledge/src/errors/attributes/e0734.rs new file mode 100644 index 0000000..e8902eb --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0734.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0734: stability attribute outside stdlib + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0734", + title: LocalizedText::new( + "Stability attribute outside standard library", + "Атрибут стабильности вне стандартной библиотеки", + "표준 라이브러리 외부의 안정성 속성" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A stability attribute (`#[stable]` or `#[unstable]`) has been used outside +of the standard library. + +These attributes are meant to only be used by the standard library and are +rejected in your own crates.", + "\ +Атрибут стабильности (`#[stable]` или `#[unstable]`) использован +вне стандартной библиотеки. + +Эти атрибуты предназначены только для стандартной библиотеки.", + "\ +안정성 속성(`#[stable]` 또는 `#[unstable]`)이 표준 라이브러리 +외부에서 사용되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove stability attributes", + "Удалите атрибуты стабильности", + "안정성 속성 제거" + ), + code: "// Instead of:\n// #[stable(feature = \"a\", since = \"1.0\")]\nfn foo() {}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0734.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0736.rs b/masterror-knowledge/src/errors/attributes/e0736.rs new file mode 100644 index 0000000..c115781 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0736.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0736: naked function incompatible attributes + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0736", + title: LocalizedText::new( + "Naked function with incompatible attribute", + "Naked функция с несовместимым атрибутом", + "호환되지 않는 속성이 있는 naked 함수" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +Functions marked with `#[naked]` are restricted in what other attributes +they may be marked with. Incompatible attributes include: +- `#[inline]` +- `#[track_caller]` +- `#[test]`, `#[ignore]`, `#[should_panic]` + +These incompatibilities exist because naked functions deliberately impose +strict restrictions on the code that the compiler produces.", + "\ +Функции с `#[naked]` имеют ограничения на другие атрибуты. +Несовместимы: `#[inline]`, `#[track_caller]`, `#[test]`.", + "\ +`#[naked]`로 표시된 함수는 다른 속성에 제한이 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove incompatible attributes", + "Удалите несовместимые атрибуты", + "호환되지 않는 속성 제거" + ), + code: "#[unsafe(naked)]\npub extern \"C\" fn foo() {\n // naked_asm!(...)\n}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0736.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0774.rs b/masterror-knowledge/src/errors/attributes/e0774.rs new file mode 100644 index 0000000..583f909 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0774.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0774: derive on invalid target + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0774", + title: LocalizedText::new( + "Derive applied to invalid target", + "Derive применён к неподходящему элементу", + "잘못된 대상에 derive 적용" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +The `derive` attribute was applied on something which is not a struct, union, +or enum. The `derive` attribute is only allowed on these three item types.", + "\ +Атрибут `derive` применён к элементу, который не является структурой, +объединением или перечислением. `derive` допустим только для них.", + "\ +`derive` 속성이 struct, union, enum이 아닌 것에 적용되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Apply derive to struct, enum, or union", + "Применяйте derive к struct, enum или union", + "struct, enum, union에 derive 적용" + ), + code: "#[derive(Clone)]\nstruct Bar {\n field: u32,\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Derivable Traits", + url: "https://doc.rust-lang.org/book/appendix-03-derivable-traits.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0774.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0777.rs b/masterror-knowledge/src/errors/attributes/e0777.rs new file mode 100644 index 0000000..4de7350 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0777.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0777: literal in derive + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0777", + title: LocalizedText::new( + "Literal value in derive", + "Литеральное значение в derive", + "derive에 리터럴 값" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A literal value (like a string) was used inside `#[derive]` instead of a +path to a trait. + +The `#[derive]` attribute only accepts trait paths as arguments, not string +literals or other literal values.", + "\ +В `#[derive]` использовано литеральное значение (например, строка) +вместо пути к трейту. + +`#[derive]` принимает только пути к трейтам.", + "\ +`#[derive]`에 트레이트 경로 대신 리터럴 값이 사용되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove quotes from trait name", + "Удалите кавычки из имени трейта", + "트레이트 이름에서 따옴표 제거" + ), + code: "#[derive(Clone)] // not \"Clone\"\nstruct Foo;" + } + ], + links: &[ + DocLink { + title: "Rust Book: Derivable Traits", + url: "https://doc.rust-lang.org/book/appendix-03-derivable-traits.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0777.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0778.rs b/masterror-knowledge/src/errors/attributes/e0778.rs new file mode 100644 index 0000000..edca93e --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0778.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0778: malformed instruction_set attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0778", + title: LocalizedText::new( + "Malformed instruction_set attribute", + "Неправильный атрибут instruction_set", + "잘못된 instruction_set 속성" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +The `instruction_set` attribute was malformed. This attribute requires +exactly one argument specifying the instruction set architecture.", + "\ +Атрибут `instruction_set` неправильно сформирован. +Он требует ровно один аргумент, указывающий архитектуру.", + "\ +`instruction_set` 속성이 잘못되었습니다. +명령어 집합 아키텍처를 지정하는 인수가 필요합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Provide instruction set argument", + "Укажите аргумент набора инструкций", + "명령어 집합 인수 제공" + ), + code: "#[cfg_attr(target_arch=\"arm\", instruction_set(arm::a32))]\nfn something() {}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Codegen Attributes", + url: "https://doc.rust-lang.org/reference/attributes/codegen.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0779.rs b/masterror-knowledge/src/errors/attributes/e0779.rs new file mode 100644 index 0000000..15156d2 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0779.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0779: unknown instruction_set argument + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0779", + title: LocalizedText::new( + "Unknown instruction_set argument", + "Неизвестный аргумент instruction_set", + "알 수 없는 instruction_set 인수" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +An unknown argument was given to the `instruction_set` attribute. + +Currently supported arguments are: +- `arm::a32` +- `arm::t32`", + "\ +В атрибут `instruction_set` передан неизвестный аргумент. + +Поддерживаемые аргументы: `arm::a32`, `arm::t32`.", + "\ +`instruction_set` 속성에 알 수 없는 인수가 전달되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use valid instruction set", + "Используйте допустимый набор инструкций", + "유효한 명령어 집합 사용" + ), + code: "#[cfg_attr(target_arch=\"arm\", instruction_set(arm::a32))]\npub fn something() {}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Codegen Attributes", + url: "https://doc.rust-lang.org/reference/attributes/codegen.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0780.rs b/masterror-knowledge/src/errors/attributes/e0780.rs new file mode 100644 index 0000000..c8e66e7 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0780.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0780: doc(inline) with anonymous import + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0780", + title: LocalizedText::new( + "Cannot use doc(inline) with anonymous imports", + "Нельзя использовать doc(inline) с анонимным импортом", + "익명 임포트와 doc(inline) 사용 불가" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +The `#[doc(inline)]` attribute was applied to an anonymous import (using `as _`). + +Anonymous imports are always rendered with `#[doc(no_inline)]` by default, +making the `#[doc(inline)]` attribute invalid in this context.", + "\ +Атрибут `#[doc(inline)]` применён к анонимному импорту (с `as _`). + +Анонимные импорты всегда отображаются с `#[doc(no_inline)]`.", + "\ +`#[doc(inline)]` 속성이 익명 임포트(`as _` 사용)에 적용되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove doc(inline) attribute", + "Удалите атрибут doc(inline)", + "doc(inline) 속성 제거" + ), + code: "pub use foo::Foo as _; // without #[doc(inline)]" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0780.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0787.rs b/masterror-knowledge/src/errors/attributes/e0787.rs new file mode 100644 index 0000000..99797ae --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0787.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0787: unsupported naked function definition + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0787", + title: LocalizedText::new( + "Unsupported naked function definition", + "Неподдерживаемое определение naked функции", + "지원되지 않는 naked 함수 정의" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +A naked function was defined incorrectly. Naked functions must follow these rules: +1. Body must contain a single `naked_asm!` block +2. Execution must never fall through past the assembly code +3. Only `att_syntax` and `raw` asm options are allowed +4. Only `const` and `sym` operands are permitted", + "\ +Naked функция определена неправильно. Правила: +1. Тело должно содержать один блок `naked_asm!` +2. Выполнение не должно выходить за пределы ассемблерного кода +3. Только опции `att_syntax` и `raw` +4. Только операнды `const` и `sym`", + "\ +naked 함수가 잘못 정의되었습니다. naked 함수는 다음 규칙을 따라야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use naked_asm! in function body", + "Используйте naked_asm! в теле функции", + "함수 본문에 naked_asm! 사용" + ), + code: "#[unsafe(naked)]\npub extern \"C\" fn foo() {\n naked_asm!(\"ret\");\n}" + } + ], + links: &[ + DocLink { + title: "RFC 2972", + url: "https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md" + } + ] +}; diff --git a/masterror-knowledge/src/errors/attributes/e0788.rs b/masterror-knowledge/src/errors/attributes/e0788.rs new file mode 100644 index 0000000..66470a8 --- /dev/null +++ b/masterror-knowledge/src/errors/attributes/e0788.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0788: coverage attribute in invalid position (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0788", + title: LocalizedText::new( + "Coverage attribute in invalid position", + "Атрибут coverage в неправильном месте", + "잘못된 위치의 coverage 속성" + ), + category: Category::Attributes, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler. + +A `#[coverage(off|on)]` attribute was found in a position where it is not allowed. + +Coverage attributes can be applied to: +- Function and method declarations with a body +- Closure expressions +- `impl` blocks and modules", + "\ +Примечание: Эта ошибка больше не выдаётся компилятором. + +Атрибут `#[coverage]` может применяться к функциям, замыканиям, +блокам impl и модулям.", + "\ +참고: 이 오류 코드는 더 이상 발생하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Apply coverage to valid items", + "Применяйте coverage к допустимым элементам", + "유효한 항목에 coverage 적용" + ), + code: "#[coverage(off)]\nfn uncovered_fn() { /* ... */ }" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0788.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/borrowing.rs b/masterror-knowledge/src/errors/borrowing.rs new file mode 100644 index 0000000..4176e11 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing.rs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Borrowing-related errors. + +mod e0499; +mod e0500; +mod e0501; +mod e0502; +mod e0503; +mod e0504; +mod e0506; +mod e0508; +mod e0510; +mod e0521; +mod e0524; +mod e0594; +mod e0596; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0499::ENTRY, + &e0500::ENTRY, + &e0501::ENTRY, + &e0502::ENTRY, + &e0503::ENTRY, + &e0504::ENTRY, + &e0506::ENTRY, + &e0508::ENTRY, + &e0510::ENTRY, + &e0521::ENTRY, + &e0524::ENTRY, + &e0594::ENTRY, + &e0596::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/borrowing/e0499.rs b/masterror-knowledge/src/errors/borrowing/e0499.rs new file mode 100644 index 0000000..b43ca0b --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0499.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0499: cannot borrow as mutable more than once + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0499", + title: LocalizedText::new( + "Cannot borrow as mutable more than once", + "Нельзя заимствовать как изменяемое более одного раза", + "가변으로 두 번 이상 빌릴 수 없음" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +Rust allows only ONE mutable reference to data at a time. This is stricter +than the immutable borrowing rule and prevents all aliased mutation. + +Why? Two mutable references to the same data could lead to: +- Data races in concurrent code +- Iterator invalidation +- Dangling pointers after reallocation + +This rule is checked at compile time, giving you fearless concurrency.", + "\ +Rust разрешает только ОДНУ изменяемую ссылку на данные одновременно. +Это строже правила неизменяемого заимствования. + +Почему? Две изменяемые ссылки на одни данные могут привести к: +- Гонкам данных в конкурентном коде +- Инвалидации итераторов +- Висячим указателям после реаллокации", + "\ +Rust는 데이터에 대해 한 번에 하나의 가변 참조만 허용합니다. +이는 불변 빌림 규칙보다 엄격합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use scopes to limit borrow lifetime", + "Использовать области видимости", + "스코프를 사용하여 빌림 수명 제한" + ), + code: "{ let r1 = &mut x; *r1 += 1; } // r1 dropped\nlet r2 = &mut x;" + }, + FixSuggestion { + description: LocalizedText::new( + "Use RefCell for interior mutability", + "Использовать RefCell", + "내부 가변성을 위해 RefCell 사용" + ), + code: "use std::cell::RefCell;\nlet x = RefCell::new(value);" + } + ], + links: &[ + DocLink { + title: "Rust Book: Mutable References", + url: "https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0499.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0500.rs b/masterror-knowledge/src/errors/borrowing/e0500.rs new file mode 100644 index 0000000..8721f48 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0500.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0500: closure requires unique access but X is already borrowed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0500", + title: LocalizedText::new( + "Closure requires unique access but value is already borrowed", + "Замыкание требует уникальный доступ, но значение уже заимствовано", + "클로저가 고유 접근을 필요로 하지만 값이 이미 빌려짐" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +A closure that mutates a captured variable needs exclusive access to it. +But you've already borrowed the value elsewhere, creating a conflict. + +Closures that capture by mutable reference act like mutable borrows.", + "\ +Замыкание, изменяющее захваченную переменную, требует эксклюзивного доступа.", + "\ +캡처된 변수를 변경하는 클로저는 독점적인 접근이 필요합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "End the borrow before the closure", + "Завершить заимствование перед замыканием", + "클로저 전에 빌림 종료" + ), + code: "{ let r = &x; use(r); }\nlet c = || x += 1;" + }, + FixSuggestion { + description: LocalizedText::new( + "Move the value into the closure", + "Переместить значение в замыкание", + "클로저로 값 이동" + ), + code: "let c = move || { x += 1; };" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0500.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0501.rs b/masterror-knowledge/src/errors/borrowing/e0501.rs new file mode 100644 index 0000000..34298ab --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0501.rs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0501: cannot borrow X as mutable because previous closure requires unique +//! access + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0501", + title: LocalizedText::new( + "Cannot borrow because closure requires unique access", + "Нельзя заимствовать, так как замыкание требует уникальный доступ", + "클로저가 고유 접근을 필요로 하여 빌릴 수 없음" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +A closure has captured a variable mutably, and now you're trying to borrow +that same variable again. The closure's capture acts like a mutable borrow +that lasts for the closure's entire lifetime.", + "\ +Замыкание захватило переменную изменяемо, и теперь вы пытаетесь заимствовать +ту же переменную снова.", + "\ +클로저가 변수를 가변으로 캡처했고, 이제 같은 변수를 다시 빌리려고 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use the closure before borrowing again", + "Использовать замыкание перед повторным заимствованием", + "다시 빌리기 전에 클로저 사용" + ), + code: "let mut c = || x += 1;\nc(); // use closure\nlet r = &x; // now safe" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0501.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0502.rs b/masterror-knowledge/src/errors/borrowing/e0502.rs new file mode 100644 index 0000000..fa372c0 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0502.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0502: cannot borrow as mutable because also borrowed as immutable + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0502", + title: LocalizedText::new( + "Cannot borrow as mutable (already borrowed as immutable)", + "Нельзя заимствовать как изменяемое (уже заимствовано как неизменяемое)", + "가변으로 빌릴 수 없음 (이미 불변으로 빌림)" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +Rust enforces a strict borrowing rule: you can have EITHER one mutable +reference OR any number of immutable references, but never both at once. + +This prevents data races at compile time. If you could mutate data while +someone else is reading it, the reader might see inconsistent state. + +The immutable borrow is still \"active\" because it's used later in code.", + "\ +Rust применяет строгое правило: можно иметь ЛИБО одну изменяемую ссылку, +ЛИБО любое количество неизменяемых, но никогда обе одновременно. + +Это предотвращает гонки данных.", + "\ +Rust는 엄격한 빌림 규칙을 적용합니다: 하나의 가변 참조 또는 여러 불변 참조를 +가질 수 있지만, 동시에 둘 다 가질 수는 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "End the immutable borrow before mutating", + "Завершить неизменяемое заимствование", + "변경 전에 불변 빌림 종료" + ), + code: "{ let r = &x; println!(\"{}\", r); } // r dropped\nx.push(1);" + }, + FixSuggestion { + description: LocalizedText::new( + "Clone before mutation", + "Клонировать перед изменением", + "변경 전에 복제" + ), + code: "let copy = x[0].clone();\nx.push(copy);" + } + ], + links: &[ + DocLink { + title: "Rust Book: References and Borrowing", + url: "https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0502.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0503.rs b/masterror-knowledge/src/errors/borrowing/e0503.rs new file mode 100644 index 0000000..083a5c3 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0503.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0503: cannot use X because it was mutably borrowed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0503", + title: LocalizedText::new( + "Cannot use value because it was mutably borrowed", + "Нельзя использовать значение, так как оно изменяемо заимствовано", + "가변으로 빌려져서 값을 사용할 수 없음" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +While a mutable borrow is active, you cannot access the original value +in any way. This prevents you from observing partially modified state +or creating aliased mutable references. + +The mutable borrow has exclusive access until it ends.", + "\ +Пока активно изменяемое заимствование, вы не можете обращаться к +исходному значению никак.", + "\ +가변 빌림이 활성화된 동안 원래 값에 어떤 방식으로도 접근할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "End the mutable borrow first", + "Сначала завершить изменяемое заимствование", + "먼저 가변 빌림 종료" + ), + code: "{ let r = &mut x; modify(r); } // r dropped\nuse_value(&x);" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0503.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0504.rs b/masterror-knowledge/src/errors/borrowing/e0504.rs new file mode 100644 index 0000000..196ca1c --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0504.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0504: cannot move borrowed variable into closure + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0504", + title: LocalizedText::new( + "Cannot move borrowed value into closure", + "Нельзя переместить заимствованное значение в замыкание", + "빌린 값을 클로저로 이동할 수 없음" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +This error occurs when attempting to move a borrowed variable into a closure +using the `move` keyword. A value cannot be moved into a closure while it is +being borrowed elsewhere, as this would invalidate the existing borrow. + +Note: This error code is no longer emitted by the compiler.", + "\ +Эта ошибка возникает при попытке переместить заимствованную переменную +в замыкание с помощью ключевого слова `move`. Значение нельзя переместить +в замыкание, пока оно заимствовано в другом месте. + +Примечание: этот код ошибки больше не выдаётся компилятором.", + "\ +이 오류는 `move` 키워드를 사용하여 빌린 변수를 클로저로 이동하려고 할 때 발생합니다. +값이 다른 곳에서 빌려진 동안에는 클로저로 이동할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a reference in the closure instead", + "Использовать ссылку в замыкании", + "클로저에서 참조 사용" + ), + code: "let x = move || { println!(\"{}\", fancy_ref.num); };" + }, + FixSuggestion { + description: LocalizedText::new( + "Limit borrow lifetime with a scoped block", + "Ограничить время жизни заимствования блоком", + "스코프 블록으로 빌림 수명 제한" + ), + code: "{ let r = &val; use(r); } // r dropped\nlet x = move || use(val);" + }, + FixSuggestion { + description: LocalizedText::new( + "Use Arc for shared ownership in threads", + "Использовать Arc для разделяемого владения", + "스레드에서 공유 소유권을 위해 Arc 사용" + ), + code: "use std::sync::Arc;\nlet shared = Arc::new(val);\nlet clone = shared.clone();" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0504.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0506.rs b/masterror-knowledge/src/errors/borrowing/e0506.rs new file mode 100644 index 0000000..8c3a482 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0506.rs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0506: cannot assign to X because it is borrowed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0506", + title: LocalizedText::new( + "Cannot assign because it is borrowed", + "Нельзя присвоить, так как значение заимствовано", + "빌려져 있어서 할당할 수 없음" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +You're trying to assign to a value while a borrow of it exists. +This would invalidate the existing reference. + +You must wait for all borrows to end before assigning a new value.", + "\ +Вы пытаетесь присвоить значение, пока существует его заимствование.", + "\ +빌림이 존재하는 동안 값에 할당하려고 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "End the borrow before assigning", + "Завершить заимствование перед присваиванием", + "할당 전에 빌림 종료" + ), + code: "{ let r = &x; use(r); } // borrow ends\nx = new_value;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0506.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0508.rs b/masterror-knowledge/src/errors/borrowing/e0508.rs new file mode 100644 index 0000000..4b0449c --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0508.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0508: cannot move out of type `[T]`, a non-copy slice + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0508", + title: LocalizedText::new( + "Cannot move out of type, a non-copy slice", + "Нельзя переместить из типа — это не-Copy срез", + "타입에서 이동할 수 없음, 비복사 슬라이스" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +You're trying to move a value out of a slice, but slices don't own their data. +They're just views into an array or Vec. + +Moving out would leave a \"hole\" in the slice, which isn't allowed.", + "\ +Вы пытаетесь переместить значение из среза, но срезы не владеют данными.", + "\ +슬라이스에서 값을 이동하려고 하지만, 슬라이스는 데이터를 소유하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Clone the element", + "Клонировать элемент", + "요소 복제" + ), + code: "let elem = slice[i].clone();" + }, + FixSuggestion { + description: LocalizedText::new( + "Use into_iter() on Vec", + "Использовать into_iter() на Vec", + "Vec에 into_iter() 사용" + ), + code: "for elem in vec.into_iter() { ... }" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0508.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0510.rs b/masterror-knowledge/src/errors/borrowing/e0510.rs new file mode 100644 index 0000000..c21a602 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0510.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0510: cannot assign in match guard + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0510", + title: LocalizedText::new( + "Cannot assign in match guard", + "Нельзя присваивать в охранном выражении match", + "매치 가드에서 할당할 수 없음" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +The matched value was assigned in a match guard. This is not allowed because +mutating the matched value in a guard could cause the match to become +non-exhaustive, as it might change which pattern arm should execute. + +The guard expression is evaluated after pattern matching but before the arm +body executes, so modifying the matched value would require re-evaluating +previous patterns.", + "\ +Сопоставляемое значение было изменено в охранном выражении match. +Это запрещено, поскольку изменение значения в охране может нарушить +полноту сопоставления, так как может измениться подходящая ветвь. + +Охранное выражение вычисляется после сопоставления с образцом, но до +выполнения тела ветви.", + "\ +매치 가드에서 매칭된 값이 할당되었습니다. 가드에서 매칭된 값을 변경하면 +매치가 비완전해질 수 있어 허용되지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Move mutation into match arm body", + "Переместить изменение в тело ветви", + "변경을 매치 암 본문으로 이동" + ), + code: "match x {\n Some(_) => { x = None; } // ok in body\n None => {}\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0510.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0521.rs b/masterror-knowledge/src/errors/borrowing/e0521.rs new file mode 100644 index 0000000..cc39e9e --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0521.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0521: borrowed data escapes outside of closure + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0521", + title: LocalizedText::new( + "Borrowed data escapes outside of closure", + "Заимствованные данные выходят за пределы замыкания", + "빌린 데이터가 클로저 외부로 탈출함" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +This error occurs when borrowed data is used within a closure in a way that +causes it to escape the closure's scope. When you explicitly annotate a closure +parameter with a type that includes a reference, it creates a new lifetime +declaration that may be incompatible with how the borrowed data is being used. + +The issue typically arises when a closure parameter is explicitly annotated +with a reference type, and that reference is then stored or used in a way +that extends beyond the closure's lifetime.", + "\ +Эта ошибка возникает, когда заимствованные данные используются в замыкании +так, что они выходят за пределы области видимости замыкания. Когда вы явно +аннотируете параметр замыкания типом со ссылкой, создаётся новое объявление +времени жизни, которое может быть несовместимо с использованием данных.", + "\ +이 오류는 빌린 데이터가 클로저 내에서 클로저의 스코프를 벗어나는 방식으로 +사용될 때 발생합니다. 참조를 포함하는 타입으로 클로저 매개변수를 명시적으로 +어노테이션하면 새로운 라이프타임이 생성됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove explicit type annotation, let compiler infer", + "Удалить явную аннотацию типа", + "명시적 타입 어노테이션 제거" + ), + code: "let mut list: Vec<&str> = Vec::new();\nlet _add = |el| { list.push(el); }; // no type annotation" + }], + links: &[ + DocLink { + title: "Closure Type Inference", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html#closure-type-inference-and-annotation" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0521.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0524.rs b/masterror-knowledge/src/errors/borrowing/e0524.rs new file mode 100644 index 0000000..ee44814 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0524.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0524: variable requiring unique access used in multiple closures + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0524", + title: LocalizedText::new( + "Two closures require unique access to same variable", + "Два замыкания требуют уникальный доступ к одной переменной", + "두 클로저가 같은 변수에 대한 고유 접근 필요" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +A variable which requires unique access is being used in more than one closure +at the same time. Since mutable references require exclusive access, Rust's +borrow checker prevents this to maintain memory safety. + +This error occurs when you attempt to borrow a mutable variable in multiple +closures simultaneously.", + "\ +Переменная, требующая уникального доступа, используется одновременно +в нескольких замыканиях. Поскольку изменяемые ссылки требуют +эксклюзивного доступа, проверка заимствований Rust предотвращает это.", + "\ +고유 접근이 필요한 변수가 동시에 둘 이상의 클로저에서 사용되고 있습니다. +가변 참조는 배타적 접근이 필요하므로 Rust의 빌림 검사기가 이를 방지합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use Rc> for shared mutable access", + "Использовать Rc> для общего изменяемого доступа", + "공유 가변 접근을 위해 Rc> 사용" + ), + code: "use std::rc::Rc;\nuse std::cell::RefCell;\nlet x = Rc::new(RefCell::new(val));\nlet y = Rc::clone(&x);" + }, + FixSuggestion { + description: LocalizedText::new( + "Run closures sequentially in separate scopes", + "Выполнять замыкания последовательно в разных областях", + "별도의 스코프에서 클로저를 순차적으로 실행" + ), + code: "{ let mut c1 = || set(&mut *x); c1(); }\nlet mut c2 = || set(&mut *x); c2();" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0524.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0594.rs b/masterror-knowledge/src/errors/borrowing/e0594.rs new file mode 100644 index 0000000..062efcc --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0594.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0594: cannot assign to immutable value + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0594", + title: LocalizedText::new( + "Cannot assign to immutable value", + "Нельзя присвоить неизменяемому значению", + "불변 값에 할당할 수 없음" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +A non-mutable value was assigned a value. In Rust, variables are immutable +by default, so you must explicitly use the `mut` keyword to allow modifications. + +This error occurs when attempting to modify a variable or field that was not +declared as mutable.", + "\ +Неизменяемому значению было присвоено значение. В Rust переменные +по умолчанию неизменяемы, поэтому необходимо явно использовать +ключевое слово `mut` для разрешения изменений.", + "\ +불변 값에 값이 할당되었습니다. Rust에서 변수는 기본적으로 불변이므로 +수정을 허용하려면 `mut` 키워드를 명시적으로 사용해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Declare the variable as mutable", + "Объявить переменную как изменяемую", + "변수를 가변으로 선언" + ), + code: "let mut x = SolarSystem { earth: 3 };\nx.earth = 2; // ok!" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0594.html" + }] +}; diff --git a/masterror-knowledge/src/errors/borrowing/e0596.rs b/masterror-knowledge/src/errors/borrowing/e0596.rs new file mode 100644 index 0000000..3f17af3 --- /dev/null +++ b/masterror-knowledge/src/errors/borrowing/e0596.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0596: cannot borrow as mutable, as it is not declared as mutable + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0596", + title: LocalizedText::new( + "Cannot borrow as mutable (not declared as mutable)", + "Нельзя заимствовать как изменяемое (не объявлено как изменяемое)", + "가변으로 빌릴 수 없음 (가변으로 선언되지 않음)" + ), + category: Category::Borrowing, + explanation: LocalizedText::new( + "\ +You're trying to get a mutable reference to something that wasn't declared +as mutable. To modify through a reference, the original binding must be `mut`. + +This is Rust's way of making mutation explicit and visible in the code.", + "\ +Вы пытаетесь получить изменяемую ссылку на то, что не было объявлено +как изменяемое. Для изменения через ссылку оригинал должен быть `mut`.", + "\ +가변으로 선언되지 않은 것에 대한 가변 참조를 얻으려고 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add mut to the variable declaration", + "Добавить mut к объявлению переменной", + "변수 선언에 mut 추가" + ), + code: "let mut x = vec![1, 2, 3];" + }, + FixSuggestion { + description: LocalizedText::new( + "Add mut to function parameter", + "Добавить mut к параметру функции", + "함수 매개변수에 mut 추가" + ), + code: "fn process(data: &mut Vec) { ... }" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0596.html" + }] +}; diff --git a/masterror-knowledge/src/errors/const_eval.rs b/masterror-knowledge/src/errors/const_eval.rs new file mode 100644 index 0000000..edb7bc4 --- /dev/null +++ b/masterror-knowledge/src/errors/const_eval.rs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Const evaluation related errors. + +mod e0492; +mod e0493; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[&e0492::ENTRY, &e0493::ENTRY]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/const_eval/e0492.rs b/masterror-knowledge/src/errors/const_eval/e0492.rs new file mode 100644 index 0000000..a053831 --- /dev/null +++ b/masterror-knowledge/src/errors/const_eval/e0492.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0492: borrow of const with interior mutability + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0492", + title: LocalizedText::new( + "Borrow of constant containing interior mutability", + "Заимствование константы с внутренней изменяемостью", + "내부 가변성을 포함하는 상수의 빌림" + ), + category: Category::ConstEval, + explanation: LocalizedText::new( + "\ +An attempt was made to take a reference to a const that contains types with +interior mutability (like AtomicUsize or Cell). + +A const represents a constant value that should never change. However, types +with interior mutability allow mutation through shared references. This +creates a contradiction: a constant could theoretically be mutated. + +A static is different - it's explicitly a single memory location.", + "\ +Попытка взять ссылку на const, содержащий типы с внутренней изменяемостью +(такие как AtomicUsize или Cell). + +Const представляет константное значение, которое не должно меняться. +Однако типы с внутренней изменяемостью позволяют мутацию через +разделяемые ссылки, что создаёт противоречие.", + "\ +내부 가변성을 가진 타입(AtomicUsize 또는 Cell 등)을 포함하는 +const에 대한 참조를 가져오려고 시도했습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use static instead of const", + "Использовать static вместо const", + "const 대신 static 사용" + ), + code: "use std::sync::atomic::AtomicUsize;\n\nstatic A: AtomicUsize = AtomicUsize::new(0);\nstatic B: &'static AtomicUsize = &A; // ok!" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0492.html" + }] +}; diff --git a/masterror-knowledge/src/errors/const_eval/e0493.rs b/masterror-knowledge/src/errors/const_eval/e0493.rs new file mode 100644 index 0000000..c1a336b --- /dev/null +++ b/masterror-knowledge/src/errors/const_eval/e0493.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0493: value with Drop may be dropped during const-eval + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0493", + title: LocalizedText::new( + "Value with custom Drop may be dropped during const-eval", + "Значение с Drop может быть уничтожено при const-вычислении", + "커스텀 Drop을 가진 값이 const-eval 중에 드롭될 수 있음" + ), + category: Category::ConstEval, + explanation: LocalizedText::new( + "\ +A value that implements the Drop trait was used in a const context (like a +static initializer). The issue is that Drop implementations can execute +arbitrary code that isn't const-checked, which violates the constraints +of compile-time evaluation. + +Drop logic could have unpredictable side effects and must be deterministic +and verifiable at compile-time.", + "\ +Значение, реализующее трейт Drop, использовано в const-контексте +(например, в инициализаторе static). Проблема в том, что реализации +Drop могут выполнять произвольный код, который не проверяется на +const-совместимость, что нарушает ограничения вычисления во время +компиляции.", + "\ +Drop 트레이트를 구현하는 값이 const 컨텍스트(예: static 초기화자)에서 +사용되었습니다. Drop 구현은 const-checked되지 않는 임의의 코드를 +실행할 수 있어 컴파일 타임 평가 제약을 위반합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Initialize fields directly without temporaries", + "Инициализировать поля напрямую без временных значений", + "임시 값 없이 필드 직접 초기화" + ), + code: "static FOO: Foo = Foo { field1: DropType::A }; // Direct init" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0493.html" + }] +}; diff --git a/masterror-knowledge/src/errors/consts.rs b/masterror-knowledge/src/errors/consts.rs new file mode 100644 index 0000000..3f9507d --- /dev/null +++ b/masterror-knowledge/src/errors/consts.rs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Constant and static related errors. + +mod e0010; +mod e0015; +mod e0080; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[&e0010::ENTRY, &e0015::ENTRY, &e0080::ENTRY]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/consts/e0010.rs b/masterror-knowledge/src/errors/consts/e0010.rs new file mode 100644 index 0000000..86784bf --- /dev/null +++ b/masterror-knowledge/src/errors/consts/e0010.rs @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0010: cannot allocate in const/static context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0010", + title: LocalizedText::new( + "Cannot allocate in const/static", + "Нельзя выделять память в const/static", + "const/static에서 할당 불가" + ), + category: Category::Consts, + explanation: LocalizedText::new( + "\ +The value of statics and constants must be known at compile time. Creating a +boxed value or using `vec![]` allocates memory on the heap at runtime, which +cannot be done in a const context. + +Example: + const CON: Vec = vec![1, 2, 3]; // Error: heap allocation", + "\ +Значения static и const должны быть известны во время компиляции. +Создание Box или использование vec![] выделяет память в куче во время +выполнения, что недопустимо в контексте const.", + "\ +static과 const의 값은 컴파일 시점에 알려져야 합니다. 힙 할당은 런타임에 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use an array instead", + "Использовать массив вместо Vec", + "대신 배열 사용" + ), + code: "const CON: [i32; 3] = [1, 2, 3];" + }, + FixSuggestion { + description: LocalizedText::new( + "Use lazy_static or once_cell for runtime initialization", + "Использовать lazy_static или once_cell", + "런타임 초기화를 위해 lazy_static 또는 once_cell 사용" + ), + code: "use std::sync::LazyLock;\nstatic CON: LazyLock> = LazyLock::new(|| vec![1, 2, 3]);" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Constant Evaluation", + url: "https://doc.rust-lang.org/reference/const_eval.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0010.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/consts/e0015.rs b/masterror-knowledge/src/errors/consts/e0015.rs new file mode 100644 index 0000000..26ed757 --- /dev/null +++ b/masterror-knowledge/src/errors/consts/e0015.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0015: non-const function called in const context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0015", + title: LocalizedText::new( + "Non-const function in const context", + "Не-const функция в const контексте", + "const 컨텍스트에서 non-const 함수" + ), + category: Category::Consts, + explanation: LocalizedText::new( + "\ +This error occurs when you call a non-`const` function within a constant or +static expression. Only `const fn` functions can be evaluated at compile time. + +Example: + fn create_some() -> Option { Some(1) } + const FOO: Option = create_some(); // Error: not a const fn", + "\ +Эта ошибка возникает при вызове не-const функции в константном выражении. +Только функции с `const fn` могут вычисляться во время компиляции.", + "\ +이 오류는 상수 표현식에서 non-const 함수를 호출할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Mark the function as const fn", + "Пометить функцию как const fn", + "함수를 const fn으로 표시" + ), + code: "const fn create_some() -> Option { Some(1) }\nconst FOO: Option = create_some();" + }], + links: &[ + DocLink { + title: "Rust Reference: Const Functions", + url: "https://doc.rust-lang.org/reference/const_eval.html#const-functions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0015.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/consts/e0080.rs b/masterror-knowledge/src/errors/consts/e0080.rs new file mode 100644 index 0000000..cfa4517 --- /dev/null +++ b/masterror-knowledge/src/errors/consts/e0080.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0080: constant value evaluation failed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0080", + title: LocalizedText::new( + "Constant evaluation failed", + "Ошибка вычисления константы", + "상수 평가 실패" + ), + category: Category::Consts, + explanation: LocalizedText::new( + "\ +This error occurs when the compiler cannot evaluate a constant expression. +This typically happens with operations that are mathematically or +computationally invalid: + +- Division by zero +- Integer overflow +- Invalid bit shifts + +Example: + enum E { X = (1 / 0) } // Error: division by zero", + "\ +Эта ошибка возникает, когда компилятор не может вычислить константное +выражение. Обычно это происходит при недопустимых операциях: +деление на ноль, целочисленное переполнение.", + "\ +이 오류는 컴파일러가 상수 표현식을 평가할 수 없을 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Ensure valid arithmetic operations", + "Убедиться в корректности арифметических операций", + "유효한 산술 연산 확인" + ), + code: "enum E {\n X = 1,\n Y = 2,\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Constant Evaluation", + url: "https://doc.rust-lang.org/reference/const_eval.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0080.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/features.rs b/masterror-knowledge/src/errors/features.rs new file mode 100644 index 0000000..3185b61 --- /dev/null +++ b/masterror-knowledge/src/errors/features.rs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Feature flag and compiler feature errors. + +mod e0635; +mod e0636; +mod e0658; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[&e0635::ENTRY, &e0636::ENTRY, &e0658::ENTRY]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/features/e0635.rs b/masterror-knowledge/src/errors/features/e0635.rs new file mode 100644 index 0000000..2efcbb2 --- /dev/null +++ b/masterror-knowledge/src/errors/features/e0635.rs @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0635: unknown feature + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0635", + title: LocalizedText::new( + "Unknown feature in #![feature] attribute", + "Неизвестная функция в атрибуте #![feature]", + "#![feature] 속성에 알 수 없는 기능" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unknown or non-existent feature was specified in a `#![feature]` attribute. + +Feature flags are used to opt into unstable or experimental Rust features, +and they must be valid feature names recognized by the Rust compiler.", + "\ +Неизвестная или несуществующая функция была указана в атрибуте `#![feature]`. + +Флаги функций используются для включения нестабильных или экспериментальных +функций Rust и должны быть допустимыми именами функций, распознаваемыми +компилятором Rust.", + "\ +`#![feature]` 속성에 알 수 없거나 존재하지 않는 기능이 지정되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Verify the feature name spelling", + "Проверить правописание имени функции", + "기능 이름 철자 확인" + ), + code: "#![feature(existing_feature)] // check spelling" + }, + FixSuggestion { + description: LocalizedText::new( + "Check the Unstable Book for valid features", + "Проверить Unstable Book для допустимых функций", + "유효한 기능은 Unstable Book 확인" + ), + code: "// See https://doc.rust-lang.org/unstable-book/" + } + ], + links: &[ + DocLink { + title: "The Unstable Book", + url: "https://doc.rust-lang.org/unstable-book/" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0635.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/features/e0636.rs b/masterror-knowledge/src/errors/features/e0636.rs new file mode 100644 index 0000000..5e9e37e --- /dev/null +++ b/masterror-knowledge/src/errors/features/e0636.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0636: duplicate feature + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0636", + title: LocalizedText::new( + "Feature enabled multiple times", + "Функция включена несколько раз", + "기능이 여러 번 활성화됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The same feature is enabled multiple times with `#![feature]` attributes. +The Rust compiler does not allow duplicate `#![feature]` declarations for +the same feature. Each feature should only be enabled once per crate.", + "\ +Одна и та же функция включена несколько раз с помощью атрибутов `#![feature]`. +Компилятор Rust не допускает дублирующиеся объявления `#![feature]` для одной +и той же функции. Каждая функция должна быть включена только один раз в крейте.", + "\ +동일한 기능이 `#![feature]` 속성으로 여러 번 활성화되었습니다. +각 기능은 크레이트당 한 번만 활성화해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove duplicate feature attribute", + "Удалить дублирующийся атрибут функции", + "중복 기능 속성 제거" + ), + code: "#![feature(rust1)] // keep only one" + }], + links: &[ + DocLink { + title: "The Unstable Book", + url: "https://doc.rust-lang.org/unstable-book/" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0636.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/features/e0658.rs b/masterror-knowledge/src/errors/features/e0658.rs new file mode 100644 index 0000000..29697c8 --- /dev/null +++ b/masterror-knowledge/src/errors/features/e0658.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0658: unstable feature used + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0658", + title: LocalizedText::new( + "Unstable feature used", + "Использована нестабильная функция", + "불안정한 기능 사용됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unstable feature was used without properly enabling it. Unstable features +are experimental functionality that may change or be removed in future Rust +versions. + +Unstable features require: +- The nightly version of Rust +- Explicit opt-in via `#![feature(...)]` attribute", + "\ +Использована нестабильная функция без её правильного включения. Нестабильные +функции — это экспериментальная функциональность, которая может измениться +или быть удалена в будущих версиях Rust. + +Нестабильные функции требуют: +- Ночную версию Rust +- Явное включение через атрибут `#![feature(...)]`", + "\ +불안정한 기능이 적절한 활성화 없이 사용되었습니다. 불안정한 기능은 +향후 Rust 버전에서 변경되거나 제거될 수 있는 실험적 기능입니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Enable the feature with #![feature(...)]", + "Включить функцию с помощью #![feature(...)]", + "#![feature(...)]로 기능 활성화" + ), + code: "#![feature(core_intrinsics)]\n\nuse std::intrinsics; // ok!" + }, + FixSuggestion { + description: LocalizedText::new( + "Switch to nightly Rust", + "Переключиться на ночную версию Rust", + "nightly Rust로 전환" + ), + code: "rustup default nightly" + } + ], + links: &[ + DocLink { + title: "The Unstable Book", + url: "https://doc.rust-lang.org/unstable-book/" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0658.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/generics.rs b/masterror-knowledge/src/errors/generics.rs new file mode 100644 index 0000000..6356a54 --- /dev/null +++ b/masterror-knowledge/src/errors/generics.rs @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Generic parameter related errors. + +mod e0107; +mod e0109; +mod e0128; +mod e0393; +mod e0401; +mod e0403; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0107::ENTRY, + &e0109::ENTRY, + &e0128::ENTRY, + &e0393::ENTRY, + &e0401::ENTRY, + &e0403::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/generics/e0107.rs b/masterror-knowledge/src/errors/generics/e0107.rs new file mode 100644 index 0000000..e348fe8 --- /dev/null +++ b/masterror-knowledge/src/errors/generics/e0107.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0107: wrong number of generic arguments + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0107", + title: LocalizedText::new( + "Wrong number of generic arguments", + "Неправильное количество обобщённых аргументов", + "제네릭 인수 개수 불일치" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An incorrect number of generic arguments was provided. The compiler expects +a specific number of generic type parameters, lifetime parameters, or const +parameters, but you've supplied a different amount. + +This commonly happens when: +- Using a generic type without providing all required type arguments +- Providing more type arguments than the type accepts +- Forgetting lifetime parameters when they are required", + "\ +Указано неправильное количество обобщённых аргументов. Компилятор ожидает +определённое количество параметров типа, времени жизни или констант, +но вы указали другое количество. + +Это часто происходит когда: +- Используется обобщённый тип без всех необходимых аргументов +- Указано больше аргументов типа, чем принимает тип +- Забыты параметры времени жизни", + "\ +제공된 제네릭 인수의 수가 올바르지 않습니다. 컴파일러는 특정 수의 타입, +라이프타임 또는 const 매개변수를 기대하지만 다른 수가 제공되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Provide the correct number of type arguments", + "Указать правильное количество аргументов типа", + "올바른 수의 타입 인수 제공" + ), + code: "struct Foo { x: T }\nstruct Bar { x: Foo } // provide one type argument" + }, + FixSuggestion { + description: LocalizedText::new( + "Check the type definition for required parameters", + "Проверить определение типа на требуемые параметры", + "필요한 매개변수에 대한 타입 정의 확인" + ), + code: "fn foo(x: T, y: U) {}\nfoo::(x, 12); // two type arguments needed" + } + ], + links: &[ + DocLink { + title: "Rust Book: Generic Data Types", + url: "https://doc.rust-lang.org/book/ch10-01-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0107.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/generics/e0109.rs b/masterror-knowledge/src/errors/generics/e0109.rs new file mode 100644 index 0000000..1000010 --- /dev/null +++ b/masterror-knowledge/src/errors/generics/e0109.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0109: type arguments not allowed for this type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0109", + title: LocalizedText::new( + "Type arguments not allowed for this type", + "Аргументы типа не разрешены для этого типа", + "이 타입에는 타입 인수가 허용되지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +You tried to provide a generic argument to a type which doesn't need it. +Primitive types like u32, bool, i64 don't accept type parameters. + +Generic arguments for enum variant constructors go after the variant, +not after the enum. For example, write Option::None:: rather than +Option::::None.", + "\ +Вы попытались передать обобщённый аргумент типу, который его не принимает. +Примитивные типы вроде u32, bool, i64 не принимают параметры типа. + +Обобщённые аргументы для конструкторов вариантов перечислений указываются +после варианта, а не после перечисления.", + "\ +제네릭 인수를 받지 않는 타입에 제네릭 인수를 제공하려고 했습니다. +u32, bool, i64와 같은 기본 타입은 타입 매개변수를 받지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove the type argument from primitive type", + "Удалить аргумент типа у примитивного типа", + "기본 타입에서 타입 인수 제거" + ), + code: "type X = u32; // not u32" + }, + FixSuggestion { + description: LocalizedText::new( + "Place generic args after enum variant", + "Поместить обобщённые аргументы после варианта", + "열거형 변형 뒤에 제네릭 인수 배치" + ), + code: "Option::None:: // not Option::::None" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Types", + url: "https://doc.rust-lang.org/reference/types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0109.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/generics/e0128.rs b/masterror-knowledge/src/errors/generics/e0128.rs new file mode 100644 index 0000000..183cc58 --- /dev/null +++ b/masterror-knowledge/src/errors/generics/e0128.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0128: generic parameters with a default cannot use forward declared +//! identifiers + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0128", + title: LocalizedText::new( + "Generic parameters with a default cannot use forward declared identifiers", + "Обобщённые параметры со значением по умолчанию не могут использовать ещё не объявленные идентификаторы", + "기본값이 있는 제네릭 매개변수는 전방 선언된 식별자를 사용할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type parameter with default value is using a forward declared identifier. +Type parameter defaults can only reference parameters that are declared +before them. Since type parameters are evaluated in order, attempting to +use a not-yet-defined identifier in a default value causes this error.", + "\ +Параметр типа со значением по умолчанию использует ещё не объявленный +идентификатор. Значения по умолчанию для параметров типа могут ссылаться +только на параметры, объявленные до них. Поскольку параметры типа +вычисляются по порядку, использование ещё не определённого идентификатора +вызывает эту ошибку.", + "\ +기본값이 있는 타입 매개변수가 전방 선언된 식별자를 사용하고 있습니다. +타입 매개변수 기본값은 이전에 선언된 매개변수만 참조할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Reorder type parameters so referenced ones come first", + "Переупорядочить параметры типа так, чтобы используемые шли первыми", + "참조되는 매개변수가 먼저 오도록 타입 매개변수 재정렬" + ), + code: "struct Foo {\n field1: T,\n field2: U,\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Type Parameters", + url: "https://doc.rust-lang.org/reference/items/generics.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0128.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/generics/e0393.rs b/masterror-knowledge/src/errors/generics/e0393.rs new file mode 100644 index 0000000..8c37386 --- /dev/null +++ b/masterror-knowledge/src/errors/generics/e0393.rs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0393: type parameter with Self default not specified + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0393", + title: LocalizedText::new( + "Type parameter referencing Self must be specified", + "Параметр типа со ссылкой на Self должен быть указан", + "Self를 참조하는 타입 매개변수를 지정해야 함" + ), + category: Category::Generics, + explanation: LocalizedText::new( + "\ +A type parameter which references `Self` in its default value was not specified. +This error occurs when a trait has a default type parameter that references +`Self`, but the trait is used as a trait object without explicitly specifying +that type parameter. + +Trait objects require a single, fully-defined trait. When a default parameter +is `Self`, the trait effectively changes for each concrete type: +- i32 would need to implement A +- bool would need to implement A + +Since each type implements a different version of the trait, they cannot be +unified into a single trait object.", + "\ +Параметр типа со ссылкой на `Self` в значении по умолчанию не был указан. +Эта ошибка возникает, когда трейт имеет параметр типа по умолчанию, ссылающийся +на `Self`, но трейт используется как трейт-объект без явного указания этого +параметра типа. + +Трейт-объекты требуют единого, полностью определённого трейта. Когда параметр +по умолчанию - `Self`, трейт фактически меняется для каждого конкретного типа: +- i32 должен реализовывать A +- bool должен реализовывать A + +Поскольку каждый тип реализует разную версию трейта, они не могут быть +объединены в единый трейт-объект.", + "\ +기본값에서 `Self`를 참조하는 타입 매개변수가 지정되지 않았습니다. +이 오류는 트레이트가 `Self`를 참조하는 기본 타입 매개변수를 가지고 있지만, +해당 타입 매개변수를 명시적으로 지정하지 않고 트레이트 객체로 사용될 때 발생합니다. + +트레이트 객체는 단일하고 완전히 정의된 트레이트를 필요로 합니다. +기본 매개변수가 `Self`일 때, 각 구체적인 타입에 대해 트레이트가 효과적으로 변경됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Explicitly specify the concrete type parameter", + "Явно указать конкретный параметр типа", + "구체적인 타입 매개변수를 명시적으로 지정" + ), + code: "trait A {}\n\nfn together_we_will_rule_the_galaxy(son: &dyn A) {} // Ok!" + }], + links: &[ + DocLink { + title: "Rust Reference: Trait Objects", + url: "https://doc.rust-lang.org/reference/types/trait-object.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0393.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/generics/e0401.rs b/masterror-knowledge/src/errors/generics/e0401.rs new file mode 100644 index 0000000..1761724 --- /dev/null +++ b/masterror-knowledge/src/errors/generics/e0401.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0401: inner items do not inherit generic parameters + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0401", + title: LocalizedText::new( + "Inner items do not inherit generic parameters", + "Вложенные элементы не наследуют параметры типов", + "내부 항목은 제네릭 매개변수를 상속하지 않음" + ), + category: Category::Generics, + explanation: LocalizedText::new( + "\ +Nested items (functions, types, or structs) cannot use generic parameters from +their enclosing scope. Inner items are treated as top-level items that can +only be accessed from within their containing scope. + +This is a deliberate design choice - inner functions need their own generic +parameters to be self-contained.", + "\ +Вложенные элементы (функции, типы или структуры) не могут использовать +параметры типов из внешней области видимости. Внутренние элементы +рассматриваются как элементы верхнего уровня. + +Это сделано намеренно - внутренние функции должны быть самодостаточными.", + "\ +중첩된 항목(함수, 타입 또는 구조체)은 외부 스코프의 제네릭 매개변수를 +사용할 수 없습니다. 내부 항목은 최상위 항목으로 취급됩니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a closure instead of inner function", + "Использовать замыкание вместо функции", + "내부 함수 대신 클로저 사용" + ), + code: "fn foo(x: T) {\n let bar = |y: T| { /* closure captures T */ };\n bar(x);\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Explicitly declare generic parameters in inner item", + "Явно объявить параметры типов во вложенном элементе", + "내부 항목에 제네릭 매개변수 명시적 선언" + ), + code: "fn foo(x: T) {\n fn bar(y: T) { }\n bar(x);\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0401.html" + }] +}; diff --git a/masterror-knowledge/src/errors/generics/e0403.rs b/masterror-knowledge/src/errors/generics/e0403.rs new file mode 100644 index 0000000..a70cffc --- /dev/null +++ b/masterror-knowledge/src/errors/generics/e0403.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0403: duplicate type parameter name + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0403", + title: LocalizedText::new( + "Some type parameters have the same name", + "Несколько параметров типа имеют одинаковое имя", + "일부 타입 매개변수가 같은 이름을 가짐" + ), + category: Category::Generics, + explanation: LocalizedText::new( + "\ +Multiple type parameters with the same name were declared in a function, trait, +or other generic item. Rust requires all type parameters within the same scope +to have unique names. + +Type parameters in associated items also cannot shadow parameters from the +containing item.", + "\ +В функции, трейте или другом обобщённом элементе объявлено несколько +параметров типа с одинаковым именем. Rust требует, чтобы все параметры +типа в одной области видимости имели уникальные имена.", + "\ +함수, 트레이트 또는 다른 제네릭 항목에서 같은 이름의 타입 매개변수가 +여러 개 선언되었습니다. Rust는 같은 스코프 내 모든 타입 매개변수가 +고유한 이름을 가질 것을 요구합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Rename clashing type parameters to be unique", + "Переименовать конфликтующие параметры типа", + "충돌하는 타입 매개변수 이름 변경" + ), + code: "fn f(s: T, u: U) {} // Use different names" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0403.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes.rs b/masterror-knowledge/src/errors/lifetimes.rs new file mode 100644 index 0000000..efe6e08 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Lifetime-related errors. + +mod e0106; +mod e0195; +mod e0226; +mod e0227; +mod e0228; +mod e0261; +mod e0262; +mod e0263; +mod e0478; +mod e0482; +mod e0491; +mod e0495; +mod e0496; +mod e0515; +mod e0581; +mod e0582; +mod e0597; +mod e0621; +mod e0623; +mod e0625; +mod e0626; +mod e0637; +mod e0657; +mod e0700; +mod e0716; +mod e0803; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0106::ENTRY, + &e0195::ENTRY, + &e0226::ENTRY, + &e0227::ENTRY, + &e0228::ENTRY, + &e0261::ENTRY, + &e0262::ENTRY, + &e0263::ENTRY, + &e0478::ENTRY, + &e0482::ENTRY, + &e0491::ENTRY, + &e0495::ENTRY, + &e0496::ENTRY, + &e0515::ENTRY, + &e0581::ENTRY, + &e0582::ENTRY, + &e0597::ENTRY, + &e0621::ENTRY, + &e0623::ENTRY, + &e0625::ENTRY, + &e0626::ENTRY, + &e0637::ENTRY, + &e0657::ENTRY, + &e0700::ENTRY, + &e0716::ENTRY, + &e0803::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/lifetimes/e0106.rs b/masterror-knowledge/src/errors/lifetimes/e0106.rs new file mode 100644 index 0000000..3d10310 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0106.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0106: missing lifetime specifier + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0106", + title: LocalizedText::new( + "Missing lifetime specifier", + "Отсутствует спецификатор времени жизни", + "라이프타임 지정자 누락" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +References in Rust have lifetimes - they describe how long the reference +is valid. Usually the compiler infers lifetimes, but sometimes you must +be explicit. + +Lifetime annotations don't change how long values live. They describe +relationships between references so the compiler can verify safety.", + "\ +Ссылки в Rust имеют времена жизни — они описывают, как долго ссылка +действительна. Обычно компилятор выводит времена жизни, но иногда нужно +указать явно.", + "\ +Rust의 참조에는 라이프타임이 있습니다 - 참조가 얼마나 오래 유효한지 설명합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add explicit lifetime parameter", + "Добавить явный параметр времени жизни", + "명시적 라이프타임 매개변수 추가" + ), + code: "struct Foo<'a> { x: &'a str }" + }, + FixSuggestion { + description: LocalizedText::new( + "Use owned type instead", + "Использовать владеющий тип", + "소유 타입 사용" + ), + code: "struct Foo { x: String }" + }, + FixSuggestion { + description: LocalizedText::new( + "Use 'static for compile-time constants", + "Использовать 'static для констант", + "컴파일 시간 상수에 'static 사용" + ), + code: "fn get_str() -> &'static str { \"hello\" }" + } + ], + links: &[ + DocLink { + title: "Rust Book: Lifetimes", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0106.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0195.rs b/masterror-knowledge/src/errors/lifetimes/e0195.rs new file mode 100644 index 0000000..4177095 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0195.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0195: lifetime parameters or bounds on method do not match the trait +//! declaration + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0195", + title: LocalizedText::new( + "Lifetime parameters or bounds on method do not match the trait declaration", + "Параметры времени жизни или ограничения метода не соответствуют объявлению трейта", + "메서드의 라이프타임 매개변수 또는 바운드가 트레이트 선언과 일치하지 않음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +The lifetime parameters of the method do not match the trait declaration. +When implementing a trait method with lifetime parameters, the lifetime +bounds and constraints must be identical between the trait definition +and its implementation.", + "\ +Параметры времени жизни метода не соответствуют объявлению трейта. +При реализации метода трейта с параметрами времени жизни, ограничения +времени жизни должны быть идентичны между определением трейта и его +реализацией.", + "\ +메서드의 라이프타임 매개변수가 트레이트 선언과 일치하지 않습니다. +라이프타임 매개변수가 있는 트레이트 메서드를 구현할 때 라이프타임 +바운드와 제약 조건은 트레이트 정의와 구현 사이에서 동일해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match lifetime declarations and bounds exactly", + "Точно соответствовать объявлениям и ограничениям времени жизни", + "라이프타임 선언과 바운드를 정확히 일치시키기" + ), + code: "trait Trait {\n fn t<'a,'b:'a>(x: &'a str, y: &'b str);\n}\n\nstruct Foo;\n\nimpl Trait for Foo {\n fn t<'a,'b:'a>(x: &'a str, y: &'b str) { // ok!\n }\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Lifetime Annotations", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0195.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0226.rs b/masterror-knowledge/src/errors/lifetimes/e0226.rs new file mode 100644 index 0000000..99c4e72 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0226.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0226: multiple explicit lifetime bounds on trait object + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0226", + title: LocalizedText::new( + "Multiple explicit lifetime bounds on trait object", + "Несколько явных ограничений времени жизни для трейт-объекта", + "트레이트 객체에 여러 명시적 수명 바운드" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +More than one explicit lifetime bound was used on a trait object. +Trait objects in Rust can only have ONE explicit lifetime bound. + +If you need to work with multiple lifetimes, consider restructuring +your code or using a single lifetime that encompasses the requirements +of both.", + "\ +Для трейт-объекта было использовано более одного явного ограничения +времени жизни. Трейт-объекты в Rust могут иметь только ОДНО явное +ограничение времени жизни.", + "\ +트레이트 객체에 둘 이상의 명시적 수명 바운드가 사용되었습니다. +트레이트 객체는 하나의 명시적 수명 바운드만 가질 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove all but one lifetime bound", + "Удалите все ограничения времени жизни, кроме одного", + "하나를 제외한 모든 수명 바운드 제거" + ), + code: "trait Foo {}\n\ntype T<'a> = dyn Foo + 'a;" + }], + links: &[ + DocLink { + title: "Rust Reference: Trait Object Lifetime Bounds", + url: "https://doc.rust-lang.org/reference/types/trait-object.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0226.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0227.rs b/masterror-knowledge/src/errors/lifetimes/e0227.rs new file mode 100644 index 0000000..4c6d60c --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0227.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0227: ambiguous lifetime bounds + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0227", + title: LocalizedText::new( + "Ambiguous lifetime bounds", + "Неоднозначные ограничения времени жизни", + "모호한 수명 바운드" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +Unable to determine a unique region in derived region bounds. + +This error occurs when the Rust compiler cannot determine exactly one +unique lifetime from a set of derived region bounds. When a trait +object could satisfy multiple lifetime constraints, you need to be +explicit about which lifetime applies.", + "\ +Невозможно определить единственный регион из производных ограничений регионов. + +Эта ошибка возникает, когда компилятор Rust не может определить ровно +одно уникальное время жизни из набора производных ограничений регионов.", + "\ +파생된 영역 바운드에서 고유한 영역을 결정할 수 없습니다. +명시적으로 어떤 수명이 적용되는지 지정해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Explicitly specify a lifetime bound", + "Явно укажите ограничение времени жизни", + "수명 바운드를 명시적으로 지정" + ), + code: "struct Baz<'foo, 'bar, 'baz>\nwhere\n 'baz: 'foo + 'bar,\n{\n obj: dyn FooBar<'foo, 'bar> + 'baz,\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Lifetimes", + url: "https://doc.rust-lang.org/reference/trait-bounds.html#lifetime-bounds" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0227.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0228.rs b/masterror-knowledge/src/errors/lifetimes/e0228.rs new file mode 100644 index 0000000..11d2a6f --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0228.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0228: undeducible lifetime bound for trait objects + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0228", + title: LocalizedText::new( + "Undeducible lifetime bound for trait object", + "Невыводимое ограничение времени жизни для трейт-объекта", + "트레이트 객체의 추론 불가능한 수명 바운드" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +The lifetime bound for this object type cannot be deduced from context +and must be specified. + +This error occurs when a trait object is used as a type argument in +a generic type that has multiple lifetime bounds, and Rust cannot +automatically infer which lifetime should apply to the trait object.", + "\ +Ограничение времени жизни для этого типа объекта не может быть выведено +из контекста и должно быть указано. + +Эта ошибка возникает, когда трейт-объект используется как аргумент типа +в обобщённом типе с несколькими ограничениями времени жизни.", + "\ +이 객체 타입의 수명 바운드를 컨텍스트에서 추론할 수 없으므로 +명시적으로 지정해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Explicitly specify the trait object's lifetime", + "Явно укажите время жизни трейт-объекта", + "트레이트 객체의 수명을 명시적으로 지정" + ), + code: "type Foo<'a, 'b> = TwoBounds<'a, 'b, dyn Trait + 'b>;" + }, + FixSuggestion { + description: LocalizedText::new( + "Reduce to a single lifetime bound", + "Сократите до одного ограничения времени жизни", + "단일 수명 바운드로 축소" + ), + code: "struct OneBound<'a, T: 'a> {\n x: &'a i32,\n z: T,\n}" + } + ], + links: &[ + DocLink { + title: "RFC 599: Default Object Bound", + url: "https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0228.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0261.rs b/masterror-knowledge/src/errors/lifetimes/e0261.rs new file mode 100644 index 0000000..179b6d3 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0261.rs @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0261: undeclared lifetime + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0261", + title: LocalizedText::new( + "Use of undeclared lifetime", + "Использование необъявленного времени жизни", + "선언되지 않은 수명 사용" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A lifetime parameter was used without first declaring it. + +Lifetimes must be explicitly declared as generic parameters before +they can be used in function signatures, struct definitions, or +impl blocks. + +The lifetime parameter must be declared in angle brackets before +being referenced in the type or function signature.", + "\ +Параметр времени жизни был использован без предварительного объявления. + +Времена жизни должны быть явно объявлены как параметры дженериков, +прежде чем их можно использовать в сигнатурах функций, определениях +структур или блоках impl.", + "\ +수명 매개변수가 선언되지 않고 사용되었습니다. +수명은 사용하기 전에 제네릭 매개변수로 선언해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Declare lifetime in function signature", + "Объявите время жизни в сигнатуре функции", + "함수 시그니처에서 수명 선언" + ), + code: "fn foo<'a>(x: &'a str) {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Declare lifetime in struct definition", + "Объявите время жизни в определении структуры", + "구조체 정의에서 수명 선언" + ), + code: "struct Foo<'a> {\n x: &'a str,\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Declare lifetime on impl block", + "Объявите время жизни в блоке impl", + "impl 블록에서 수명 선언" + ), + code: "impl<'a> Foo<'a> {\n fn foo(x: &'a str) {}\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Lifetimes", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0261.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0262.rs b/masterror-knowledge/src/errors/lifetimes/e0262.rs new file mode 100644 index 0000000..80ddbca --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0262.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0262: invalid lifetime parameter name + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0262", + title: LocalizedText::new( + "Invalid lifetime parameter name", + "Недопустимое имя параметра времени жизни", + "잘못된 수명 매개변수 이름" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +An invalid name was used for a lifetime parameter. + +The name `'static` cannot be used as a named lifetime parameter because +it is a special built-in lifetime that denotes the lifetime of the +entire program. It has special meaning in Rust and is reserved, so it +cannot be redefined or used as a custom generic lifetime parameter.", + "\ +Для параметра времени жизни использовано недопустимое имя. + +Имя `'static` нельзя использовать как именованный параметр времени жизни, +потому что это специальное встроенное время жизни, обозначающее время +жизни всей программы.", + "\ +수명 매개변수에 잘못된 이름이 사용되었습니다. +`'static`은 예약된 이름이므로 사용자 정의 수명 매개변수로 사용할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a valid custom lifetime name", + "Используйте допустимое пользовательское имя времени жизни", + "유효한 사용자 정의 수명 이름 사용" + ), + code: "fn foo<'a>(x: &'a str) {}" + }], + links: &[ + DocLink { + title: "Rust Book: Static Lifetime", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#the-static-lifetime" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0262.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0263.rs b/masterror-knowledge/src/errors/lifetimes/e0263.rs new file mode 100644 index 0000000..bdff4a7 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0263.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0263: duplicate lifetime declaration + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0263", + title: LocalizedText::new( + "Duplicate lifetime declaration", + "Дублирующееся объявление времени жизни", + "중복된 수명 선언" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A lifetime was declared more than once in the same scope. + +A lifetime parameter cannot have the same name as another lifetime +parameter within the same function or generic declaration. + +Note: This error code is no longer emitted by the compiler.", + "\ +Время жизни было объявлено более одного раза в той же области видимости. + +Параметр времени жизни не может иметь то же имя, что и другой параметр +времени жизни в той же функции или обобщённом объявлении. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +수명이 같은 범위에서 두 번 이상 선언되었습니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Rename duplicate lifetime to unique identifier", + "Переименуйте дублирующееся время жизни в уникальный идентификатор", + "중복된 수명을 고유 식별자로 이름 변경" + ), + code: "fn foo<'a, 'b, 'c>(x: &'a str, y: &'b str, z: &'c str) {}" + }], + links: &[ + DocLink { + title: "Rust Book: Lifetimes", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0263.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0309.rs b/masterror-knowledge/src/errors/lifetimes/e0309.rs new file mode 100644 index 0000000..f9c366f --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0309.rs @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0309: parameter type is missing an explicit lifetime bound + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0309", + title: LocalizedText::new( + "Parameter type is missing an explicit lifetime bound", + "Параметр типа не имеет явного ограничения времени жизни", + "매개변수 타입에 명시적 라이프타임 바운드가 없음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A type parameter lacks an explicit lifetime bound required by an associated +type constraint. The compiler cannot verify that all data in the type T is +valid for the required lifetime 'a. + +This commonly happens when: +- A struct field uses an associated type like >::Output +- The trait implementation requires a lifetime bound (e.g., T: 'a) +- The struct definition doesn't declare this same bound in its where-clause", + "\ +Параметр типа не имеет явного ограничения времени жизни, требуемого +ассоциированным типом. Компилятор не может проверить, что все данные +в типе T действительны для требуемого времени жизни 'a. + +Это часто происходит когда: +- Поле структуры использует ассоциированный тип +- Реализация трейта требует ограничения времени жизни +- Определение структуры не объявляет это ограничение", + "\ +타입 매개변수에 연관 타입 제약에 필요한 명시적 라이프타임 바운드가 없습니다. +컴파일러는 타입 T의 모든 데이터가 필요한 라이프타임 'a에 유효한지 확인할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add lifetime bound to type parameter", + "Добавить ограничение времени жизни к параметру типа", + "타입 매개변수에 라이프타임 바운드 추가" + ), + code: "struct Foo<'a, T>\nwhere\n T: 'a,\n{\n foo: >::Output\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Lifetime Bounds", + url: "https://doc.rust-lang.org/reference/trait-bounds.html#lifetime-bounds" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0309.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0310.rs b/masterror-knowledge/src/errors/lifetimes/e0310.rs new file mode 100644 index 0000000..bfc5687 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0310.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0310: parameter type may not live long enough (requires 'static) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0310", + title: LocalizedText::new( + "Parameter type may not live long enough", + "Параметр типа может не жить достаточно долго", + "매개변수 타입이 충분히 오래 살지 않을 수 있음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +Type parameters in type definitions have lifetimes associated with them that +represent how long the data stored within them is guaranteed to live. When a +type parameter is used with a reference that requires a specific lifetime +(like 'static), the type parameter must be constrained to meet that requirement. + +Example: struct Foo { foo: &'static T } fails because T is not constrained +to the 'static lifetime that the reference requires.", + "\ +Параметры типов имеют связанные с ними времена жизни, которые представляют, +как долго данные гарантированно существуют. Когда параметр типа используется +со ссылкой, требующей определённого времени жизни (например 'static), +параметр типа должен быть ограничен для соответствия этому требованию.", + "\ +타입 정의의 타입 매개변수에는 저장된 데이터가 얼마나 오래 유효한지를 나타내는 +라이프타임이 연결되어 있습니다. 타입 매개변수가 특정 라이프타임('static 등)을 +요구하는 참조와 함께 사용될 때, 해당 요구사항을 충족하도록 제약되어야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add 'static lifetime bound to type parameter", + "Добавить ограничение 'static к параметру типа", + "타입 매개변수에 'static 라이프타임 바운드 추가" + ), + code: "struct Foo {\n foo: &'static T\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Static Lifetime", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#the-static-lifetime" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0310.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0311.rs b/masterror-knowledge/src/errors/lifetimes/e0311.rs new file mode 100644 index 0000000..9e6f498 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0311.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0311: unsatisfied outlives bound with elided region + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0311", + title: LocalizedText::new( + "Unsatisfied outlives bound with elided region", + "Неудовлетворённое ограничение outlives с опущенным временем жизни", + "생략된 영역으로 인한 outlives 바운드 불만족" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +This error occurs when there is an unsatisfied outlives bound involving an +elided region and a generic type parameter. The compiler automatically adds +lifetime bounds based on function signatures, and when these don't align with +generic parameter requirements, this error is raised. + +The fix is to explicitly name the elided lifetime and add the outlives bound +to the generic parameter.", + "\ +Эта ошибка возникает, когда есть неудовлетворённое ограничение outlives, +включающее опущенное время жизни и параметр обобщённого типа. Компилятор +автоматически добавляет ограничения времени жизни на основе сигнатур функций, +и когда они не согласуются с требованиями параметра, возникает эта ошибка.", + "\ +생략된 영역과 제네릭 타입 매개변수를 포함하는 outlives 바운드가 충족되지 않을 때 +이 오류가 발생합니다. 컴파일러는 함수 시그니처를 기반으로 라이프타임 바운드를 +자동으로 추가하며, 이것이 제네릭 매개변수 요구사항과 맞지 않으면 이 오류가 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Explicitly name elided lifetime and add bound", + "Явно указать опущенное время жизни и добавить ограничение", + "생략된 라이프타임을 명시하고 바운드 추가" + ), + code: "fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {\n with_restriction::(x)\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Lifetime Elision", + url: "https://doc.rust-lang.org/reference/lifetime-elision.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0311.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0316.rs b/masterror-knowledge/src/errors/lifetimes/e0316.rs new file mode 100644 index 0000000..c8f66b0 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0316.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0316: nested quantification over lifetimes in where clause + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0316", + title: LocalizedText::new( + "Nested quantification over lifetimes", + "Вложенная квантификация по временам жизни", + "라이프타임에 대한 중첩 한정" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A where clause contains a nested quantification over lifetimes, which is not +supported in Rust. Rust syntax allows lifetime quantifications in two places: +1. Quantifying over the trait bound only: Ty: for<'l> Trait<'l> +2. Quantifying over the whole clause: for<'l> &'l Ty: Trait<'l> + +However, using both in the same clause leads to nested lifetime quantification.", + "\ +Where-клауза содержит вложенную квантификацию по временам жизни, которая +не поддерживается в Rust. Синтаксис Rust позволяет квантификацию в двух местах: +1. Квантификация только по trait bound: Ty: for<'l> Trait<'l> +2. Квантификация по всей клаузе: for<'l> &'l Ty: Trait<'l> + +Использование обоих приводит к вложенной квантификации.", + "\ +where 절에 중첩된 라이프타임 한정이 포함되어 있으며, 이는 Rust에서 지원되지 않습니다. +Rust 문법은 두 위치에서 라이프타임 한정을 허용합니다: +1. 트레이트 바운드만 한정: Ty: for<'l> Trait<'l> +2. 전체 절 한정: for<'l> &'l Ty: Trait<'l>" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Combine lifetime parameters in single for<>", + "Объединить параметры времени жизни в один for<>", + "단일 for<>에서 라이프타임 매개변수 결합" + ), + code: "fn foo(t: T)\nwhere\n for<'a, 'b> &'a T: Tr<'a, 'b>,\n{\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Higher-Ranked Trait Bounds", + url: "https://doc.rust-lang.org/reference/trait-bounds.html#higher-ranked-trait-bounds" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0316.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0478.rs b/masterror-knowledge/src/errors/lifetimes/e0478.rs new file mode 100644 index 0000000..b252153 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0478.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0478: lifetime bound not satisfied + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0478", + title: LocalizedText::new( + "Lifetime bound not satisfied", + "Ограничение времени жизни не выполнено", + "라이프타임 바운드가 충족되지 않음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A lifetime parameter doesn't satisfy the required lifetime bounds of a trait +or type. When a trait has a lifetime bound (superbound), any type implementing +or using that trait must ensure its lifetimes respect those bounds. + +The bound 'a: 'b means 'a must live at least as long as 'b.", + "\ +Параметр времени жизни не удовлетворяет требуемым ограничениям трейта +или типа. Когда трейт имеет ограничение времени жизни (superbound), +любой тип, реализующий или использующий этот трейт, должен обеспечить +соответствие своих времён жизни этим ограничениям. + +Ограничение 'a: 'b означает, что 'a должно жить не меньше чем 'b.", + "\ +라이프타임 매개변수가 트레이트 또는 타입의 필수 라이프타임 바운드를 +충족하지 않습니다. 'a: 'b 바운드는 'a가 최소한 'b만큼 살아야 함을 +의미합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add lifetime bound to enforce relationship", + "Добавить ограничение времени жизни", + "관계를 강제하기 위해 라이프타임 바운드 추가" + ), + code: "struct Prince<'kiss, 'snow: 'kiss> {\n child: Box + 'snow>,\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0478.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0482.rs b/masterror-knowledge/src/errors/lifetimes/e0482.rs new file mode 100644 index 0000000..2169687 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0482.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0482: lifetime of returned value doesn't outlive function call + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0482", + title: LocalizedText::new( + "Lifetime of returned value doesn't outlive function call", + "Время жизни возвращаемого значения не переживает вызов функции", + "반환된 값의 라이프타임이 함수 호출보다 오래 살지 않음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +This error occurs when using impl Trait in return types with lifetimes that +don't properly align. The issue arises because impl Trait implicitly applies +a 'static lifetime restriction, but the actual data may only live for a +shorter lifetime. + +Note: This error is no longer emitted by modern compilers.", + "\ +Эта ошибка возникает при использовании impl Trait в возвращаемых типах +с неправильно согласованными временами жизни. Проблема в том, что +impl Trait неявно применяет ограничение 'static, но данные могут жить +только более короткое время. + +Примечание: эта ошибка больше не выдаётся современными компиляторами.", + "\ +이 오류는 라이프타임이 제대로 정렬되지 않는 반환 타입에서 impl Trait를 +사용할 때 발생합니다. impl Trait가 암묵적으로 'static 라이프타임 +제한을 적용하기 때문입니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add lifetime bounds to impl Trait", + "Добавить ограничения времени жизни к impl Trait", + "impl Trait에 라이프타임 바운드 추가" + ), + code: "fn prefix<'a>(\n words: impl Iterator + 'a\n) -> impl Iterator + 'a {\n words.map(|v| format!(\"foo-{}\", v))\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use 'static lifetime", + "Использовать время жизни 'static", + "'static 라이프타임 사용" + ), + code: "fn prefix(\n words: impl Iterator\n) -> impl Iterator {\n words.map(|v| format!(\"foo-{}\", v))\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0482.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0491.rs b/masterror-knowledge/src/errors/lifetimes/e0491.rs new file mode 100644 index 0000000..5c518ff --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0491.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0491: reference has longer lifetime than data it references + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0491", + title: LocalizedText::new( + "Reference has longer lifetime than data it references", + "Ссылка имеет большее время жизни чем данные", + "참조가 참조하는 데이터보다 긴 라이프타임을 가짐" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +The compiler cannot guarantee that a lifetime parameter will outlive another +lifetime parameter in a reference type. When you have a reference with +lifetime 'a to data with lifetime 'b, 'b must outlive 'a to ensure the +reference is always valid.", + "\ +Компилятор не может гарантировать, что один параметр времени жизни +переживёт другой в ссылочном типе. Когда есть ссылка с временем жизни 'a +на данные с временем жизни 'b, 'b должно пережить 'a, чтобы ссылка +всегда была действительна.", + "\ +컴파일러가 참조 타입에서 한 라이프타임 매개변수가 다른 라이프타임 +매개변수보다 오래 살 것을 보장할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add lifetime bound to enforce that 'b outlives 'a", + "Добавить ограничение, чтобы 'b пережило 'a", + "'b가 'a보다 오래 살도록 라이프타임 바운드 추가" + ), + code: "impl<'a, 'b: 'a> Trait<'a, 'b> for usize {\n type Out = &'a Foo<'b>; // works!\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0491.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0495.rs b/masterror-knowledge/src/errors/lifetimes/e0495.rs new file mode 100644 index 0000000..a5ce0a0 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0495.rs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0495: cannot infer an appropriate lifetime + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0495", + title: LocalizedText::new( + "Cannot infer an appropriate lifetime", + "Невозможно вывести подходящее время жизни", + "적절한 라이프타임을 추론할 수 없음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +The compiler found conflicting lifetime requirements and couldn't +determine which one to use.", + "\ +Компилятор обнаружил конфликтующие требования времён жизни.", + "\ +컴파일러가 충돌하는 라이프타임 요구사항을 찾았습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add explicit lifetime bounds", + "Добавить явные ограничения времени жизни", + "명시적 라이프타임 바운드 추가" + ), + code: "fn process<'a, 'b: 'a>(x: &'a str, y: &'b str) -> &'a str" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0495.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0496.rs b/masterror-knowledge/src/errors/lifetimes/e0496.rs new file mode 100644 index 0000000..3c9a1b4 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0496.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0496: lifetime name shadowing + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0496", + title: LocalizedText::new( + "Lifetime name shadows another lifetime", + "Имя времени жизни затеняет другое время жизни", + "라이프타임 이름이 다른 라이프타임을 가림" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +The same lifetime name was used in nested scopes, causing the inner lifetime +to shadow (hide) the outer lifetime. This is not allowed in Rust because it +creates ambiguity about which lifetime is being referenced.", + "\ +Одно и то же имя времени жизни использовано во вложенных областях +видимости, из-за чего внутреннее время жизни затеняет внешнее. +Это запрещено в Rust, так как создаёт неоднозначность.", + "\ +중첩된 스코프에서 같은 라이프타임 이름이 사용되어 내부 라이프타임이 +외부 라이프타임을 가립니다. 이는 어떤 라이프타임이 참조되는지 +모호함을 만들기 때문에 Rust에서 허용되지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Rename one of the conflicting lifetimes", + "Переименовать одно из конфликтующих времён жизни", + "충돌하는 라이프타임 중 하나의 이름 변경" + ), + code: "struct Foo<'a> {\n a: &'a i32,\n}\n\nimpl<'a> Foo<'a> {\n fn f<'b>(x: &'b i32) {} // Use 'b instead of 'a\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0496.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0515.rs b/masterror-knowledge/src/errors/lifetimes/e0515.rs new file mode 100644 index 0000000..f8ca6a2 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0515.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0515: cannot return reference to temporary value + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0515", + title: LocalizedText::new( + "Cannot return reference to temporary value", + "Нельзя вернуть ссылку на временное значение", + "임시 값에 대한 참조를 반환할 수 없음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +You're trying to return a reference to a value that was created inside +the function. When the function returns, that value is dropped. + +The reference would point to freed memory - a dangling pointer.", + "\ +Вы пытаетесь вернуть ссылку на значение, созданное внутри функции. +При возврате из функции это значение будет уничтожено.", + "\ +함수 내에서 생성된 값에 대한 참조를 반환하려고 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Return owned value instead of reference", + "Вернуть владеющее значение вместо ссылки", + "참조 대신 소유 값 반환" + ), + code: "fn create() -> String { String::from(\"hello\") }" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a parameter lifetime", + "Использовать время жизни параметра", + "매개변수 라이프타임 사용" + ), + code: "fn longest<'a>(x: &'a str, y: &'a str) -> &'a str" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0515.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0581.rs b/masterror-knowledge/src/errors/lifetimes/e0581.rs new file mode 100644 index 0000000..3db317f --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0581.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0581: lifetime appears only in return type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0581", + title: LocalizedText::new( + "Lifetime appears only in return type", + "Время жизни появляется только в возвращаемом типе", + "라이프타임이 반환 타입에서만 나타남" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +In a `fn` type, a lifetime parameter must appear in both the argument types +and return type. If a lifetime appears only in the return type and not in +the arguments, it's impossible to determine how long the lifetime should +actually be, since there's nothing constraining it. + +This restriction ensures the compiler can properly track lifetime relationships.", + "\ +В типе `fn` параметр времени жизни должен появляться как в типах аргументов, +так и в возвращаемом типе. Если время жизни появляется только в возвращаемом +типе, невозможно определить, каким оно должно быть на самом деле.", + "\ +`fn` 타입에서 라이프타임 매개변수는 인수 타입과 반환 타입 모두에 나타나야 합니다. +라이프타임이 인수가 아닌 반환 타입에만 나타나면 라이프타임이 실제로 얼마나 +길어야 하는지 결정할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use lifetime in both arguments and return type", + "Использовать время жизни и в аргументах, и в возвращаемом типе", + "인수와 반환 타입 모두에서 라이프타임 사용" + ), + code: "let x: for<'a> fn(&'a i32) -> &'a i32;" + }, + FixSuggestion { + description: LocalizedText::new( + "Use 'static lifetime for return-only case", + "Использовать 'static для случая только возврата", + "반환 전용 케이스에 'static 라이프타임 사용" + ), + code: "let y: fn() -> &'static i32;" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0581.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0582.rs b/masterror-knowledge/src/errors/lifetimes/e0582.rs new file mode 100644 index 0000000..991b8f1 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0582.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0582: lifetime only in associated-type binding + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0582", + title: LocalizedText::new( + "Lifetime only present in associated-type binding", + "Время жизни присутствует только в привязке ассоциированного типа", + "라이프타임이 연관 타입 바인딩에서만 존재" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A lifetime is only present in an associated-type binding, and not in the input +types to the trait. This creates an unsatisfiable constraint because the +compiler cannot guarantee that the lifetime is actually used. + +The lifetime must also appear in the input types to properly constrain it.", + "\ +Время жизни присутствует только в привязке ассоциированного типа, а не +во входных типах трейта. Это создаёт неудовлетворимое ограничение, поскольку +компилятор не может гарантировать, что время жизни действительно используется. + +Время жизни должно также появляться во входных типах.", + "\ +라이프타임이 연관 타입 바인딩에만 존재하고 트레이트의 입력 타입에는 없습니다. +이는 컴파일러가 라이프타임이 실제로 사용된다는 것을 보장할 수 없기 때문에 +충족할 수 없는 제약을 만듭니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Include lifetime in input types", + "Включить время жизни во входные типы", + "입력 타입에 라이프타임 포함" + ), + code: "where F: for<'a> Fn(&'a i32) -> Option<&'a i32>" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0582.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0597.rs b/masterror-knowledge/src/errors/lifetimes/e0597.rs new file mode 100644 index 0000000..bf3f11f --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0597.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0597: value does not live long enough + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0597", + title: LocalizedText::new( + "Value does not live long enough", + "Значение живёт недостаточно долго", + "값이 충분히 오래 살지 않음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +You're creating a reference to something that will be destroyed before +the reference is used. This would create a dangling pointer. + +Rust prevents this at compile time. The referenced value must live at +least as long as the reference itself.", + "\ +Вы создаёте ссылку на что-то, что будет уничтожено до использования ссылки.", + "\ +참조가 사용되기 전에 파괴될 것에 대한 참조를 만들고 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Move value to outer scope", + "Переместить значение во внешнюю область", + "값을 외부 스코프로 이동" + ), + code: "let s = String::from(\"hello\"); // declare before use" + }, + FixSuggestion { + description: LocalizedText::new( + "Return owned value instead", + "Вернуть владеющее значение", + "소유 값 반환" + ), + code: "fn get() -> String { s.to_string() }" + } + ], + links: &[ + DocLink { + title: "Rust Book: Lifetimes", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0597.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0621.rs b/masterror-knowledge/src/errors/lifetimes/e0621.rs new file mode 100644 index 0000000..b7247fc --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0621.rs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0621: explicit lifetime required in the type of X + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0621", + title: LocalizedText::new( + "Explicit lifetime required in the type", + "Требуется явное время жизни в типе", + "타입에 명시적 라이프타임이 필요함" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +The compiler cannot infer lifetimes in this context. You need to add +explicit lifetime annotations to show how references relate.", + "\ +Компилятор не может вывести времена жизни в этом контексте.", + "\ +컴파일러가 이 컨텍스트에서 라이프타임을 추론할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add lifetime parameter to function", + "Добавить параметр времени жизни к функции", + "함수에 라이프타임 매개변수 추가" + ), + code: "fn process<'a>(data: &'a str) -> &'a str { data }" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0621.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0623.rs b/masterror-knowledge/src/errors/lifetimes/e0623.rs new file mode 100644 index 0000000..152bb3b --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0623.rs @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0623: lifetime mismatch + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0623", + title: LocalizedText::new( + "Lifetime mismatch", + "Несоответствие времён жизни", + "라이프타임 불일치" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +Two lifetimes in your code don't match where they should.", + "\ +Два времени жизни в коде не совпадают там, где должны.", + "\ +코드에서 두 라이프타임이 일치해야 하는 곳에서 일치하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Ensure consistent lifetime annotations", + "Обеспечить согласованные аннотации", + "일관된 라이프타임 어노테이션 확보" + ), + code: "fn foo<'a>(x: &'a str) -> &'a str { x }" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0623.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0625.rs b/masterror-knowledge/src/errors/lifetimes/e0625.rs new file mode 100644 index 0000000..3df7da6 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0625.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0625: const cannot refer to thread-local static + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0625", + title: LocalizedText::new( + "Const cannot refer to thread-local static", + "Константа не может ссылаться на thread-local static", + "const는 thread-local static을 참조할 수 없음" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A compile-time const variable is referring to a thread-local static variable. + +Const variables cannot depend on thread-local statics because const values +must be evaluated at compile time, while thread-local statics are inherently +runtime-dependent.", + "\ +Константа времени компиляции ссылается на thread-local static переменную. + +Константы не могут зависеть от thread-local statics, потому что значения +констант должны быть вычислены во время компиляции, тогда как thread-local +statics по своей природе зависят от времени выполнения.", + "\ +컴파일 시간 const 변수가 thread-local static 변수를 참조하고 있습니다. +const 값은 컴파일 시간에 평가되어야 하지만 thread-local statics는 +본질적으로 런타임 의존적입니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Extract value as separate const", + "Извлечь значение как отдельную константу", + "값을 별도의 const로 추출" + ), + code: "const C: usize = 12;\n\n#[thread_local]\nstatic X: usize = C;\n\nconst Y: usize = 2 * C; // both refer to const C" + }], + links: &[ + DocLink { + title: "Constants", + url: "https://doc.rust-lang.org/reference/items/constant-items.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0625.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0626.rs b/masterror-knowledge/src/errors/lifetimes/e0626.rs new file mode 100644 index 0000000..db5addd --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0626.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0626: borrow persists across yield point + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0626", + title: LocalizedText::new( + "Borrow in coroutine persists across yield point", + "Заимствование в сопрограмме сохраняется через точку yield", + "코루틴의 빌림이 yield 지점을 넘어 지속됨" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A borrow remains in scope across a `yield` point in a movable (unmarked) +coroutine. This is not permitted because the coroutine could be moved while +the borrow is still active, violating borrow safety rules. + +In an unmarked (movable) coroutine, you cannot have a borrow that is still +in scope when a `yield` occurs.", + "\ +Заимствование остаётся в области видимости через точку `yield` в подвижной +(непомеченной) сопрограмме. Это не разрешено, потому что сопрограмма может +быть перемещена, пока заимствование ещё активно, нарушая правила +безопасности заимствования. + +В непомеченной (подвижной) сопрограмме у вас не может быть заимствования, +которое ещё находится в области видимости при выполнении `yield`.", + "\ +이동 가능한(표시되지 않은) 코루틴에서 빌림이 `yield` 지점을 넘어 +범위 내에 남아 있습니다. 코루틴이 빌림이 활성화된 상태에서 이동될 수 +있어 빌림 안전 규칙을 위반할 수 있으므로 허용되지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Mark the coroutine as static", + "Пометить сопрограмму как static", + "코루틴을 static으로 표시" + ), + code: "let mut b = #[coroutine] static || {\n let a = &String::from(\"hello\");\n yield ();\n println!(\"{}\", a);\n};" + }, + FixSuggestion { + description: LocalizedText::new( + "Store by value instead of borrowing", + "Хранить по значению вместо заимствования", + "빌림 대신 값으로 저장" + ), + code: "let mut b = #[coroutine] || {\n let a = String::from(\"hello\");\n yield ();\n println!(\"{}\", a);\n};" + } + ], + links: &[ + DocLink { + title: "Coroutines", + url: "https://doc.rust-lang.org/std/ops/trait.Coroutine.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0626.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0637.rs b/masterror-knowledge/src/errors/lifetimes/e0637.rs new file mode 100644 index 0000000..2b626c4 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0637.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0637: underscore lifetime used illegally + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0637", + title: LocalizedText::new( + "'_ lifetime used in illegal place", + "Время жизни '_ использовано в недопустимом месте", + "'_ 라이프타임이 잘못된 위치에서 사용됨" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +The `'_` lifetime name or `&T` without an explicit lifetime name has been +used in an illegal place. + +The `'_` lifetime is reserved for the anonymous lifetime and cannot be +used as a named lifetime identifier in some places. Similarly, `&T` without +an explicit lifetime name is not permitted in certain contexts like trait +bounds and where clauses.", + "\ +Имя времени жизни `'_` или `&T` без явного имени времени жизни было +использовано в недопустимом месте. + +Время жизни `'_` зарезервировано для анонимного времени жизни и не может +использоваться как именованный идентификатор времени жизни в некоторых +местах. Аналогично, `&T` без явного имени времени жизни не допускается +в определённых контекстах, таких как ограничения трейтов и where-предложения.", + "\ +`'_` 라이프타임 이름 또는 명시적 라이프타임 이름이 없는 `&T`가 +잘못된 위치에서 사용되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use explicit lifetime name", + "Использовать явное имя времени жизни", + "명시적 라이프타임 이름 사용" + ), + code: "fn foo<'a>(str1: &'a str, str2: &'a str) -> &'a str { }" + }, + FixSuggestion { + description: LocalizedText::new( + "Use higher-ranked trait bounds", + "Использовать ограничения трейтов высшего ранга", + "고차 트레이트 바운드 사용" + ), + code: "fn foo()\nwhere\n T: for<'a> Into<&'a u32>,\n{}" + } + ], + links: &[ + DocLink { + title: "Lifetime Elision", + url: "https://doc.rust-lang.org/reference/lifetime-elision.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0637.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0657.rs b/masterror-knowledge/src/errors/lifetimes/e0657.rs new file mode 100644 index 0000000..1535653 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0657.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0657: impl Trait captures higher-ranked lifetime + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0657", + title: LocalizedText::new( + "impl Trait captured higher-ranked lifetime", + "impl Trait захватил время жизни высшего ранга", + "impl Trait가 고차 라이프타임을 캡처함" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +An `impl Trait` type attempts to capture a higher-ranked lifetime +(a lifetime introduced by a `for<'a>` binder), which is not supported. + +`impl Trait` types are only allowed to capture lifetimes from their parent +items, not from any `for<'a>` binders in scope.", + "\ +Тип `impl Trait` пытается захватить время жизни высшего ранга +(время жизни, введённое связывателем `for<'a>`), что не поддерживается. + +Типам `impl Trait` разрешено захватывать только времена жизни из их +родительских элементов, но не из связывателей `for<'a>` в области видимости.", + "\ +`impl Trait` 타입이 고차 라이프타임(`for<'a>` 바인더로 도입된 +라이프타임)을 캡처하려고 시도하는데, 이는 지원되지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Avoid capturing higher-ranked lifetimes in impl Trait", + "Избегать захвата времён жизни высшего ранга в impl Trait", + "impl Trait에서 고차 라이프타임 캡처 피하기" + ), + code: "// Refactor to use concrete types for associated types" + }], + links: &[ + DocLink { + title: "Higher-Ranked Trait Bounds", + url: "https://doc.rust-lang.org/nomicon/hrtb.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0657.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0700.rs b/masterror-knowledge/src/errors/lifetimes/e0700.rs new file mode 100644 index 0000000..f0ec8d0 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0700.rs @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0700: hidden type captures lifetime + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0700", + title: LocalizedText::new( + "Hidden type captures lifetime", + "Скрытый тип захватывает время жизни", + "숨겨진 타입이 라이프타임을 캡처함" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +When using `impl Trait` return type, the hidden concrete type captures +a lifetime that isn't declared in the function signature.", + "\ +При использовании типа возврата `impl Trait` скрытый конкретный тип +захватывает время жизни, не объявленное в сигнатуре.", + "\ +`impl Trait` 반환 타입을 사용할 때, 숨겨진 구체적 타입이 선언되지 않은 라이프타임을 캡처합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Declare the captured lifetime", + "Объявить захваченное время жизни", + "캡처된 라이프타임 선언" + ), + code: "fn foo<'a>(x: &'a str) -> impl Iterator + 'a" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0700.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0716.rs b/masterror-knowledge/src/errors/lifetimes/e0716.rs new file mode 100644 index 0000000..f12a054 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0716.rs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0716: temporary value dropped while borrowed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0716", + title: LocalizedText::new( + "Temporary value dropped while borrowed", + "Временное значение уничтожено во время заимствования", + "빌린 동안 임시 값이 삭제됨" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A temporary value was created, borrowed, and then immediately dropped. +The borrow outlives the temporary. + +Temporaries only live until the end of the statement by default.", + "\ +Было создано временное значение, заимствовано и сразу уничтожено.", + "\ +임시 값이 생성되고, 빌려지고, 즉시 삭제되었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Bind temporary to a variable", + "Привязать временное значение к переменной", + "임시 값을 변수에 바인딩" + ), + code: "let value = create_value();\nlet reference = &value;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0716.html" + }] +}; diff --git a/masterror-knowledge/src/errors/lifetimes/e0803.rs b/masterror-knowledge/src/errors/lifetimes/e0803.rs new file mode 100644 index 0000000..05661f8 --- /dev/null +++ b/masterror-knowledge/src/errors/lifetimes/e0803.rs @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0803: lifetime mismatch in trait implementation + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0803", + title: LocalizedText::new( + "Lifetime mismatch in trait implementation", + "Несоответствие времён жизни в реализации трейта", + "트레이트 구현에서 라이프타임 불일치" + ), + category: Category::Lifetimes, + explanation: LocalizedText::new( + "\ +A trait implementation returns a reference without an explicit lifetime +linking it to `self`. This commonly arises in generic trait implementations +requiring explicit lifetime bounds. + +The issue occurs when: +- A trait method returns a reference +- The trait is implemented for a struct with a lifetime parameter +- The compiler cannot verify if the returned reference satisfies constraints + +Solution: Explicitly bind lifetimes in the trait definition and implementation.", + "\ +Реализация трейта возвращает ссылку без явного времени жизни, +связывающего её с `self`. Это часто возникает в обобщённых +реализациях трейтов, требующих явных ограничений времени жизни. + +Проблема возникает когда: +- Метод трейта возвращает ссылку +- Трейт реализован для структуры с параметром времени жизни +- Компилятор не может проверить, удовлетворяет ли ссылка ограничениям + +Решение: явно привязать времена жизни в определении и реализации трейта.", + "\ +트레이트 구현이 `self`에 명시적 라이프타임 연결 없이 참조를 반환합니다. +이는 명시적 라이프타임 바운드가 필요한 제네릭 트레이트 구현에서 자주 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add lifetime parameter to trait", + "Добавить параметр времени жизни в трейт", + "트레이트에 라이프타임 매개변수 추가" + ), + code: "\ +trait DataAccess<'a, T> { + fn get_ref(&'a self) -> T; +} + +impl<'a> DataAccess<'a, &'a f64> for Container<'a> { + fn get_ref(&'a self) -> &'a f64 { + self.value + } +}" + }], + links: &[ + DocLink { + title: "Rust Book: Lifetimes", + url: "https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0803.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/linking.rs b/masterror-knowledge/src/errors/linking.rs new file mode 100644 index 0000000..65f8b73 --- /dev/null +++ b/masterror-knowledge/src/errors/linking.rs @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Crate linking related errors. + +mod e0460; +mod e0461; +mod e0462; +mod e0463; +mod e0464; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0460::ENTRY, + &e0461::ENTRY, + &e0462::ENTRY, + &e0463::ENTRY, + &e0464::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/linking/e0460.rs b/masterror-knowledge/src/errors/linking/e0460.rs new file mode 100644 index 0000000..48f5d73 --- /dev/null +++ b/masterror-knowledge/src/errors/linking/e0460.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0460: found possibly newer version of crate + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0460", + title: LocalizedText::new( + "Found possibly newer version of crate", + "Найдена возможно более новая версия крейта", + "크레이트의 더 새로운 버전이 발견됨" + ), + category: Category::Linking, + explanation: LocalizedText::new( + "\ +A program depends on two different versions of the same crate, creating an +incompatible dependency chain. This happens when: +- Your crate depends on crate `a` version 1 +- Your crate also depends on crate `b` +- Crate `b` depends on crate `a` version 2 + +The version mismatch is tracked using SVH (Strict Version Hash).", + "\ +Программа зависит от двух разных версий одного и того же крейта, +создавая несовместимую цепочку зависимостей. Это происходит когда: +- Ваш крейт зависит от крейта `a` версии 1 +- Ваш крейт также зависит от крейта `b` +- Крейт `b` зависит от крейта `a` версии 2", + "\ +프로그램이 같은 크레이트의 두 가지 다른 버전에 의존하여 호환되지 +않는 의존성 체인을 만듭니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use Cargo to manage dependencies", + "Использовать Cargo для управления зависимостями", + "Cargo를 사용하여 의존성 관리" + ), + code: "# Cargo automatically resolves dependencies" + }, + FixSuggestion { + description: LocalizedText::new( + "Recompile with consistent versions", + "Перекомпилировать с согласованными версиями", + "일관된 버전으로 재컴파일" + ), + code: "# Ensure all crates depend on same version" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0460.html" + }] +}; diff --git a/masterror-knowledge/src/errors/linking/e0461.rs b/masterror-knowledge/src/errors/linking/e0461.rs new file mode 100644 index 0000000..4484e7b --- /dev/null +++ b/masterror-knowledge/src/errors/linking/e0461.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0461: crate with mismatched target triple + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0461", + title: LocalizedText::new( + "Couldn't find crate with expected target triple", + "Не удалось найти крейт с ожидаемым целевым триплетом", + "예상된 타겟 트리플을 가진 크레이트를 찾을 수 없음" + ), + category: Category::Linking, + explanation: LocalizedText::new( + "\ +Rust cannot find a required crate compiled for the target architecture. +When linking crates together, they must be compiled for the same target +triple (architecture/OS combination). If one crate is compiled for x86_64 +and another for ARM, they have incompatible binary formats.", + "\ +Rust не может найти требуемый крейт, скомпилированный для целевой +архитектуры. При связывании крейтов они должны быть скомпилированы +для одного целевого триплета. Если один крейт скомпилирован для x86_64, +а другой для ARM, они имеют несовместимые бинарные форматы.", + "\ +Rust가 타겟 아키텍처용으로 컴파일된 필수 크레이트를 찾을 수 없습니다. +크레이트를 연결할 때 같은 타겟 트리플로 컴파일되어야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use Cargo to manage targets", + "Использовать Cargo для управления целями", + "Cargo를 사용하여 타겟 관리" + ), + code: "# Cargo handles target triples automatically" + }, + FixSuggestion { + description: LocalizedText::new( + "Recompile with consistent --target flag", + "Перекомпилировать с одинаковым флагом --target", + "일관된 --target 플래그로 재컴파일" + ), + code: "rustc --target x86_64-unknown-linux-gnu lib.rs\nrustc --target x86_64-unknown-linux-gnu main.rs" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0461.html" + }] +}; diff --git a/masterror-knowledge/src/errors/linking/e0462.rs b/masterror-knowledge/src/errors/linking/e0462.rs new file mode 100644 index 0000000..434ead6 --- /dev/null +++ b/masterror-knowledge/src/errors/linking/e0462.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0462: found staticlib instead of rlib/dylib + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0462", + title: LocalizedText::new( + "Found staticlib instead of rlib or dylib", + "Найден staticlib вместо rlib или dylib", + "rlib 또는 dylib 대신 staticlib이 발견됨" + ), + category: Category::Linking, + explanation: LocalizedText::new( + "\ +An attempt was made to link a crate compiled as staticlib from another +Rust crate. A staticlib is a static library format intended only for +linking with non-Rust applications (like C programs). It is not a valid +crate type for Rust-to-Rust linking. + +Valid Rust crate types for Rust linking: rlib or dylib.", + "\ +Попытка связать крейт, скомпилированный как staticlib, из другого +крейта Rust. Staticlib - формат статической библиотеки, предназначенный +только для связывания с не-Rust приложениями (например, C программами). + +Допустимые типы крейтов для связывания Rust: rlib или dylib.", + "\ +다른 Rust 크레이트에서 staticlib로 컴파일된 크레이트를 연결하려고 +시도했습니다. staticlib은 비Rust 애플리케이션(C 프로그램 등)과 +연결하기 위한 정적 라이브러리 형식입니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Recompile as rlib or dylib", + "Перекомпилировать как rlib или dylib", + "rlib 또는 dylib로 재컴파일" + ), + code: "#![crate_type = \"rlib\"]\n// or in Cargo.toml:\n// [lib]\n// crate-type = [\"rlib\"]" + }], + links: &[ + DocLink { + title: "Linkage", + url: "https://doc.rust-lang.org/reference/linkage.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0462.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/linking/e0463.rs b/masterror-knowledge/src/errors/linking/e0463.rs new file mode 100644 index 0000000..0c61655 --- /dev/null +++ b/masterror-knowledge/src/errors/linking/e0463.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0463: can't find crate + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0463", + title: LocalizedText::new( + "Can't find crate", + "Не удаётся найти крейт", + "크레이트를 찾을 수 없음" + ), + category: Category::Linking, + explanation: LocalizedText::new( + "\ +A crate was declared but cannot be found. This happens when: +- The crate is not present in dependencies +- The crate exists under a different name +- For std/core: cross-compiling for an unsupported target + +If missing std or core when cross-compiling: +- Add precompiled version via rustup target add +- Build std from source with cargo build -Z build-std +- Use #![no_std] to avoid requiring std", + "\ +Крейт объявлен, но не найден. Это происходит когда: +- Крейт отсутствует в зависимостях +- Крейт существует под другим именем +- Для std/core: кросс-компиляция для неподдерживаемой цели + +Если отсутствует std или core при кросс-компиляции: +- Добавить прекомпилированную версию через rustup target add +- Собрать std из исходников с cargo build -Z build-std +- Использовать #![no_std]", + "\ +크레이트가 선언되었지만 찾을 수 없습니다. 다음 경우에 발생합니다: +- 크레이트가 의존성에 없음 +- 크레이트가 다른 이름으로 존재 +- std/core의 경우: 지원되지 않는 타겟으로 크로스 컴파일" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add the crate to Cargo.toml", + "Добавить крейт в Cargo.toml", + "Cargo.toml에 크레이트 추가" + ), + code: "[dependencies]\nfoo = \"1.0\"" + }, + FixSuggestion { + description: LocalizedText::new( + "Add target for cross-compilation", + "Добавить цель для кросс-компиляции", + "크로스 컴파일을 위한 타겟 추가" + ), + code: "rustup target add thumbv7em-none-eabihf" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0463.html" + }] +}; diff --git a/masterror-knowledge/src/errors/linking/e0464.rs b/masterror-knowledge/src/errors/linking/e0464.rs new file mode 100644 index 0000000..e515326 --- /dev/null +++ b/masterror-knowledge/src/errors/linking/e0464.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0464: multiple matching crates found + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0464", + title: LocalizedText::new( + "Multiple library files found with the same crate name", + "Найдено несколько библиотек с одним именем крейта", + "같은 크레이트 이름을 가진 여러 라이브러리 파일이 발견됨" + ), + category: Category::Linking, + explanation: LocalizedText::new( + "\ +The Rust compiler found multiple library files with the same crate name, +making it unable to determine which one to use. This can occur when: +- Multiple versions of a crate exist in the search path +- Caching issues with the build directory +- Using extern crate without specifying the path", + "\ +Компилятор Rust нашёл несколько библиотечных файлов с одинаковым именем +крейта и не может определить, какой использовать. Это может произойти: +- Несколько версий крейта в пути поиска +- Проблемы кэширования в директории сборки +- Использование extern crate без указания пути", + "\ +Rust 컴파일러가 같은 크레이트 이름을 가진 여러 라이브러리 파일을 +발견하여 어떤 것을 사용할지 결정할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Clean the build directory", + "Очистить директорию сборки", + "빌드 디렉토리 정리" + ), + code: "cargo clean" + }, + FixSuggestion { + description: LocalizedText::new( + "Specify the full path to the crate", + "Указать полный путь к крейту", + "크레이트에 대한 전체 경로 지정" + ), + code: "rustc --extern crate_name=/path/to/libcrate.rlib main.rs" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0464.html" + }] +}; diff --git a/masterror-knowledge/src/errors/ownership.rs b/masterror-knowledge/src/errors/ownership.rs new file mode 100644 index 0000000..81e599f --- /dev/null +++ b/masterror-knowledge/src/errors/ownership.rs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Ownership-related errors. + +mod e0373; +mod e0381; +mod e0382; +mod e0383; +mod e0384; +mod e0505; +mod e0507; +mod e0509; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0373::ENTRY, + &e0381::ENTRY, + &e0382::ENTRY, + &e0383::ENTRY, + &e0384::ENTRY, + &e0505::ENTRY, + &e0507::ENTRY, + &e0509::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/ownership/e0373.rs b/masterror-knowledge/src/errors/ownership/e0373.rs new file mode 100644 index 0000000..e5344d3 --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0373.rs @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0373: captured variable may not live long enough + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0373", + title: LocalizedText::new( + "Captured variable may not live long enough", + "Захваченная переменная может жить недостаточно долго", + "캡처된 변수가 충분히 오래 살지 않을 수 있음" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +This error occurs when attempting to use data captured by a closure after that +data may no longer exist. It's commonly encountered in: + +1. Returning closures - Stack-allocated data captured by reference becomes + invalid once the function returns +2. Spawning threads - The stack frame containing captured variables may + disappear before the thread completes +3. Using async blocks - Async blocks may capture data by reference but + execute later + +The `move` keyword causes the closure to own the captured data rather than +taking references to it, eliminating lifetime issues.", + "\ +Эта ошибка возникает при попытке использовать данные, захваченные замыканием, +после того как эти данные могут перестать существовать. Часто встречается: + +1. При возврате замыканий - данные на стеке, захваченные по ссылке, становятся + недействительными после возврата из функции +2. При порождении потоков - стековый кадр с захваченными переменными может + исчезнуть до завершения потока +3. При использовании async-блоков - они могут захватить данные по ссылке, + но выполниться позже + +Ключевое слово `move` заставляет замыкание владеть захваченными данными.", + "\ +이 오류는 클로저에 의해 캡처된 데이터가 더 이상 존재하지 않을 수 있는 시점에 +사용하려고 할 때 발생합니다. 일반적으로 다음 상황에서 발생합니다: + +1. 클로저 반환 - 참조로 캡처된 스택 할당 데이터는 함수 반환 후 무효화됨 +2. 스레드 생성 - 캡처된 변수를 포함하는 스택 프레임이 스레드 완료 전에 사라질 수 있음 +3. async 블록 사용 - 참조로 데이터를 캡처하지만 나중에 실행됨" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use move closure to transfer ownership", + "Использовать move-замыкание для передачи владения", + "소유권을 이전하기 위해 move 클로저 사용" + ), + code: "fn foo() -> Box u32> {\n let x = 0u32;\n Box::new(move |y| x + y) // x is moved into closure\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Clone the value before capturing", + "Клонировать значение перед захватом", + "캡처 전에 값 복제" + ), + code: "let data = data.clone();\nstd::thread::spawn(move || {\n // use data\n});" + } + ], + links: &[ + DocLink { + title: "Rust Book: Closures", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0373.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/ownership/e0381.rs b/masterror-knowledge/src/errors/ownership/e0381.rs new file mode 100644 index 0000000..8518c29 --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0381.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0381: borrow of possibly-uninitialized variable + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0381", + title: LocalizedText::new( + "Borrow of possibly-uninitialized variable", + "Заимствование возможно неинициализированной переменной", + "초기화되지 않았을 수 있는 변수의 빌림" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +Rust requires all variables to be initialized before use. You're trying +to use a variable that might not have been assigned a value yet. + +This prevents reading garbage memory. The compiler tracks initialization +through all possible code paths.", + "\ +Rust требует инициализации всех переменных перед использованием. +Вы пытаетесь использовать переменную, которая может быть не инициализирована. + +Это предотвращает чтение мусора из памяти.", + "\ +Rust는 사용 전에 모든 변수를 초기화해야 합니다. +아직 값이 할당되지 않았을 수 있는 변수를 사용하려고 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Initialize the variable", + "Инициализировать переменную", + "변수 초기화" + ), + code: "let x = 0; // or any default value" + }, + FixSuggestion { + description: LocalizedText::new( + "Use Option for maybe-uninitialized", + "Использовать Option для возможно неинициализированных", + "초기화되지 않을 수 있는 경우 Option 사용" + ), + code: "let x: Option = None;\nif condition { x = Some(42); }" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0381.html" + }] +}; diff --git a/masterror-knowledge/src/errors/ownership/e0382.rs b/masterror-knowledge/src/errors/ownership/e0382.rs new file mode 100644 index 0000000..f5371d6 --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0382.rs @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0382: borrow of moved value + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0382", + title: LocalizedText::new( + "Borrow of moved value", + "Заимствование перемещённого значения", + "이동된 값의 빌림" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +In Rust, each value has exactly one owner at a time. This is the foundation +of Rust's memory safety guarantees without garbage collection. + +When you assign a value to another variable or pass it to a function, +ownership MOVES to the new location. The original variable becomes invalid +and cannot be used anymore. + +This happens because Rust needs to know exactly when to free memory. +With one owner, there's no ambiguity about who is responsible for cleanup.", + "\ +В Rust каждое значение имеет ровно одного владельца. Это основа +гарантий безопасности памяти без сборщика мусора. + +Когда вы присваиваете значение другой переменной или передаёте в функцию, +владение ПЕРЕМЕЩАЕТСЯ. Исходная переменная становится недействительной. + +Rust должен точно знать, когда освобождать память. +С одним владельцем нет неоднозначности в том, кто отвечает за очистку.", + "\ +Rust에서 각 값은 정확히 하나의 소유자를 가집니다. 이것이 가비지 컬렉터 없이 +메모리 안전성을 보장하는 기반입니다. + +값을 다른 변수에 할당하거나 함수에 전달하면 소유권이 새 위치로 이동합니다. +원래 변수는 무효화되어 더 이상 사용할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Clone the value (creates a deep copy)", + "Клонировать значение (глубокая копия)", + "값을 복제 (깊은 복사)" + ), + code: "let s2 = s.clone();" + }, + FixSuggestion { + description: LocalizedText::new( + "Borrow with a reference (no copy)", + "Заимствовать по ссылке (без копии)", + "참조로 빌림 (복사 없음)" + ), + code: "let s2 = &s;" + }, + FixSuggestion { + description: LocalizedText::new( + "Implement Copy trait (for small types)", + "Реализовать Copy (для маленьких типов)", + "Copy 트레이트 구현 (작은 타입용)" + ), + code: "#[derive(Copy, Clone)]" + } + ], + links: &[ + DocLink { + title: "Rust Book: Ownership", + url: "https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0382.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/ownership/e0383.rs b/masterror-knowledge/src/errors/ownership/e0383.rs new file mode 100644 index 0000000..ebf37f9 --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0383.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0383: partial reinitialization of uninitialized structure + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0383", + title: LocalizedText::new( + "Partial reinitialization of uninitialized structure", + "Частичная переинициализация неинициализированной структуры", + "초기화되지 않은 구조체의 부분 재초기화" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +You're trying to partially reinitialize a struct that was moved from. +After a move, the entire struct is invalid - you can't assign to just +one field. + +You must reinitialize the entire struct.", + "\ +Вы пытаетесь частично переинициализировать структуру после перемещения. +После перемещения вся структура недействительна - нельзя присвоить +только одно поле. + +Нужно переинициализировать всю структуру.", + "\ +이동된 구조체를 부분적으로 재초기화하려고 합니다. +이동 후 전체 구조체가 무효화됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Reinitialize the entire struct", + "Переинициализировать всю структуру", + "전체 구조체 재초기화" + ), + code: "s = MyStruct { field1: val1, field2: val2 };" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0383.html" + }] +}; diff --git a/masterror-knowledge/src/errors/ownership/e0384.rs b/masterror-knowledge/src/errors/ownership/e0384.rs new file mode 100644 index 0000000..19696a4 --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0384.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0384: cannot assign twice to immutable variable + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0384", + title: LocalizedText::new( + "Cannot assign twice to immutable variable", + "Нельзя присвоить дважды неизменяемой переменной", + "불변 변수에 두 번 할당할 수 없음" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +Variables in Rust are immutable by default. Once a value is bound to a name, +you cannot change it unless you explicitly mark it as mutable with `mut`. + +This is a deliberate design choice that makes code easier to reason about. +When you see a variable without `mut`, you know it won't change.", + "\ +Переменные в Rust неизменяемы по умолчанию. После привязки значения +к имени вы не можете его изменить без явного указания `mut`. + +Это осознанное решение, упрощающее понимание кода. +Если переменная без `mut`, она не изменится.", + "\ +Rust의 변수는 기본적으로 불변입니다. 값이 이름에 바인딩되면 +`mut`로 명시적으로 표시하지 않는 한 변경할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Make the variable mutable", + "Сделать переменную изменяемой", + "변수를 가변으로 만들기" + ), + code: "let mut x = 5;\nx = 10;" + }, + FixSuggestion { + description: LocalizedText::new( + "Use shadowing (create new binding)", + "Использовать затенение (новая привязка)", + "섀도잉 사용 (새 바인딩 생성)" + ), + code: "let x = 5;\nlet x = 10; // shadows the first x" + } + ], + links: &[ + DocLink { + title: "Rust Book: Variables and Mutability", + url: "https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0384.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/ownership/e0505.rs b/masterror-knowledge/src/errors/ownership/e0505.rs new file mode 100644 index 0000000..e76eec9 --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0505.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0505: cannot move out of X because it is borrowed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0505", + title: LocalizedText::new( + "Cannot move out because it is borrowed", + "Нельзя переместить, так как значение заимствовано", + "빌려져 있어서 이동할 수 없음" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +You're trying to move a value while a borrow of it still exists. +This would invalidate the reference, creating a dangling pointer. + +The borrow must end (go out of scope) before you can move the value. + +Rust tracks the lifetime of all borrows to prevent this at compile time.", + "\ +Вы пытаетесь переместить значение, пока существует его заимствование. +Это сделает ссылку недействительной. + +Заимствование должно закончиться до перемещения значения.", + "\ +빌림이 존재하는 동안 값을 이동하려고 합니다. +이것은 참조를 무효화하여 댕글링 포인터를 만듭니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "End the borrow before moving", + "Завершить заимствование перед перемещением", + "이동 전에 빌림 종료" + ), + code: "{ let r = &x; use(r); } // borrow ends\nmove_value(x);" + }, + FixSuggestion { + description: LocalizedText::new( + "Clone before borrowing", + "Клонировать перед заимствованием", + "빌리기 전에 복제" + ), + code: "let cloned = x.clone();\nlet r = &cloned;\nmove_value(x);" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0505.html" + }] +}; diff --git a/masterror-knowledge/src/errors/ownership/e0507.rs b/masterror-knowledge/src/errors/ownership/e0507.rs new file mode 100644 index 0000000..3df095f --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0507.rs @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0507: cannot move out of borrowed content + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0507", + title: LocalizedText::new( + "Cannot move out of borrowed content", + "Нельзя переместить из заимствованного содержимого", + "빌린 내용에서 이동할 수 없음" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +You're trying to take ownership of a value that you only have a reference to. +References are borrows - they don't own the data. + +Moving out of a reference would leave the original owner with invalid data, +violating Rust's memory safety guarantees. + +Common cases: +- Indexing into a Vec or array with `vec[i]` and trying to own the element +- Dereferencing a reference and trying to move the value +- Pattern matching on borrowed data with ownership patterns", + "\ +Вы пытаетесь забрать владение значением, на которое у вас только ссылка. +Ссылки - это заимствования, они не владеют данными. + +Перемещение из ссылки оставит исходного владельца с недействительными данными. + +Частые случаи: +- Индексация Vec с попыткой забрать элемент +- Разыменование ссылки с попыткой переместить +- Pattern matching на заимствованных данных", + "\ +참조만 있는 값의 소유권을 가져오려고 합니다. +참조는 빌림입니다 - 데이터를 소유하지 않습니다. + +참조에서 이동하면 원래 소유자가 무효한 데이터를 갖게 됩니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new("Clone the value", "Клонировать значение", "값 복제"), + code: "let owned = borrowed.clone();" + }, + FixSuggestion { + description: LocalizedText::new( + "Use mem::take or mem::replace", + "Использовать mem::take или mem::replace", + "mem::take 또는 mem::replace 사용" + ), + code: "let owned = std::mem::take(&mut vec[i]);" + }, + FixSuggestion { + description: LocalizedText::new( + "Use swap_remove for Vec", + "Использовать swap_remove для Vec", + "Vec에 swap_remove 사용" + ), + code: "let owned = vec.swap_remove(i);" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0507.html" + }] +}; diff --git a/masterror-knowledge/src/errors/ownership/e0509.rs b/masterror-knowledge/src/errors/ownership/e0509.rs new file mode 100644 index 0000000..4d39ab1 --- /dev/null +++ b/masterror-knowledge/src/errors/ownership/e0509.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0509: cannot move out of type X, which implements the Drop trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0509", + title: LocalizedText::new( + "Cannot move out of type which implements Drop", + "Нельзя переместить из типа, реализующего Drop", + "Drop을 구현하는 타입에서 이동할 수 없음" + ), + category: Category::Ownership, + explanation: LocalizedText::new( + "\ +Types that implement Drop have custom cleanup logic that runs when they're +destroyed. Moving a field out would leave the struct in a partially valid +state, and Drop wouldn't know what to clean up. + +Rust prevents this to ensure Drop always sees a valid value.", + "\ +Типы с Drop имеют пользовательскую логику очистки при уничтожении. +Перемещение поля оставит структуру в частично валидном состоянии, +и Drop не будет знать, что очищать. + +Rust предотвращает это для гарантии валидности значения в Drop.", + "\ +Drop을 구현하는 타입은 파괴될 때 실행되는 사용자 정의 정리 로직이 있습니다. +필드를 이동하면 구조체가 부분적으로 유효한 상태가 됩니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new("Clone the field", "Клонировать поле", "필드 복제"), + code: "let field = self.field.clone();" + }, + FixSuggestion { + description: LocalizedText::new( + "Use Option and take()", + "Использовать Option и take()", + "Option과 take() 사용" + ), + code: "struct S { field: Option }\nlet field = self.field.take();" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0509.html" + }] +}; diff --git a/masterror-knowledge/src/errors/patterns.rs b/masterror-knowledge/src/errors/patterns.rs new file mode 100644 index 0000000..22ab4a7 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns.rs @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Pattern matching errors. + +mod e0004; +mod e0005; +mod e0023; +mod e0025; +mod e0026; +mod e0027; +mod e0029; +mod e0030; +mod e0033; +mod e0158; +mod e0164; +mod e0170; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0004::ENTRY, + &e0005::ENTRY, + &e0023::ENTRY, + &e0025::ENTRY, + &e0026::ENTRY, + &e0027::ENTRY, + &e0029::ENTRY, + &e0030::ENTRY, + &e0033::ENTRY, + &e0158::ENTRY, + &e0164::ENTRY, + &e0170::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/patterns/e0004.rs b/masterror-knowledge/src/errors/patterns/e0004.rs new file mode 100644 index 0000000..eaec9a1 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0004.rs @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0004: non-exhaustive patterns in match expression + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0004", + title: LocalizedText::new( + "Non-exhaustive patterns in match", + "Неполное покрытие вариантов в match", + "match에서 패턴이 완전하지 않음" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when a `match` expression doesn't cover all possible values +of the input type. The compiler requires that match expressions handle every +possible case to guarantee a value can be assigned. + +Example: + enum Color { Red, Green, Blue } + match color { + Color::Red => {}, + Color::Green => {}, + // missing Color::Blue! + }", + "\ +Эта ошибка возникает, когда выражение `match` не покрывает все возможные +значения входного типа. Компилятор требует, чтобы match обрабатывал каждый +возможный случай.", + "\ +이 오류는 `match` 표현식이 입력 타입의 모든 가능한 값을 다루지 않을 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Cover all enum variants explicitly", + "Явно указать все варианты enum", + "모든 열거형 변형을 명시적으로 처리" + ), + code: "match color {\n Color::Red => {},\n Color::Green => {},\n Color::Blue => {},\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use wildcard pattern to catch remaining cases", + "Использовать шаблон _ для остальных случаев", + "와일드카드 패턴으로 나머지 케이스 처리" + ), + code: "match color {\n Color::Red => {},\n _ => {},\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Patterns and Matching", + url: "https://doc.rust-lang.org/book/ch18-00-patterns.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0004.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0005.rs b/masterror-knowledge/src/errors/patterns/e0005.rs new file mode 100644 index 0000000..b7f9b77 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0005.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0005: refutable pattern in local binding + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0005", + title: LocalizedText::new( + "Refutable pattern in local binding", + "Опровержимый паттерн в локальной привязке", + "로컬 바인딩에서 반박 가능한 패턴" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when you use a pattern in a `let` binding that can fail to +match (refutable pattern). Patterns in `let` must be irrefutable - they must +always match. + +Example: + let Some(x) = maybe_value; // Error: maybe_value could be None + +The pattern `Some(x)` is refutable because the value could be `None`.", + "\ +Эта ошибка возникает, когда в `let` используется паттерн, который может +не совпасть (опровержимый паттерн). Паттерны в `let` должны быть +неопровержимыми - всегда совпадать.", + "\ +이 오류는 `let` 바인딩에서 실패할 수 있는 패턴(반박 가능한 패턴)을 사용할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use if let for refutable patterns", + "Использовать if let для опровержимых паттернов", + "반박 가능한 패턴에 if let 사용" + ), + code: "if let Some(x) = maybe_value {\n // use x\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use match to handle all cases", + "Использовать match для всех случаев", + "모든 케이스를 처리하기 위해 match 사용" + ), + code: "match maybe_value {\n Some(x) => { /* use x */ },\n None => {},\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Refutable Patterns", + url: "https://doc.rust-lang.org/book/ch18-02-refutability.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0005.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0023.rs b/masterror-knowledge/src/errors/patterns/e0023.rs new file mode 100644 index 0000000..bd8d6b0 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0023.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0023: wrong number of fields in pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0023", + title: LocalizedText::new( + "Wrong number of fields in pattern", + "Неверное количество полей в паттерне", + "패턴에서 잘못된 필드 수" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when a pattern provides the wrong number of sub-patterns for +an enum variant's fields. + +Example: + enum Fruit { Apple(String, String) } + match fruit { + Fruit::Apple(a) => {}, // Error: Apple has 2 fields, not 1 + } + +Each enum variant has a specific number of fields, and your pattern must +provide exactly that many sub-patterns.", + "\ +Эта ошибка возникает, когда паттерн содержит неверное количество подпаттернов +для полей варианта enum.", + "\ +이 오류는 패턴이 열거형 변형의 필드에 대해 잘못된 수의 하위 패턴을 제공할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match the exact number of fields", + "Указать точное количество полей", + "정확한 필드 수와 일치" + ), + code: "match fruit {\n Fruit::Apple(a, b) => {},\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Patterns", + url: "https://doc.rust-lang.org/book/ch18-00-patterns.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0023.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0025.rs b/masterror-knowledge/src/errors/patterns/e0025.rs new file mode 100644 index 0000000..c066e20 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0025.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0025: field bound multiple times in pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0025", + title: LocalizedText::new( + "Field bound multiple times in pattern", + "Поле связано несколько раз в паттерне", + "패턴에서 필드가 여러 번 바인딩됨" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +Each field of a struct can only be bound once in a pattern. This error occurs +when you bind the same field multiple times. + +Example: + struct Foo { a: u8, b: u8 } + let Foo { a: x, a: y } = foo; // Error: field `a` bound twice", + "\ +Каждое поле структуры может быть связано только один раз в паттерне.", + "\ +구조체의 각 필드는 패턴에서 한 번만 바인딩할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Bind each field only once", + "Связать каждое поле только один раз", + "각 필드를 한 번만 바인딩" + ), + code: "let Foo { a: x, b: y } = foo;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0025.html" + }] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0026.rs b/masterror-knowledge/src/errors/patterns/e0026.rs new file mode 100644 index 0000000..644dcd8 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0026.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0026: nonexistent field in struct pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0026", + title: LocalizedText::new( + "Nonexistent field in struct pattern", + "Несуществующее поле в паттерне структуры", + "구조체 패턴에 존재하지 않는 필드" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when a struct pattern tries to extract a field that doesn't +exist in the struct definition. + +Example: + struct Thing { x: u32, y: u32 } + match thing { + Thing { x, z } => {} // Error: Thing has no field `z` + }", + "\ +Эта ошибка возникает, когда паттерн структуры пытается извлечь поле, +которого нет в определении структуры.", + "\ +이 오류는 구조체 패턴이 구조체 정의에 없는 필드를 추출하려고 할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use field renaming syntax if needed", + "Использовать переименование поля при необходимости", + "필요한 경우 필드 이름 변경 구문 사용" + ), + code: "match thing {\n Thing { x, y: z } => {} // renames y to z\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0026.html" + }] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0027.rs b/masterror-knowledge/src/errors/patterns/e0027.rs new file mode 100644 index 0000000..4de2045 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0027.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0027: pattern missing struct fields + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0027", + title: LocalizedText::new( + "Pattern missing struct fields", + "В паттерне отсутствуют поля структуры", + "패턴에서 구조체 필드 누락" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when a pattern for a struct fails to specify a sub-pattern +for every field of the struct. + +Example: + struct Dog { name: String, age: u32 } + match dog { + Dog { age: x } => {} // Error: missing field `name` + }", + "\ +Эта ошибка возникает, когда паттерн для структуры не указывает подпаттерн +для каждого поля структуры.", + "\ +이 오류는 구조체 패턴이 모든 필드에 대한 하위 패턴을 지정하지 않을 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Specify all fields", + "Указать все поля", + "모든 필드 지정" + ), + code: "match dog {\n Dog { name: ref n, age: x } => {}\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use .. to ignore remaining fields", + "Использовать .. для игнорирования остальных полей", + ".. 를 사용하여 나머지 필드 무시" + ), + code: "match dog {\n Dog { age: x, .. } => {}\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0027.html" + }] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0029.rs b/masterror-knowledge/src/errors/patterns/e0029.rs new file mode 100644 index 0000000..6f77d77 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0029.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0029: range pattern with non-numeric/char type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0029", + title: LocalizedText::new( + "Range pattern with non-numeric type", + "Диапазонный паттерн с нечисловым типом", + "숫자가 아닌 타입의 범위 패턴" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when you use a range pattern with types other than numbers +or characters. Range patterns only work with numeric types and `char`. + +Example: + match string { + \"hello\" ..= \"world\" => {} // Error: strings don't support ranges + }", + "\ +Эта ошибка возникает при использовании диапазонного паттерна с типами, +отличными от чисел или символов.", + "\ +이 오류는 숫자나 문자가 아닌 타입으로 범위 패턴을 사용할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a guard clause instead", + "Использовать условие вместо диапазона", + "대신 가드 절 사용" + ), + code: "match string {\n s if s >= \"hello\" && s <= \"world\" => {},\n _ => {},\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0029.html" + }] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0030.rs b/masterror-knowledge/src/errors/patterns/e0030.rs new file mode 100644 index 0000000..ca683a9 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0030.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0030: invalid range pattern (lower > upper) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0030", + title: LocalizedText::new( + "Invalid range pattern", + "Недопустимый диапазонный паттерн", + "잘못된 범위 패턴" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when a range pattern has a start value greater than the +end value, making the range empty. + +Example: + match 5u32 { + 1000 ..= 5 => {} // Error: 1000 > 5, empty range + }", + "\ +Эта ошибка возникает, когда начальное значение диапазона больше конечного, +что делает диапазон пустым.", + "\ +이 오류는 범위 패턴의 시작 값이 끝 값보다 클 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Swap the range bounds", + "Поменять границы диапазона местами", + "범위 경계 교환" + ), + code: "match 5u32 {\n 5 ..= 1000 => {}\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0030.html" + }] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0033.rs b/masterror-knowledge/src/errors/patterns/e0033.rs new file mode 100644 index 0000000..03456a7 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0033.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0033: trait type dereferenced in pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0033", + title: LocalizedText::new( + "Trait type dereferenced in pattern", + "Разыменование трейт-объекта в паттерне", + "패턴에서 트레이트 타입 역참조" + ), + category: Category::Patterns, + explanation: LocalizedText::new( + "\ +This error occurs when you try to dereference a trait object in a pattern. +Trait types don't have a known size at compile time, so they cannot be +dereferenced to create a local variable. + +Example: + let trait_obj: &dyn MyTrait = &value; + let &x = trait_obj; // Error: cannot dereference trait object", + "\ +Эта ошибка возникает при попытке разыменовать трейт-объект в паттерне. +Трейт-типы не имеют известного размера во время компиляции.", + "\ +이 오류는 패턴에서 트레이트 객체를 역참조하려고 할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Call methods directly on trait object", + "Вызывать методы напрямую на трейт-объекте", + "트레이트 객체에서 직접 메서드 호출" + ), + code: "trait_obj.method();" + }], + links: &[ + DocLink { + title: "Rust Book: Trait Objects", + url: "https://doc.rust-lang.org/book/ch17-02-trait-objects.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0033.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0158.rs b/masterror-knowledge/src/errors/patterns/e0158.rs new file mode 100644 index 0000000..77c629c --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0158.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0158: a generic parameter or static has been referenced in a pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0158", + title: LocalizedText::new( + "A generic parameter or static has been referenced in a pattern", + "Обобщённый параметр или статическая переменная использованы в паттерне", + "제네릭 매개변수 또는 static이 패턴에서 참조됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A generic parameter or static has been referenced in a pattern match. +The compiler rejects this because it cannot prove that pattern matching +is exhaustive when generic types are involved. + +Rust performs type checking on generic methods rather than on monomorphized +instances. Since a trait could have arbitrary implementations, the compiler +cannot guarantee that a pattern will always resolve to a known value.", + "\ +Обобщённый параметр или статическая переменная использованы в паттерне. +Компилятор отклоняет это, потому что не может доказать исчерпывающее +сопоставление паттернов при использовании обобщённых типов. + +Rust выполняет проверку типов для обобщённых методов, а не для +мономорфизированных экземпляров.", + "\ +제네릭 매개변수 또는 static이 패턴 매치에서 참조되었습니다. +컴파일러는 제네릭 타입이 관련된 경우 패턴 매칭이 완전하다는 것을 +증명할 수 없기 때문에 이를 거부합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use guard clauses instead of direct pattern matching", + "Использовать условия охраны вместо прямого сопоставления", + "직접 패턴 매칭 대신 가드 절 사용" + ), + code: "fn test(arg: char) {\n match arg {\n c if c == A::X => println!(\"A::X\"),\n c if c == Y => println!(\"Y\"),\n _ => ()\n }\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Match Expressions", + url: "https://doc.rust-lang.org/reference/expressions/match-expr.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0158.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0164.rs b/masterror-knowledge/src/errors/patterns/e0164.rs new file mode 100644 index 0000000..f6e31b8 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0164.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0164: expected tuple struct/variant, found method + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0164", + title: LocalizedText::new( + "Expected tuple struct/variant, found method", + "Ожидался кортежный struct/вариант, найден метод", + "튜플 구조체/변형이 예상되었으나 메서드가 발견됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +You attempted to match something that is neither a tuple struct nor a tuple +variant as a pattern in a match expression. Only tuple structs and tuple +variants are allowed as patterns. + +You can only use actual enum variants (unit variants, tuple variants, or +struct variants) as patterns in match expressions - not function calls or +methods, even if they return the same type.", + "\ +Вы попытались использовать в паттерне что-то, что не является ни кортежной +структурой, ни кортежным вариантом. Только кортежные структуры и варианты +можно использовать как паттерны. + +В паттернах match можно использовать только варианты перечислений, а не +вызовы функций или методов, даже если они возвращают тот же тип.", + "\ +매치 표현식에서 튜플 구조체나 튜플 변형이 아닌 것을 패턴으로 +매칭하려고 했습니다. 튜플 구조체와 튜플 변형만 패턴으로 허용됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use actual enum variants in patterns", + "Использовать настоящие варианты перечисления в паттернах", + "패턴에서 실제 열거형 변형 사용" + ), + code: "enum A {\n B,\n C,\n}\n\nfn bar(foo: A) {\n match foo {\n A::B => (), // ok! B is a unit variant\n A::C => (),\n }\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Patterns", + url: "https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0164.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/patterns/e0170.rs b/masterror-knowledge/src/errors/patterns/e0170.rs new file mode 100644 index 0000000..22f9928 --- /dev/null +++ b/masterror-knowledge/src/errors/patterns/e0170.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0170: pattern binding uses same name as one of the variants + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0170", + title: LocalizedText::new( + "Pattern binding uses same name as one of the variants", + "Привязка паттерна использует то же имя, что и вариант", + "패턴 바인딩이 변형 이름과 동일한 이름 사용" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A pattern binding is using the same name as one of the variants of a type. +Rust interprets unqualified variant names as new variable bindings rather +than references to the enum variants, which is likely not the intended behavior.", + "\ +Привязка паттерна использует то же имя, что и один из вариантов типа. +Rust интерпретирует неквалифицированные имена вариантов как новые +привязки переменных, а не как ссылки на варианты перечисления.", + "\ +패턴 바인딩이 타입의 변형 중 하나와 동일한 이름을 사용하고 있습니다. +Rust는 정규화되지 않은 변형 이름을 열거형 변형에 대한 참조가 아닌 +새 변수 바인딩으로 해석합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Qualify the variant names", + "Квалифицировать имена вариантов", + "변형 이름 정규화" + ), + code: "enum Method { GET, POST }\n\nmatch m {\n Method::GET => {}, // properly qualified\n Method::POST => {},\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Import variants into scope", + "Импортировать варианты в область видимости", + "스코프로 변형 가져오기" + ), + code: "use Method::*;\nenum Method { GET, POST }\n\nmatch m {\n GET => {}, // now unqualified names work\n POST => {},\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Enum Patterns", + url: "https://doc.rust-lang.org/book/ch06-02-match.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0170.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/raprogramm.rs b/masterror-knowledge/src/errors/raprogramm.rs new file mode 100644 index 0000000..b632c66 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm.rs @@ -0,0 +1,202 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Best practices from RAprogramm's RustManifest. +//! +//! These are not compiler errors but recommendations and patterns +//! from + +mod ra001; +mod ra002; +mod ra003; +mod ra004; +mod ra005; +mod ra006; +mod ra007; +mod ra008; +mod ra009; +mod ra010; +mod ra011; +mod ra012; +mod ra013; +mod ra014; +mod ra015; +mod ra016; +mod ra017; +mod ra018; +mod ra019; +mod ra020; +mod ra021; + +use std::{collections::HashMap, sync::LazyLock}; + +use arrayvec::ArrayString; + +pub use crate::errors::LocalizedText; + +/// Global practice registry singleton. +static PRACTICE_REGISTRY: LazyLock = LazyLock::new(PracticeRegistry::build); + +/// Best practice category. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum PracticeCategory { + ErrorHandling, + Performance, + Naming, + Documentation, + Design, + Testing, + Security, + Safety, + Memory, + Idiomatic +} + +impl PracticeCategory { + pub fn name(&self, lang: &str) -> &'static str { + match (self, lang) { + (Self::ErrorHandling, "ru") => "Обработка ошибок", + (Self::ErrorHandling, "ko") => "오류 처리", + (Self::ErrorHandling, _) => "Error Handling", + + (Self::Performance, "ru") => "Производительность", + (Self::Performance, "ko") => "성능", + (Self::Performance, _) => "Performance", + + (Self::Naming, "ru") => "Именование", + (Self::Naming, "ko") => "명명", + (Self::Naming, _) => "Naming", + + (Self::Documentation, "ru") => "Документация", + (Self::Documentation, "ko") => "문서화", + (Self::Documentation, _) => "Documentation", + + (Self::Design, "ru") => "Проектирование", + (Self::Design, "ko") => "설계", + (Self::Design, _) => "Design", + + (Self::Testing, "ru") => "Тестирование", + (Self::Testing, "ko") => "테스트", + (Self::Testing, _) => "Testing", + + (Self::Security, "ru") => "Безопасность", + (Self::Security, "ko") => "보안", + (Self::Security, _) => "Security", + + (Self::Safety, "ru") => "Безопасность памяти", + (Self::Safety, "ko") => "메모리 안전", + (Self::Safety, _) => "Memory Safety", + + (Self::Memory, "ru") => "Управление памятью", + (Self::Memory, "ko") => "메모리 관리", + (Self::Memory, _) => "Memory Management", + + (Self::Idiomatic, "ru") => "Идиоматичность", + (Self::Idiomatic, "ko") => "관용적 코드", + (Self::Idiomatic, _) => "Idiomatic Code" + } + } +} + +/// A best practice recommendation. +#[derive(Debug, Clone)] +pub struct BestPractice { + pub code: &'static str, + pub title: LocalizedText, + pub category: PracticeCategory, + pub explanation: LocalizedText, + pub good_example: &'static str, + pub bad_example: &'static str, + pub source: &'static str +} + +static ENTRIES: &[&BestPractice] = &[ + &ra001::ENTRY, + &ra002::ENTRY, + &ra003::ENTRY, + &ra004::ENTRY, + &ra005::ENTRY, + &ra006::ENTRY, + &ra007::ENTRY, + &ra008::ENTRY, + &ra009::ENTRY, + &ra010::ENTRY, + &ra011::ENTRY, + &ra012::ENTRY, + &ra013::ENTRY, + &ra014::ENTRY, + &ra015::ENTRY, + &ra016::ENTRY, + &ra017::ENTRY, + &ra018::ENTRY, + &ra019::ENTRY, + &ra020::ENTRY, + &ra021::ENTRY +]; + +pub fn entries() -> &'static [&'static BestPractice] { + ENTRIES +} + +/// Registry for best practices. +pub struct PracticeRegistry { + practices: HashMap<&'static str, &'static BestPractice> +} + +impl PracticeRegistry { + /// Get the global registry instance. + pub fn new() -> &'static Self { + &PRACTICE_REGISTRY + } + + /// Build registry from all practices. + fn build() -> Self { + let mut practices = HashMap::with_capacity(21); + for entry in entries() { + practices.insert(entry.code, *entry); + } + Self { + practices + } + } + + /// Find practice by code (RA001, etc.). + /// + /// Accepts formats: "RA001", "ra001". + /// Uses stack-allocated buffer to avoid heap allocation. + pub fn find(&self, code: &str) -> Option<&'static BestPractice> { + // Fast path: try exact match first + if let Some(entry) = self.practices.get(code) { + return Some(*entry); + } + + // Normalize to uppercase using stack buffer + let mut buf: ArrayString<8> = ArrayString::new(); + for c in code.chars().take(8) { + buf.push(c.to_ascii_uppercase()); + } + + self.practices.get(buf.as_str()).copied() + } + + /// Get all practices. + pub fn all(&self) -> impl Iterator + '_ { + self.practices.values().copied() + } + + /// Get practices by category. + pub fn by_category(&self, cat: PracticeCategory) -> Vec<&'static BestPractice> { + self.practices + .values() + .filter(|p| p.category == cat) + .copied() + .collect() + } +} + +impl Default for &'static PracticeRegistry { + fn default() -> Self { + PracticeRegistry::new() + } +} diff --git a/masterror-knowledge/src/errors/raprogramm/ra001.rs b/masterror-knowledge/src/errors/raprogramm/ra001.rs new file mode 100644 index 0000000..0d1e403 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra001.rs @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA001: Never use unwrap() in production code + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA001", + title: LocalizedText::new( + "Never use unwrap() in production code", + "Никогда не используйте unwrap() в продакшене", + "프로덕션 코드에서 unwrap() 사용 금지" + ), + category: PracticeCategory::ErrorHandling, + explanation: LocalizedText::new( + "\ +unwrap() calls panic!() if the value is None or Err. +In production this crashes the entire service. +Use ? operator to propagate errors or handle them explicitly with match/map_err.", + "\ +unwrap() вызывает panic!() если значение None или Err. +В продакшене это приводит к падению всего сервиса. +Используйте оператор ? для пробрасывания ошибок или обрабатывайте явно через match/map_err.", + "\ +unwrap()은 값이 None이거나 Err이면 panic!()을 호출합니다. +프로덕션에서는 전체 서비스가 중단됩니다. +? 연산자로 에러를 전파하거나 match/map_err로 명시적으로 처리하세요." + ), + good_example: r#"let config = Config::from_file("config.toml") + .map_err(|e| format!("Failed to load config: {}", e))?;"#, + bad_example: r#"let config = Config::from_file("config.toml").unwrap();"#, + source: "https://github.com/RAprogramm/RustManifest#6-panic-avoidance-in-production" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra002.rs b/masterror-knowledge/src/errors/raprogramm/ra002.rs new file mode 100644 index 0000000..52c5391 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra002.rs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA002: Use ? operator for error propagation + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA002", + title: LocalizedText::new( + "Use ? operator for error propagation", + "Используйте оператор ? для распространения ошибок", + "오류 전파에 ? 연산자 사용" + ), + category: PracticeCategory::ErrorHandling, + explanation: LocalizedText::new( + "\ +The ? operator is the idiomatic way to handle errors in Rust. +It automatically converts errors and propagates them up the call stack. + +Use ok_or() or ok_or_else() to convert Option to Result with meaningful messages.", + "\ +Оператор ? — идиоматический способ обработки ошибок в Rust. +Он автоматически конвертирует ошибки и распространяет их вверх по стеку вызовов.", + "\ +? 연산자는 Rust에서 오류를 처리하는 관용적인 방법입니다." + ), + good_example: r#"let value = some_option.ok_or("Expected a value")?; +let data = fetch_data().map_err(|e| AppError::Network(e))?;"#, + bad_example: r#"let value = some_option.unwrap(); +let data = fetch_data().expect("fetch failed");"#, + source: "https://github.com/RAprogramm/RustManifest#5-best-practices" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra003.rs b/masterror-knowledge/src/errors/raprogramm/ra003.rs new file mode 100644 index 0000000..14b249c --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra003.rs @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA003: Avoid unnecessary clone() calls + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA003", + title: LocalizedText::new( + "Avoid unnecessary clone() calls", + "Избегайте ненужных вызовов clone()", + "불필요한 clone() 호출 피하기" + ), + category: PracticeCategory::Performance, + explanation: LocalizedText::new( + "\ +Cloning allocates memory and copies data. Often you can use references instead. +Only clone when you actually need ownership of the data. + +Common anti-patterns: +- Cloning just to satisfy the borrow checker (restructure instead) +- Cloning in a loop (clone once before the loop) +- Cloning when a reference would work", + "\ +Клонирование выделяет память и копирует данные. Часто можно использовать ссылки. +Клонируйте только когда действительно нужно владение данными.", + "\ +클론은 메모리를 할당하고 데이터를 복사합니다. 종종 참조를 대신 사용할 수 있습니다." + ), + good_example: r#"fn process(data: &str) { /* use reference */ } +let owned = expensive_data.clone(); // clone once +for item in &items { process(item); }"#, + bad_example: r#"for item in items { + process(item.clone()); // clones every iteration! +}"#, + source: "https://github.com/RAprogramm/RustManifest#3-code-quality" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra004.rs b/masterror-knowledge/src/errors/raprogramm/ra004.rs new file mode 100644 index 0000000..ab1caae --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra004.rs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA004: Use descriptive, meaningful names + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA004", + title: LocalizedText::new( + "Use descriptive, meaningful names", + "Используйте описательные, значимые имена", + "설명적이고 의미 있는 이름 사용" + ), + category: PracticeCategory::Naming, + explanation: LocalizedText::new( + "\ +Names must reflect purpose. Avoid generic terms like 'create', 'handle', 'data'. +Descriptive names reduce ambiguity, facilitate easier onboarding, and improve +maintainability. + +Conventions: +- snake_case for variables and functions +- PascalCase for structs and enums +- SCREAMING_SNAKE_CASE for constants", + "\ +Имена должны отражать назначение. Избегайте общих терминов вроде 'create', 'handle', 'data'. +Описательные имена уменьшают неоднозначность и улучшают поддерживаемость.", + "\ +이름은 목적을 반영해야 합니다. 'create', 'handle', 'data' 같은 일반적인 용어를 피하세요." + ), + good_example: r#"fn create_user_handler(req: CreateUserRequest) -> Result +const MAX_RETRY_ATTEMPTS: u32 = 3; +struct UserAuthenticationService { ... }"#, + bad_example: r#"fn create(r: Request) -> Result +const MAX: u32 = 3; +struct Service { ... }"#, + source: "https://github.com/RAprogramm/RustManifest#2-naming-conventions" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra005.rs b/masterror-knowledge/src/errors/raprogramm/ra005.rs new file mode 100644 index 0000000..0087cc2 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra005.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA005: No inline comments - use docblocks only + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA005", + title: LocalizedText::new( + "No inline comments - use docblocks only", + "Никаких инлайн комментариев - только docblocks", + "인라인 주석 금지 - docblock만 사용" + ), + category: PracticeCategory::Documentation, + explanation: LocalizedText::new( + "\ +Avoid // and /* */ explanations in code. All documentation lives in docblocks: +/// for items, //! for modules. + +Standardized headings for IDE/LSP stability: +- # Overview - Short purpose statement +- # Examples - Minimal, compilable samples +- # Errors - Precise failure modes for Result types +- # Panics - Only if unavoidable +- # Safety - Required if unsafe code present", + "\ +Избегайте // и /* */ объяснений в коде. Вся документация живёт в docblocks: +/// для элементов, //! для модулей.", + "\ +코드에서 // 및 /* */ 설명을 피하세요. 모든 문서는 docblock에." + ), + good_example: r#"/// Fetches user data from the database. +/// +/// # Errors +/// Returns `DbError::NotFound` if user doesn't exist. +/// +/// # Examples +/// ``` +/// let user = fetch_user(42)?; +/// ``` +pub fn fetch_user(id: u64) -> Result"#, + bad_example: r#"// This function fetches user data from the database +// It returns an error if user is not found +pub fn fetch_user(id: u64) -> Result"#, + source: "https://github.com/RAprogramm/RustManifest#8-code-documentation" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra006.rs b/masterror-knowledge/src/errors/raprogramm/ra006.rs new file mode 100644 index 0000000..ae7a5e1 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra006.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA006: Entity naming - no -er suffixes + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA006", + title: LocalizedText::new( + "Entity naming: avoid -er, -or, -manager suffixes", + "Именование сущностей: избегайте суффиксов -er, -or, -manager", + "엔티티 명명: -er, -or, -manager 접미사 피하기" + ), + category: PracticeCategory::Naming, + explanation: LocalizedText::new( + "\ +Structures represent entities, not actions. The -er suffix encourages procedural +thinking that separates data from behavior, creating anemic domain models. +Entity naming naturally unifies data and operations. + +Transforms: +- ConfigLoader → Config +- MessageParser → Message +- RequestHandler → Request +- DataValidator → Data +- ConnectionManager → ConnectionPool + +Exceptions: Iterator, Builder, Visitor, Formatter (established patterns).", + "\ +Структуры представляют сущности, не действия. Суффикс -er поощряет процедурное +мышление, разделяющее данные и поведение. Именование сущностей объединяет их.", + "\ +구조체는 동작이 아닌 엔티티를 나타냅니다. -er 접미사는 절차적 사고를 장려합니다." + ), + good_example: r#"struct Config { ... } +struct Message { ... } +struct Request { ... } +struct ConnectionPool { ... }"#, + bad_example: r#"struct ConfigLoader { ... } +struct MessageParser { ... } +struct RequestHandler { ... } +struct ConnectionManager { ... }"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#1-entity-naming" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra007.rs b/masterror-knowledge/src/errors/raprogramm/ra007.rs new file mode 100644 index 0000000..b585557 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra007.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA007: Method naming - nouns for accessors, verbs for mutators + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA007", + title: LocalizedText::new( + "Method naming: nouns for accessors, verbs for mutators", + "Именование методов: существительные для accessors, глаголы для mutators", + "메서드 명명: accessor는 명사, mutator는 동사" + ), + category: PracticeCategory::Naming, + explanation: LocalizedText::new( + "\ +Method names reflect purpose through grammatical form: +- Accessors (nouns): name(), length(), value() — not get_name() +- Predicates (adjectives): empty(), valid(), published() — not is_empty() +- Mutators (verbs): save(), publish(), delete() + +The get_ prefix adds noise without information. Omitting verbs signals pure +accessors. Adjective predicates read more naturally than is_ constructions.", + "\ +Имена методов отражают назначение через грамматическую форму: +- Accessors: name(), length() — не get_name() +- Predicates: empty(), valid() — не is_empty() +- Mutators: save(), publish(), delete()", + "\ +메서드 이름은 문법적 형태로 목적을 반영합니다." + ), + good_example: r#"impl User { + fn name(&self) -> &str { &self.name } + fn empty(&self) -> bool { self.data.is_empty() } + fn save(&mut self) { ... } +}"#, + bad_example: r#"impl User { + fn get_name(&self) -> &str { &self.name } + fn is_empty(&self) -> bool { self.data.is_empty() } +}"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#2-method-naming" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra008.rs b/masterror-knowledge/src/errors/raprogramm/ra008.rs new file mode 100644 index 0000000..9439153 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra008.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA008: Structure size - maximum 4 fields + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA008", + title: LocalizedText::new( + "Structure size: maximum 4 fields", + "Размер структуры: максимум 4 поля", + "구조체 크기: 최대 4개 필드" + ), + category: PracticeCategory::Design, + explanation: LocalizedText::new( + "\ +A structure should have no more than 4 fields. More fields indicate multiple +responsibilities requiring composition. + +Problems with large structures: +- Complex testing with many combinations +- Changes ripple through unrelated code +- Purpose becomes unclear +- Parts cannot be reused independently + +Solution: Decompose into focused sub-structures.", + "\ +Структура должна иметь не более 4 полей. Больше полей указывает на +множественные ответственности, требующие композиции.", + "\ +구조체는 4개 이하의 필드를 가져야 합니다. 더 많은 필드는 분해가 필요함을 나타냅니다." + ), + good_example: r#"struct User { + identity: UserIdentity, + credentials: Credentials, + profile: UserProfile, + access: AccessControl, +}"#, + bad_example: r#"struct User { + id: u64, email: String, password_hash: String, + name: String, avatar: Option, bio: String, + created_at: DateTime, updated_at: DateTime, + role: Role, permissions: Vec, + last_login: Option, login_count: u32, + is_verified: bool, verification_token: Option, +}"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#3-structure-size" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra009.rs b/masterror-knowledge/src/errors/raprogramm/ra009.rs new file mode 100644 index 0000000..91573b8 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra009.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA009: Public API size - maximum 5 methods + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA009", + title: LocalizedText::new( + "Public API size: maximum 5 methods", + "Размер публичного API: максимум 5 методов", + "공개 API 크기: 최대 5개 메서드" + ), + category: PracticeCategory::Design, + explanation: LocalizedText::new( + "\ +A structure's public interface should have no more than 5 methods. +More methods signal the structure does too much. + +Large APIs indicate mixed responsibilities, forcing users to understand more, +expanding documentation and testing complexity. + +Solution: Extract secondary concerns into separate types. +Excludes: trait implementations (Display, Debug, From) and generic new().", + "\ +Публичный интерфейс структуры должен иметь не более 5 методов. +Больше методов означает, что структура делает слишком много.", + "\ +구조체의 공개 인터페이스는 5개 이하의 메서드를 가져야 합니다." + ), + good_example: r#"impl Document { + pub fn new() -> Self { ... } + pub fn load(path: &Path) -> Result { ... } + pub fn save(&self) -> Result<()> { ... } + pub fn content(&self) -> &str { ... } + pub fn metadata(&self) -> &Metadata { ... } +} + +// Rendering is separate +impl Renderer { ... } +// Export is separate +impl Exporter { ... }"#, + bad_example: r#"impl Document { + pub fn new() -> Self { ... } + pub fn load() -> Result { ... } + pub fn save() -> Result<()> { ... } + pub fn content(&self) -> &str { ... } + pub fn metadata(&self) -> &Metadata { ... } + pub fn render_html(&self) -> String { ... } + pub fn render_pdf(&self) -> Vec { ... } + pub fn export_json(&self) -> String { ... } + pub fn validate(&self) -> Result<()> { ... } + // ... 10+ more methods +}"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#4-public-api-size" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra010.rs b/masterror-knowledge/src/errors/raprogramm/ra010.rs new file mode 100644 index 0000000..16397f6 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra010.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA010: Constructors should only assign fields + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA010", + title: LocalizedText::new( + "Constructors: assignment only, no logic", + "Конструкторы: только присваивание, никакой логики", + "생성자: 할당만, 로직 없음" + ), + category: PracticeCategory::Design, + explanation: LocalizedText::new( + "\ +Constructors should only assign fields. All processing, validation, and I/O +belong in methods. + +Problems with logic in constructors: +- Constructors can fail, complicating object creation +- Work happens eagerly even if unused +- Inflexible creation paths +- Hard to test without real resources + +Benefits of assignment-only constructors: +- Infallible object creation +- Lazy evaluation of expensive work +- Multiple creation paths (from_data() for tests)", + "\ +Конструкторы должны только присваивать поля. Вся обработка, валидация и I/O +принадлежат методам.", + "\ +생성자는 필드만 할당해야 합니다. 모든 처리, 검증, I/O는 메서드에." + ), + good_example: r#"impl Server { + pub fn new(config: Config) -> Self { + Self { config, connection: None } + } + + pub fn connect(&mut self) -> Result<()> { + self.connection = Some(Connection::establish(&self.config)?); + Ok(()) + } +}"#, + bad_example: r#"impl Server { + pub fn new(config: Config) -> Result { + let connection = Connection::establish(&config)?; // I/O in constructor! + validate_config(&config)?; // Logic in constructor! + Ok(Self { config, connection }) + } +}"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#5-constructor-design" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra011.rs b/masterror-knowledge/src/errors/raprogramm/ra011.rs new file mode 100644 index 0000000..a837c1b --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra011.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA011: Immutability first - prefer self over &mut self + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA011", + title: LocalizedText::new( + "Immutability first: prefer self over &mut self", + "Сначала неизменяемость: предпочитайте self вместо &mut self", + "불변성 우선: &mut self보다 self 선호" + ), + category: PracticeCategory::Design, + explanation: LocalizedText::new( + "\ +Prefer returning new objects over mutating existing ones. Use `self` instead +of `&mut self` where practical. + +Problems with mutable objects: +- Shared state bugs from unexpected modifications +- Thread safety requires synchronization +- Temporal coupling makes operation order matter +- Incomplete state during configuration + +Exceptions: Large data structures, I/O, performance-critical loops, Iterator::next", + "\ +Предпочитайте возврат новых объектов вместо изменения существующих. +Используйте `self` вместо `&mut self` где возможно.", + "\ +기존 객체를 변경하는 것보다 새 객체를 반환하는 것을 선호하세요." + ), + good_example: r#"Request::new(url) + .header("Content-Type", "application/json") + .body(payload) + .send()"#, + bad_example: r#"let mut req = Request::new(url); +req.set_header("Content-Type", "application/json"); +req.set_body(payload); +req.send()"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#7-immutability-first" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra012.rs b/masterror-knowledge/src/errors/raprogramm/ra012.rs new file mode 100644 index 0000000..8274d8c --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra012.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA012: Constant encapsulation - associate with types + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA012", + title: LocalizedText::new( + "Encapsulate constants in their types", + "Инкапсулируйте константы в их типы", + "상수를 타입에 캡슐화" + ), + category: PracticeCategory::Design, + explanation: LocalizedText::new( + "\ +Constants belong to structures using them, not global scope. This improves +discoverability and prevents namespace pollution. + +Benefits: +- Clear discovery location +- Built-in documentation +- Automatic namespacing +- Encapsulation +- Easy refactoring", + "\ +Константы принадлежат структурам, которые их используют, а не глобальной области. +Это улучшает обнаруживаемость и предотвращает загрязнение пространства имён.", + "\ +상수는 전역 범위가 아닌 사용하는 구조체에 속합니다." + ), + good_example: r#"impl ConnectionPool { + pub const MAX_SIZE: usize = 100; +} + +impl Client { + pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); +} + +// Usage: ConnectionPool::MAX_SIZE"#, + bad_example: r#"const MAX_POOL_SIZE: usize = 100; +const DEFAULT_CLIENT_TIMEOUT: Duration = Duration::from_secs(30); +const MAX_RETRIES: u32 = 3; +const DEFAULT_PORT: u16 = 8080; +// ... scattered constants"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#8-constant-encapsulation" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra013.rs b/masterror-knowledge/src/errors/raprogramm/ra013.rs new file mode 100644 index 0000000..306b810 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra013.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA013: Testing with fakes over mocks + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA013", + title: LocalizedText::new( + "Use fakes over mocks for testing", + "Используйте fakes вместо mocks для тестирования", + "테스트에 mock보다 fake 사용" + ), + category: PracticeCategory::Testing, + explanation: LocalizedText::new( + "\ +Use simple fake implementations instead of mock libraries. Fakes provide real +behavior; mocks verify call sequences. + +| Aspect | Mocks | Fakes | +|--------|-------|-------| +| Coupling | High | Low | +| Maintenance | Breaks on refactoring | Survives changes | +| Behavior | Simulates | Provides real | +| Debugging | Cryptic | Standard | + +Mock appropriateness: Verifying external system interactions, ensuring methods +are NOT called, testing strict interaction ordering.", + "\ +Используйте простые fake-реализации вместо mock-библиотек. Fakes обеспечивают +реальное поведение; mocks проверяют последовательности вызовов.", + "\ +mock 라이브러리 대신 간단한 fake 구현을 사용하세요." + ), + good_example: r#"struct FakeDatabase { + users: HashMap, +} + +impl FakeDatabase { + fn new() -> Self { Self { users: HashMap::new() } } + fn insert(&mut self, user: User) { self.users.insert(user.id, user); } +} + +impl Database for FakeDatabase { + fn find_user(&self, id: u64) -> Option<&User> { + self.users.get(&id) + } +}"#, + bad_example: r#"#[test] +fn test_user_service() { + let mut mock = MockDatabase::new(); + mock.expect_find_user() + .with(eq(42)) + .times(1) + .returning(|_| Some(User::default())); + // Breaks when implementation changes +}"#, + source: "https://github.com/RAprogramm/RustManifest/blob/main/STRUCTURE.md#9-testing-with-fakes" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra014.rs b/masterror-knowledge/src/errors/raprogramm/ra014.rs new file mode 100644 index 0000000..4301b08 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra014.rs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA014: Pre-allocate with Vec::with_capacity + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA014", + title: LocalizedText::new( + "Pre-allocate with Vec::with_capacity", + "Предвыделяйте память с Vec::with_capacity", + "Vec::with_capacity로 사전 할당" + ), + category: PracticeCategory::Performance, + explanation: LocalizedText::new( + "\ +When you know the approximate size of a Vec, pre-allocate to avoid reallocations. +Each reallocation copies all existing elements to new memory. + +This is especially important in hot paths and loops.", + "\ +Когда знаете примерный размер Vec, предвыделяйте чтобы избежать реаллокаций. +Каждая реаллокация копирует все элементы в новую память.", + "\ +Vec의 대략적인 크기를 알 때, 재할당을 피하기 위해 사전 할당하세요." + ), + good_example: r#"let mut results = Vec::with_capacity(items.len()); +for item in items { + results.push(process(item)); +}"#, + bad_example: r#"let mut results = Vec::new(); // starts with 0 capacity +for item in items { + results.push(process(item)); // reallocates multiple times! +}"#, + source: "https://github.com/RAprogramm/RustManifest#9-code-review-methodology" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra015.rs b/masterror-knowledge/src/errors/raprogramm/ra015.rs new file mode 100644 index 0000000..0bfd79c --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra015.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA015: Avoid O(n²) algorithms + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA015", + title: LocalizedText::new( + "Avoid O(n²) algorithms", + "Избегайте алгоритмов O(n²)", + "O(n²) 알고리즘 피하기" + ), + category: PracticeCategory::Performance, + explanation: LocalizedText::new( + "\ +Nested loops over the same data often indicate O(n²) complexity. +Use HashSet/HashMap for lookups, or sort + binary search. + +What looks fine with 100 items becomes unusable with 10,000.", + "\ +Вложенные циклы по одним данным часто указывают на O(n²) сложность. +Используйте HashSet/HashMap для поиска или сортировку + бинарный поиск.", + "\ +같은 데이터에 대한 중첩 루프는 종종 O(n²) 복잡도를 나타냅니다." + ), + good_example: r#"let seen: HashSet<_> = items.iter().collect(); +for item in other_items { + if seen.contains(&item) { // O(1) lookup + // ... + } +}"#, + bad_example: r#"for item in other_items { + for existing in &items { // O(n) for each = O(n²) total + if item == existing { + // ... + } + } +}"#, + source: "https://github.com/RAprogramm/RustManifest#9-code-review-methodology" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra016.rs b/masterror-knowledge/src/errors/raprogramm/ra016.rs new file mode 100644 index 0000000..820c405 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra016.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA016: Minimize unsafe blocks + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA016", + title: LocalizedText::new( + "Minimize unsafe blocks", + "Минимизируйте unsafe блоки", + "unsafe 블록 최소화" + ), + category: PracticeCategory::Safety, + explanation: LocalizedText::new( + "\ +Unsafe code bypasses Rust's safety guarantees. Every unsafe block is a potential +source of undefined behavior, memory corruption, or security vulnerabilities. + +Isolate unsafe code in small, well-documented functions with safe wrappers. +Prove invariants with comments and tests. Consider using safe abstractions +from crates like `zerocopy`, `bytemuck`, or standard library equivalents.", + "\ +Unsafe код обходит гарантии безопасности Rust. Каждый unsafe блок — +потенциальный источник неопределённого поведения, повреждения памяти +или уязвимостей безопасности. + +Изолируйте unsafe код в небольших, хорошо документированных функциях +с безопасными обёртками. Докажите инварианты комментариями и тестами.", + "\ +unsafe 코드는 Rust의 안전 보장을 우회합니다. 모든 unsafe 블록은 +정의되지 않은 동작, 메모리 손상 또는 보안 취약점의 잠재적 원인입니다." + ), + good_example: r#"/// SAFETY: `ptr` must be valid and properly aligned. +/// The caller ensures the pointer comes from a valid allocation. +unsafe fn read_value(ptr: *const u32) -> u32 { + *ptr +} + +// Safe wrapper +pub fn get_value(slice: &[u32], index: usize) -> Option { + slice.get(index).copied() +}"#, + bad_example: r#"fn process(data: &[u8]) { + unsafe { + // 100 lines of unsafe code with no invariant documentation + let ptr = data.as_ptr(); + // ... + } +}"#, + source: "https://github.com/RAprogramm/RustManifest#memory-safety" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra017.rs b/masterror-knowledge/src/errors/raprogramm/ra017.rs new file mode 100644 index 0000000..348d8b8 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra017.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA017: No TODO without issue reference + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA017", + title: LocalizedText::new( + "No TODO without issue reference", + "TODO только со ссылкой на issue", + "이슈 참조 없는 TODO 금지" + ), + category: PracticeCategory::Documentation, + explanation: LocalizedText::new( + "\ +TODO comments without issue references become forgotten technical debt. +They accumulate over time and lose context about why they were added. + +Every TODO should reference a tracked issue (GitHub, Jira, etc.) so it can be +prioritized, assigned, and eventually resolved. Use `todo!()` macro only +in development, never in production code.", + "\ +TODO комментарии без ссылок на issue становятся забытым техническим долгом. +Они накапливаются со временем и теряют контекст о причине добавления. + +Каждый TODO должен ссылаться на отслеживаемую задачу (GitHub, Jira и т.д.). +Используйте макрос `todo!()` только в разработке, никогда в продакшене.", + "\ +이슈 참조가 없는 TODO 주석은 잊혀진 기술 부채가 됩니다. +시간이 지남에 따라 축적되고 추가된 이유에 대한 컨텍스트를 잃습니다." + ), + good_example: r#"// TODO(#123): Add retry logic for network failures +// FIXME(PROJ-456): Handle edge case when buffer is empty +fn process() { + // Implementation +}"#, + bad_example: r#"fn process() { + todo!("implement later"); + // TODO: fix this somehow + // FIXME: doesn't work +}"#, + source: "https://github.com/RAprogramm/RustManifest#documentation" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra018.rs b/masterror-knowledge/src/errors/raprogramm/ra018.rs new file mode 100644 index 0000000..bb47a43 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra018.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA018: Avoid mutable statics + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA018", + title: LocalizedText::new( + "Avoid mutable statics", + "Избегайте изменяемых static переменных", + "변경 가능한 static 변수 피하기" + ), + category: PracticeCategory::Safety, + explanation: LocalizedText::new( + "\ +Mutable statics (`static mut`) are inherently unsafe and a common source of +data races in concurrent code. Any access requires an unsafe block. + +Use thread-safe alternatives: +- `std::sync::OnceLock` for lazy initialization +- `std::sync::Mutex` or `RwLock` for mutable shared state +- `std::sync::atomic` types for simple counters/flags +- `thread_local!` for thread-local storage", + "\ +Изменяемые static (`static mut`) по своей природе небезопасны и являются +частым источником гонок данных в многопоточном коде. + +Используйте потокобезопасные альтернативы: +- `std::sync::OnceLock` для ленивой инициализации +- `std::sync::Mutex` или `RwLock` для изменяемого общего состояния +- `std::sync::atomic` типы для простых счётчиков/флагов", + "\ +변경 가능한 static(`static mut`)은 본질적으로 안전하지 않으며 +동시성 코드에서 데이터 경쟁의 일반적인 원인입니다." + ), + good_example: r#"use std::sync::OnceLock; + +static CONFIG: OnceLock = OnceLock::new(); + +fn get_config() -> &'static Config { + CONFIG.get_or_init(|| Config::load()) +}"#, + bad_example: r#"static mut COUNTER: u32 = 0; + +fn increment() { + unsafe { + COUNTER += 1; // Data race! + } +}"#, + source: "https://github.com/RAprogramm/RustManifest#memory-safety" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra019.rs b/masterror-knowledge/src/errors/raprogramm/ra019.rs new file mode 100644 index 0000000..f683549 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra019.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA019: Avoid transmute + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA019", + title: LocalizedText::new( + "Avoid std::mem::transmute", + "Избегайте std::mem::transmute", + "std::mem::transmute 피하기" + ), + category: PracticeCategory::Safety, + explanation: LocalizedText::new( + "\ +`transmute` reinterprets bits of one type as another without any checks. +It can easily cause undefined behavior if types have different layouts, +alignment requirements, or validity invariants. + +Prefer safe alternatives: +- `as` casts for numeric conversions +- `From`/`Into` traits for type conversions +- `bytemuck` crate for safe transmutes between Pod types +- `zerocopy` crate for zero-copy parsing", + "\ +`transmute` переинтерпретирует биты одного типа как другой без проверок. +Это легко может вызвать неопределённое поведение, если типы имеют разные +layouts, требования выравнивания или инварианты валидности. + +Используйте безопасные альтернативы: +- `as` для числовых преобразований +- `From`/`Into` трейты для преобразования типов +- `bytemuck` крейт для безопасных transmute между Pod типами", + "\ +`transmute`는 검사 없이 한 타입의 비트를 다른 타입으로 재해석합니다. +타입이 다른 레이아웃, 정렬 요구 사항 또는 유효성 불변성을 가지면 +정의되지 않은 동작을 쉽게 유발할 수 있습니다." + ), + good_example: r#"// Safe numeric conversion +let x: u32 = 42; +let y: i32 = x as i32; + +// Safe bytes conversion with bytemuck +use bytemuck::{Pod, Zeroable}; + +#[derive(Copy, Clone, Pod, Zeroable)] +#[repr(C)] +struct Pixel { r: u8, g: u8, b: u8, a: u8 } + +let bytes: [u8; 4] = [255, 0, 0, 255]; +let pixel: Pixel = bytemuck::cast(bytes);"#, + bad_example: r#"let x: u32 = 42; +let y: f32 = unsafe { std::mem::transmute(x) }; + +// Even worse - different sizes! +let s: &str = "hello"; +let n: usize = unsafe { std::mem::transmute(s) }; // UB!"#, + source: "https://github.com/RAprogramm/RustManifest#memory-safety" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra020.rs b/masterror-knowledge/src/errors/raprogramm/ra020.rs new file mode 100644 index 0000000..8d6f053 --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra020.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA020: Flatten nested control flow + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA020", + title: LocalizedText::new( + "Flatten nested control flow", + "Уменьшайте вложенность управляющих структур", + "중첩된 제어 흐름 평탄화" + ), + category: PracticeCategory::Idiomatic, + explanation: LocalizedText::new( + "\ +Deep nesting (>3-4 levels) makes code hard to read and reason about. +Each level of indentation adds cognitive load. + +Techniques to flatten: +- Early returns with guard clauses +- Extract nested logic into separate functions +- Use `match` with pattern guards instead of nested if/else +- Use `?` operator for error propagation +- Use iterator combinators instead of nested loops", + "\ +Глубокая вложенность (>3-4 уровней) делает код трудным для чтения. +Каждый уровень отступа добавляет когнитивную нагрузку. + +Техники для уменьшения вложенности: +- Ранний возврат с guard clauses +- Выделение вложенной логики в отдельные функции +- Использование `match` с pattern guards вместо вложенных if/else +- Оператор `?` для propagation ошибок", + "\ +깊은 중첩(3-4 레벨 이상)은 코드를 읽고 이해하기 어렵게 만듭니다. +각 들여쓰기 수준은 인지 부하를 추가합니다." + ), + good_example: r#"fn process(data: Option) -> Result { + let data = data.ok_or(Error::NoData)?; + + if !data.is_valid() { + return Err(Error::Invalid); + } + + let result = transform(data)?; + Ok(result) +}"#, + bad_example: r#"fn process(data: Option) -> Result { + if let Some(data) = data { + if data.is_valid() { + if let Ok(intermediate) = step1(data) { + if let Ok(result) = step2(intermediate) { + return Ok(result); + } + } + } + } + Err(Error::Failed) +}"#, + source: "https://github.com/RAprogramm/RustManifest#code-structure" +}; diff --git a/masterror-knowledge/src/errors/raprogramm/ra021.rs b/masterror-knowledge/src/errors/raprogramm/ra021.rs new file mode 100644 index 0000000..a89dd4f --- /dev/null +++ b/masterror-knowledge/src/errors/raprogramm/ra021.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RA021: Use String::with_capacity in loops + +use crate::errors::raprogramm::{BestPractice, LocalizedText, PracticeCategory}; + +pub static ENTRY: BestPractice = BestPractice { + code: "RA021", + title: LocalizedText::new( + "Use String::with_capacity in loops", + "Используйте String::with_capacity в циклах", + "루프에서 String::with_capacity 사용" + ), + category: PracticeCategory::Performance, + explanation: LocalizedText::new( + "\ +Building strings in loops with `push_str` or `+` causes repeated reallocations. +Each reallocation copies all existing data to a new buffer. + +Pre-allocate with `String::with_capacity` when the final size is known or +can be estimated. For complex cases, consider using `std::fmt::Write` trait +or collecting into a `Vec<&str>` and joining at the end.", + "\ +Построение строк в циклах через `push_str` или `+` вызывает повторные +реаллокации. Каждая реаллокация копирует все данные в новый буфер. + +Используйте `String::with_capacity` когда финальный размер известен или +может быть оценён. Для сложных случаев используйте `std::fmt::Write` +или собирайте в `Vec<&str>` и объединяйте в конце.", + "\ +`push_str` 또는 `+`로 루프에서 문자열을 구축하면 반복적인 +재할당이 발생합니다. 각 재할당은 모든 기존 데이터를 새 버퍼로 복사합니다." + ), + good_example: r#"fn build_csv(rows: &[Row]) -> String { + // Estimate: ~50 chars per row + let mut result = String::with_capacity(rows.len() * 50); + + for row in rows { + result.push_str(&row.to_csv_line()); + result.push('\n'); + } + result +} + +// Alternative: collect and join +let lines: Vec<_> = rows.iter().map(|r| r.to_csv_line()).collect(); +let result = lines.join("\n");"#, + bad_example: r#"fn build_csv(rows: &[Row]) -> String { + let mut result = String::new(); + + for row in rows { + result = result + &row.to_csv_line() + "\n"; // Reallocates every iteration! + } + result +}"#, + source: "https://github.com/RAprogramm/RustManifest#performance" +}; diff --git a/masterror-knowledge/src/errors/resolution.rs b/masterror-knowledge/src/errors/resolution.rs new file mode 100644 index 0000000..48a5662 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution.rs @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Name resolution errors. + +mod e0251; +mod e0252; +mod e0253; +mod e0254; +mod e0255; +mod e0256; +mod e0259; +mod e0260; +mod e0411; +mod e0412; +mod e0422; +mod e0423; +mod e0424; +mod e0425; +mod e0426; +mod e0428; +mod e0429; +mod e0430; +mod e0431; +mod e0432; +mod e0433; +mod e0434; +mod e0435; +mod e0436; +mod e0530; +mod e0531; +mod e0532; +mod e0533; +mod e0577; +mod e0583; +mod e0601; +mod e0602; +mod e0603; +mod e0615; +mod e0616; +mod e0624; +mod e0659; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0251::ENTRY, + &e0252::ENTRY, + &e0253::ENTRY, + &e0254::ENTRY, + &e0255::ENTRY, + &e0256::ENTRY, + &e0259::ENTRY, + &e0260::ENTRY, + &e0411::ENTRY, + &e0412::ENTRY, + &e0422::ENTRY, + &e0423::ENTRY, + &e0424::ENTRY, + &e0425::ENTRY, + &e0426::ENTRY, + &e0428::ENTRY, + &e0429::ENTRY, + &e0430::ENTRY, + &e0431::ENTRY, + &e0432::ENTRY, + &e0433::ENTRY, + &e0434::ENTRY, + &e0435::ENTRY, + &e0436::ENTRY, + &e0530::ENTRY, + &e0531::ENTRY, + &e0532::ENTRY, + &e0533::ENTRY, + &e0577::ENTRY, + &e0583::ENTRY, + &e0601::ENTRY, + &e0602::ENTRY, + &e0603::ENTRY, + &e0615::ENTRY, + &e0616::ENTRY, + &e0624::ENTRY, + &e0659::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/resolution/e0251.rs b/masterror-knowledge/src/errors/resolution/e0251.rs new file mode 100644 index 0000000..47daa0d --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0251.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0251: duplicate item import + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0251", + title: LocalizedText::new( + "Duplicate item name in imports", + "Дублирующееся имя элемента при импорте", + "임포트에서 중복된 항목 이름" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +Two items with the same name are imported into scope without rebinding +one of them under a new local name. + +Note: This error code is no longer emitted by the compiler. + +The error prevented name conflicts by requiring explicit disambiguation +when the same name was imported from multiple sources.", + "\ +Два элемента с одинаковым именем импортируются в область видимости +без переименования одного из них. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +같은 이름의 두 항목이 리바인딩 없이 스코프로 임포트되었습니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use 'as' keyword to rebind one of the imports", + "Используйте 'as' для переименования одного из импортов", + "'as' 키워드로 임포트 중 하나를 리바인딩" + ), + code: "use foo::baz;\nuse bar::baz as bar_baz;" + }], + links: &[ + DocLink { + title: "Rust Book: Bringing Paths into Scope", + url: "https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0251.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0252.rs b/masterror-knowledge/src/errors/resolution/e0252.rs new file mode 100644 index 0000000..f1c6e98 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0252.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0252: two items with same name cannot be imported + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0252", + title: LocalizedText::new( + "Two items with same name cannot be imported without rebinding", + "Два элемента с одинаковым именем не могут быть импортированы без переименования", + "같은 이름의 두 항목은 리바인딩 없이 임포트할 수 없음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +Two items of the same name cannot be imported without rebinding one +of the items under a new local name. + +This error occurs when you attempt to import two items with identical +names from different modules into the same scope without using aliases +to disambiguate them.", + "\ +Два элемента с одинаковым именем не могут быть импортированы без +переименования одного из них. + +Эта ошибка возникает при попытке импортировать два элемента с идентичными +именами из разных модулей в одну область видимости.", + "\ +같은 이름의 두 항목은 리바인딩 없이 임포트할 수 없습니다. +별칭을 사용하여 구분해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use aliases with 'as' keyword", + "Используйте псевдонимы с ключевым словом 'as'", + "'as' 키워드로 별칭 사용" + ), + code: "use foo::baz as foo_baz;\nuse bar::baz;" + }, + FixSuggestion { + description: LocalizedText::new( + "Reference with parent module path", + "Обращайтесь через путь родительского модуля", + "부모 모듈 경로로 참조" + ), + code: "use bar::baz;\n\nfn main() {\n let x = foo::baz; // full path\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Renaming with 'as'", + url: "https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#providing-new-names-with-the-as-keyword" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0252.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0253.rs b/masterror-knowledge/src/errors/resolution/e0253.rs new file mode 100644 index 0000000..9d198f3 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0253.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0253: attempt to import unimportable type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0253", + title: LocalizedText::new( + "Attempt to import an unimportable type", + "Попытка импортировать неимпортируемый тип", + "임포트할 수 없는 타입을 임포트하려는 시도" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An attempt was made to import a type that belongs to a trait directly. +You cannot directly import associated types from a trait. + +Associated types belong to their trait and should be accessed through +the trait itself or through concrete implementations of the trait, +rather than through direct import. + +Note: This error code is no longer emitted by the compiler.", + "\ +Была попытка напрямую импортировать тип, принадлежащий трейту. +Нельзя напрямую импортировать ассоциированные типы из трейта. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +트레이트에 속한 타입을 직접 임포트하려고 했습니다. +연관 타입은 직접 임포트할 수 없습니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Access associated type through the trait", + "Обращайтесь к ассоциированному типу через трейт", + "트레이트를 통해 연관 타입에 접근" + ), + code: "use foo::MyTrait;\n\nfn example() -> T::SomeType { todo!() }" + }], + links: &[ + DocLink { + title: "Rust Book: Associated Types", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0253.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0254.rs b/masterror-knowledge/src/errors/resolution/e0254.rs new file mode 100644 index 0000000..0395d6b --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0254.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0254: duplicate import with extern crate + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0254", + title: LocalizedText::new( + "Import conflicts with extern crate name", + "Импорт конфликтует с именем внешнего крейта", + "임포트가 extern crate 이름과 충돌" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An attempt was made to import an item with a name that conflicts with +an already-imported extern crate. + +When you import an extern crate, its name is bound in the current module's +namespace. Attempting to import another item with the same name creates +a naming conflict.", + "\ +Была попытка импортировать элемент с именем, которое конфликтует +с уже импортированным внешним крейтом. + +Когда вы импортируете внешний крейт, его имя связывается в пространстве +имён текущего модуля.", + "\ +이미 임포트된 extern crate와 충돌하는 이름의 항목을 임포트하려고 했습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Rename the extern crate with 'as'", + "Переименуйте внешний крейт с помощью 'as'", + "'as'로 extern crate 이름 변경" + ), + code: "extern crate core as libcore;\n\nmod foo {\n pub trait core {}\n}\n\nuse foo::core;" + }], + links: &[ + DocLink { + title: "Rust Reference: Extern Crates", + url: "https://doc.rust-lang.org/reference/items/extern-crates.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0254.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0255.rs b/masterror-knowledge/src/errors/resolution/e0255.rs new file mode 100644 index 0000000..5765fe9 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0255.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0255: duplicate name import + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0255", + title: LocalizedText::new( + "Import name conflicts with existing item", + "Имя импорта конфликтует с существующим элементом", + "임포트 이름이 기존 항목과 충돌" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +You can't import a value whose name is the same as another value +already defined in the module. + +This error occurs when you try to import an item using `use` that has +the same name as another item already in scope in your module.", + "\ +Нельзя импортировать значение, имя которого совпадает с именем другого +значения, уже определённого в модуле. + +Эта ошибка возникает при попытке импортировать элемент с тем же именем, +что и элемент, уже находящийся в области видимости.", + "\ +모듈에 이미 정의된 항목과 같은 이름의 값을 임포트할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use alias with 'as' keyword", + "Используйте псевдоним с ключевым словом 'as'", + "'as' 키워드로 별칭 사용" + ), + code: "use bar::foo as bar_foo;\n\nfn foo() {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use fully qualified path", + "Используйте полный путь", + "완전 정규화 경로 사용" + ), + code: "fn foo() {}\n\nfn main() {\n bar::foo(); // access via module path\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Renaming with 'as'", + url: "https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#providing-new-names-with-the-as-keyword" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0255.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0256.rs b/masterror-knowledge/src/errors/resolution/e0256.rs new file mode 100644 index 0000000..810fa83 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0256.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0256: import conflicts with type or module + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0256", + title: LocalizedText::new( + "Import conflicts with existing type or module", + "Импорт конфликтует с существующим типом или модулем", + "임포트가 기존 타입 또는 모듈과 충돌" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An attempt was made to import a type or module using `use` where the +imported name conflicts with an existing type or submodule already +defined in the same module. + +Note: This error code is no longer emitted by the compiler.", + "\ +Была попытка импортировать тип или модуль, где импортируемое имя +конфликтует с существующим типом или подмодулем. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +임포트 이름이 같은 모듈에 이미 정의된 타입이나 서브모듈과 충돌합니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use alias with 'as' keyword", + "Используйте псевдоним с ключевым словом 'as'", + "'as' 키워드로 별칭 사용" + ), + code: "use foo::Bar as FooBar;\n\ntype Bar = u32;" + }], + links: &[ + DocLink { + title: "Rust Book: Use Keyword", + url: "https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0256.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0259.rs b/masterror-knowledge/src/errors/resolution/e0259.rs new file mode 100644 index 0000000..a652c1a --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0259.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0259: duplicate external crate name + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0259", + title: LocalizedText::new( + "Duplicate external crate name", + "Дублирующееся имя внешнего крейта", + "중복된 외부 크레이트 이름" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +The name chosen for an external crate conflicts with another external +crate that has been imported into the current module. + +You cannot import two external crates using the same name in the +same scope. One of them must be renamed using the `as` keyword.", + "\ +Выбранное имя для внешнего крейта конфликтует с другим внешним крейтом, +который уже импортирован в текущий модуль. + +Нельзя импортировать два внешних крейта с одинаковым именем в одну +область видимости.", + "\ +외부 크레이트에 선택한 이름이 현재 모듈에 이미 임포트된 다른 외부 크레이트와 충돌합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Choose different name with 'as' keyword", + "Выберите другое имя с помощью ключевого слова 'as'", + "'as' 키워드로 다른 이름 선택" + ), + code: "extern crate core;\nextern crate std as other_name;" + }], + links: &[ + DocLink { + title: "Rust Reference: Extern Crates", + url: "https://doc.rust-lang.org/reference/items/extern-crates.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0259.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0260.rs b/masterror-knowledge/src/errors/resolution/e0260.rs new file mode 100644 index 0000000..2ef61de --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0260.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0260: name conflict with external crate + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0260", + title: LocalizedText::new( + "Name conflict with external crate", + "Конфликт имени с внешним крейтом", + "외부 크레이트와 이름 충돌" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An item was declared with the same name as an external crate that has +been imported into your project. + +You cannot have a local item declaration with the same name as an +external crate that's already been imported. You must either rename +your item or import the crate under a different name.", + "\ +Элемент был объявлен с тем же именем, что и внешний крейт, импортированный +в проект. + +Нельзя иметь локальное объявление элемента с тем же именем, что и +импортированный внешний крейт.", + "\ +프로젝트에 임포트된 외부 크레이트와 같은 이름으로 항목이 선언되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Rename the item", + "Переименуйте элемент", + "항목 이름 변경" + ), + code: "extern crate core;\n\nstruct xyz; // renamed from core" + }, + FixSuggestion { + description: LocalizedText::new( + "Import crate with alias", + "Импортируйте крейт с псевдонимом", + "별칭으로 크레이트 임포트" + ), + code: "extern crate core as xyz;\n\nstruct core; // now allowed" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Extern Crates", + url: "https://doc.rust-lang.org/reference/items/extern-crates.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0260.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0411.rs b/masterror-knowledge/src/errors/resolution/e0411.rs new file mode 100644 index 0000000..e574317 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0411.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0411: Self used outside impl/trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0411", + title: LocalizedText::new( + "Self used outside of impl, trait, or type definition", + "Self использован вне impl, трейта или определения типа", + "Self가 impl, 트레이트 또는 타입 정의 외부에서 사용됨" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +The Self keyword was used in a context where it's not valid. Self represents +the current type and can only be used within: +- impl blocks +- trait definitions +- type definitions + +Using Self anywhere else results in this error because there is no +\"current type\" to refer to.", + "\ +Ключевое слово Self использовано там, где это недопустимо. Self представляет +текущий тип и может использоваться только внутри: +- блоков impl +- определений трейтов +- определений типов", + "\ +Self 키워드가 유효하지 않은 컨텍스트에서 사용되었습니다. Self는 +현재 타입을 나타내며 다음 내에서만 사용할 수 있습니다: +- impl 블록 +- 트레이트 정의 +- 타입 정의" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use Self within a trait definition", + "Использовать Self внутри определения трейта", + "트레이트 정의 내에서 Self 사용" + ), + code: "trait Baz {\n fn bar() -> Self;\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Disambiguate with fully qualified syntax", + "Уточнить с помощью полного синтаксиса", + "완전한 구문으로 명확히 지정" + ), + code: "trait Baz : Foo {\n fn bar() -> ::Bar;\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0411.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0412.rs b/masterror-knowledge/src/errors/resolution/e0412.rs new file mode 100644 index 0000000..32a9aa1 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0412.rs @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0412", + title: LocalizedText::new( + "Cannot find type in this scope", + "Не удаётся найти тип в этой области видимости", + "이 스코프에서 타입을 찾을 수 없음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "The type you're referencing doesn't exist or isn't in scope.", + "Тип, на который вы ссылаетесь, не существует или не в области видимости.", + "참조하는 타입이 존재하지 않거나 스코프에 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new("Import the type", "Импортировать тип", "타입 import"), + code: "use crate::types::MyType;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0412.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0422.rs b/masterror-knowledge/src/errors/resolution/e0422.rs new file mode 100644 index 0000000..e0c34e2 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0422.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0422: identifier used as struct but is not a struct + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0422", + title: LocalizedText::new( + "Identifier is not a struct", + "Идентификатор не является структурой", + "식별자가 구조체가 아님" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An identifier was used with struct instantiation syntax ({ }) but it is +either undefined or not a struct. This happens when: +- The identifier doesn't exist at all +- The identifier refers to a variable, not a struct type", + "\ +Идентификатор использован с синтаксисом создания структуры ({ }), +но он либо не определён, либо не является структурой. Это происходит когда: +- Идентификатор вообще не существует +- Идентификатор ссылается на переменную, а не на тип структуры", + "\ +식별자가 구조체 인스턴스화 구문({ })으로 사용되었지만 정의되지 않았거나 +구조체가 아닙니다. 다음 경우에 발생합니다: +- 식별자가 존재하지 않음 +- 식별자가 구조체 타입이 아닌 변수를 참조함" + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Define the struct first", + "Сначала определить структуру", + "먼저 구조체 정의" + ), + code: "struct Foo { x: i32, y: i32 }\n\nlet x = Foo { x: 1, y: 2 };" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0422.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0423.rs b/masterror-knowledge/src/errors/resolution/e0423.rs new file mode 100644 index 0000000..ca98b4c --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0423.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0423: identifier used in wrong namespace + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0423", + title: LocalizedText::new( + "Expected value, found struct/module", + "Ожидалось значение, найдена структура/модуль", + "값이 예상되었으나 구조체/모듈이 발견됨" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An identifier was used in a way that doesn't match its namespace. Common cases: +- Using a struct name as a function: Foo() instead of Foo { } +- Forgetting ! on macro invocations: println(\"\") instead of println!(\"\") +- Using a module with . instead of :: : a.I instead of a::I", + "\ +Идентификатор использован не в соответствии с его пространством имён: +- Использование имени структуры как функции: Foo() вместо Foo { } +- Забыли ! при вызове макроса: println(\"\") вместо println!(\"\") +- Использование модуля с . вместо :: : a.I вместо a::I", + "\ +식별자가 네임스페이스와 맞지 않는 방식으로 사용되었습니다. 일반적인 경우: +- 구조체 이름을 함수처럼 사용: Foo() 대신 Foo { } +- 매크로 호출에서 ! 누락: println(\"\") 대신 println!(\"\") +- 모듈에 . 대신 :: 사용: a.I 대신 a::I" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add ! for macro invocation", + "Добавить ! для вызова макроса", + "매크로 호출에 ! 추가" + ), + code: "println!(\"Hello\"); // Not println(\"Hello\")" + }, + FixSuggestion { + description: LocalizedText::new( + "Use :: for module paths", + "Использовать :: для путей модулей", + "모듈 경로에 :: 사용" + ), + code: "let x = module::CONSTANT; // Not module.CONSTANT" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0423.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0424.rs b/masterror-knowledge/src/errors/resolution/e0424.rs new file mode 100644 index 0000000..c6f652e --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0424.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0424: self used without self receiver + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0424", + title: LocalizedText::new( + "self keyword used in function without self parameter", + "Ключевое слово self использовано в функции без параметра self", + "self 매개변수 없는 함수에서 self 키워드 사용됨" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +The self keyword was used inside an associated function that doesn't have +a self receiver parameter. The self keyword is only valid in methods - +associated functions that have self as their first parameter. + +Methods require a self receiver: self, &self, &mut self, or self: &mut Pin.", + "\ +Ключевое слово self использовано внутри ассоциированной функции без +параметра self. Ключевое слово self допустимо только в методах - +ассоциированных функциях с self в качестве первого параметра. + +Методы требуют параметр self: self, &self, &mut self или self: &mut Pin.", + "\ +self 수신자 매개변수가 없는 연관 함수 내에서 self 키워드가 사용되었습니다. +self 키워드는 메서드에서만 유효합니다 - self를 첫 번째 매개변수로 가지는 +연관 함수입니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add self receiver to make it a method", + "Добавить параметр self для создания метода", + "메서드로 만들기 위해 self 수신자 추가" + ), + code: "impl Foo {\n fn foo(&self) {\n self.bar(); // Now self is valid\n }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0424.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0425.rs b/masterror-knowledge/src/errors/resolution/e0425.rs new file mode 100644 index 0000000..b973d07 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0425.rs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0425", + title: LocalizedText::new( + "Cannot find value in this scope", + "Не удаётся найти значение в этой области видимости", + "이 스코프에서 값을 찾을 수 없음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "You're using a variable, function, or constant that doesn't exist in scope.", + "Вы используете переменную, функцию или константу, которая не существует в текущей области.", + "스코프에 존재하지 않는 변수, 함수 또는 상수를 사용하고 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Declare the variable", + "Объявить переменную", + "변수 선언" + ), + code: "let x = 10;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0425.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0426.rs b/masterror-knowledge/src/errors/resolution/e0426.rs new file mode 100644 index 0000000..8f2a31e --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0426.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0426: use of undeclared label + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0426", + title: LocalizedText::new( + "Use of undeclared label", + "Использование необъявленной метки", + "선언되지 않은 레이블 사용" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A label was used in a break or continue statement that has not been declared. +Labels are used with loop control flow statements to specify which loop to +exit or continue. Labels must be explicitly declared with a single quote +prefix before the loop keyword.", + "\ +В операторе break или continue использована метка, которая не была объявлена. +Метки используются с операторами управления циклами для указания, какой цикл +прервать или продолжить. Метки должны быть явно объявлены с префиксом +одинарной кавычки перед ключевым словом цикла.", + "\ +선언되지 않은 레이블이 break 또는 continue 문에서 사용되었습니다. +레이블은 루프 제어 흐름 문에서 어떤 루프를 종료하거나 계속할지 지정하는 데 +사용됩니다. 레이블은 루프 키워드 앞에 작은따옴표 접두사와 함께 명시적으로 +선언되어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Declare the label before the loop", + "Объявить метку перед циклом", + "루프 앞에 레이블 선언" + ), + code: "'outer: loop {\n break 'outer; // Label declared with 'outer:\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0426.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0428.rs b/masterror-knowledge/src/errors/resolution/e0428.rs new file mode 100644 index 0000000..0efa8d0 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0428.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0428: duplicate definition + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0428", + title: LocalizedText::new( + "Duplicate definition of type or module", + "Повторное определение типа или модуля", + "타입 또는 모듈의 중복 정의" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A type or module has been defined more than once in the same scope. Rust +does not allow duplicate definitions of types, structs, enums, or modules +with the same name in the same namespace.", + "\ +Тип или модуль определён более одного раза в одной области видимости. +Rust не допускает повторных определений типов, структур, перечислений +или модулей с одинаковым именем в одном пространстве имён.", + "\ +같은 스코프에서 타입 또는 모듈이 두 번 이상 정의되었습니다. Rust는 +같은 네임스페이스에서 같은 이름의 타입, 구조체, 열거형 또는 모듈의 +중복 정의를 허용하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Rename the duplicate definition", + "Переименовать повторное определение", + "중복 정의 이름 변경" + ), + code: "struct Bar;\nstruct Bar2; // Renamed from Bar" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0428.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0429.rs b/masterror-knowledge/src/errors/resolution/e0429.rs new file mode 100644 index 0000000..d765036 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0429.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0429: self cannot appear alone in use + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0429", + title: LocalizedText::new( + "self cannot appear alone as last segment in use", + "self не может быть последним сегментом в use", + "use에서 self가 마지막 세그먼트로 단독 사용될 수 없음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +The self keyword was used alone at the end of a use statement, which is +invalid. The self keyword in use statements is only valid within a +brace-enclosed list of imports.", + "\ +Ключевое слово self использовано в одиночку в конце оператора use, +что недопустимо. Ключевое слово self в операторах use допустимо только +внутри списка импортов в фигурных скобках.", + "\ +use 문 끝에서 self 키워드가 단독으로 사용되었으며, 이는 유효하지 않습니다. +use 문에서 self 키워드는 중괄호로 묶인 임포트 목록 내에서만 유효합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use self within braces", + "Использовать self внутри фигурных скобок", + "중괄호 내에서 self 사용" + ), + code: "use std::fmt::{self, Debug};" + }, + FixSuggestion { + description: LocalizedText::new( + "Import the namespace directly", + "Импортировать пространство имён напрямую", + "네임스페이스 직접 임포트" + ), + code: "use std::fmt; // Instead of use std::fmt::self;" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0429.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0430.rs b/masterror-knowledge/src/errors/resolution/e0430.rs new file mode 100644 index 0000000..d7d6da8 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0430.rs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0430: self import appears more than once + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0430", + title: LocalizedText::new( + "self import appears more than once", + "Импорт self появляется более одного раза", + "self 임포트가 두 번 이상 나타남" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +The self import appeared multiple times in a single use statement. The self +import can only appear once in an import list.", + "\ +Импорт self появился несколько раз в одном операторе use. Импорт self +может появляться только один раз в списке импортов.", + "\ +단일 use 문에서 self 임포트가 여러 번 나타났습니다. self 임포트는 +임포트 목록에서 한 번만 나타날 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove duplicate self import", + "Удалить повторный импорт self", + "중복 self 임포트 제거" + ), + code: "use something::{self}; // Only one self" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0430.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0431.rs b/masterror-knowledge/src/errors/resolution/e0431.rs new file mode 100644 index 0000000..b2444dd --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0431.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0431: invalid self import + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0431", + title: LocalizedText::new( + "self import can only appear with non-empty prefix", + "Импорт self может использоваться только с непустым префиксом", + "self 임포트는 비어 있지 않은 접두사와 함께만 사용 가능" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An attempt was made to import the current module into itself using self +without a proper prefix. The self keyword in an import list can only be +used with a non-empty prefix - you cannot import the current module into +itself.", + "\ +Попытка импортировать текущий модуль в себя с помощью self без +правильного префикса. Ключевое слово self в списке импортов может +использоваться только с непустым префиксом.", + "\ +적절한 접두사 없이 self를 사용하여 현재 모듈을 자신에게 임포트하려고 +시도했습니다. 임포트 목록의 self 키워드는 비어 있지 않은 접두사와 +함께만 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove the invalid import", + "Удалить недопустимый импорт", + "유효하지 않은 임포트 제거" + ), + code: "// Remove: use {self};\n// Instead, just access items directly" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0431.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0432.rs b/masterror-knowledge/src/errors/resolution/e0432.rs new file mode 100644 index 0000000..cff690c --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0432.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0432: unresolved import + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0432", + title: LocalizedText::new( + "Unresolved import", + "Неразрешённый импорт", + "해결되지 않은 임포트" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An import could not be resolved. Rust cannot find or resolve the import +statement. Common causes: +- Incorrect import path +- Misspelled module or item name +- Item not publicly accessible +- Missing extern crate declaration (Rust 2015)", + "\ +Импорт не может быть разрешён. Rust не может найти или разрешить +оператор импорта. Распространённые причины: +- Неправильный путь импорта +- Опечатка в имени модуля или элемента +- Элемент не является публичным +- Отсутствует объявление extern crate (Rust 2015)", + "\ +임포트를 해결할 수 없습니다. Rust가 임포트 문을 찾거나 해결할 수 +없습니다. 일반적인 원인: +- 잘못된 임포트 경로 +- 모듈 또는 항목 이름 오타 +- 항목에 공개 접근 불가 +- extern crate 선언 누락 (Rust 2015)" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use self:: prefix for relative imports", + "Использовать префикс self:: для относительных импортов", + "상대 임포트에 self:: 접두사 사용" + ), + code: "use self::something::Foo;\n\nmod something {\n pub struct Foo;\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use crate:: for imports from current crate", + "Использовать crate:: для импорта из текущего крейта", + "현재 크레이트에서 임포트할 때 crate:: 사용" + ), + code: "use crate::my_module::MyType;" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0432.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0433.rs b/masterror-knowledge/src/errors/resolution/e0433.rs new file mode 100644 index 0000000..b9e4d19 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0433.rs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0433", + title: LocalizedText::new( + "Failed to resolve: use of undeclared crate or module", + "Не удалось разрешить: необъявленный крейт или модуль", + "해결 실패: 선언되지 않은 크레이트 또는 모듈" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "Rust can't find the crate, module, or type you're trying to use.", + "Rust не может найти крейт, модуль или тип.", + "Rust가 크레이트, 모듈 또는 타입을 찾을 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new("Add use statement", "Добавить use", "use 문 추가"), + code: "use std::collections::HashMap;" + }, + FixSuggestion { + description: LocalizedText::new( + "Add dependency", + "Добавить зависимость", + "의존성 추가" + ), + code: "[dependencies]\nserde = \"1.0\"" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0433.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0434.rs b/masterror-knowledge/src/errors/resolution/e0434.rs new file mode 100644 index 0000000..9b0f2a9 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0434.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0434: cannot capture dynamic environment in fn item + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0434", + title: LocalizedText::new( + "Cannot capture dynamic environment in fn item", + "Нельзя захватить динамическое окружение во вложенной функции", + "fn 항목에서 동적 환경을 캡처할 수 없음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An inner function tried to access a variable from its containing scope. +Rust's inner functions cannot capture variables from their dynamic +environment like closures can. Inner functions are essentially treated +as top-level items.", + "\ +Вложенная функция попыталась использовать переменную из внешней +области видимости. Вложенные функции в Rust не могут захватывать +переменные из динамического окружения, как это делают замыкания.", + "\ +내부 함수가 포함하는 스코프의 변수에 접근하려고 시도했습니다. +Rust의 내부 함수는 클로저처럼 동적 환경에서 변수를 캡처할 수 +없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a closure instead", + "Использовать замыкание", + "대신 클로저 사용" + ), + code: "fn foo() {\n let y = 5;\n let bar = || { y }; // Closure captures y\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use const or static items", + "Использовать const или static", + "const 또는 static 항목 사용" + ), + code: "fn foo() {\n const Y: u32 = 5;\n fn bar() -> u32 { Y } // Can access const\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0434.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0435.rs b/masterror-knowledge/src/errors/resolution/e0435.rs new file mode 100644 index 0000000..c6d9233 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0435.rs @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0435: non-constant value in constant expression + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0435", + title: LocalizedText::new( + "Non-constant value in constant expression", + "Неконстантное значение в константном выражении", + "상수 표현식에 비상수 값" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A non-constant (runtime) value was used in a context that requires a +compile-time constant expression. Certain constructs like array lengths +require constant expressions and cannot accept runtime variables. + +Variables (let bindings) are runtime values, while constants (const) are +compile-time values.", + "\ +Неконстантное (времени выполнения) значение использовано там, где +требуется константное выражение времени компиляции. Некоторые +конструкции, такие как длина массива, требуют константных выражений. + +Переменные (let) - значения времени выполнения, а константы (const) - +значения времени компиляции.", + "\ +컴파일 타임 상수 표현식이 필요한 컨텍스트에서 비상수(런타임) 값이 +사용되었습니다. 배열 길이와 같은 특정 구조는 상수 표현식이 필요하며 +런타임 변수를 허용하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a const instead of let", + "Использовать const вместо let", + "let 대신 const 사용" + ), + code: "const FOO: usize = 42;\nlet a: [u8; FOO]; // ok!" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a literal directly", + "Использовать литерал напрямую", + "리터럴 직접 사용" + ), + code: "let a: [u8; 42]; // ok!" + } + ], + links: &[ + DocLink { + title: "Rust Book: Variables and Constants", + url: "https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0435.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0436.rs b/masterror-knowledge/src/errors/resolution/e0436.rs new file mode 100644 index 0000000..47181b4 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0436.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0436: functional record update on non-struct + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0436", + title: LocalizedText::new( + "Functional record update requires a struct", + "Функциональное обновление записи требует структуру", + "함수적 레코드 업데이트에는 구조체가 필요함" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +The functional record update syntax (..) was used on something other than +a struct. This syntax is only valid for structs, not for enum variants +(even struct-like enum variants).", + "\ +Синтаксис функционального обновления записи (..) использован не для +структуры. Этот синтаксис допустим только для структур, не для +вариантов перечислений (даже структуроподобных).", + "\ +함수적 레코드 업데이트 구문(..)이 구조체가 아닌 것에 사용되었습니다. +이 구문은 구조체에만 유효하며, 열거형 변형(구조체와 유사한 열거형 +변형 포함)에는 유효하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Extract and specify fields explicitly", + "Извлечь и указать поля явно", + "필드를 명시적으로 추출하고 지정" + ), + code: "match variant {\n Enum::Variant { field, .. } =>\n Enum::Variant { field, other: true }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0436.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0530.rs b/masterror-knowledge/src/errors/resolution/e0530.rs new file mode 100644 index 0000000..73cb249 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0530.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0530: binding shadowed something it shouldn't + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0530", + title: LocalizedText::new( + "Match binding shadows an existing item", + "Привязка в match затеняет существующий элемент", + "매치 바인딩이 기존 항목을 섀도잉함" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A binding shadowed something it shouldn't. This error occurs when a match arm +or variable uses a name that conflicts with existing bindings, such as: +- Struct names +- Enum variants +- Statics +- Associated constants + +This error also occurs when an enum variant with fields is used in a pattern +without its fields.", + "\ +Привязка затенила то, что не должна была. Эта ошибка возникает, когда ветвь +match или переменная использует имя, конфликтующее с существующими привязками: +- Имена структур +- Варианты перечислений +- Статические переменные +- Ассоциированные константы", + "\ +바인딩이 그래선 안 되는 것을 섀도잉했습니다. 이 오류는 매치 암이나 변수가 +기존 바인딩과 충돌하는 이름을 사용할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a different binding name", + "Использовать другое имя привязки", + "다른 바인딩 이름 사용" + ), + code: "static TEST: i32 = 0;\nmatch r {\n some_value => {} // not TEST\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use const instead of static for pattern matching", + "Использовать const вместо static для сопоставления", + "패턴 매칭을 위해 static 대신 const 사용" + ), + code: "const TEST: i32 = 0; // const allowed in patterns\nmatch r {\n TEST => {}\n _ => {}\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0530.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0531.rs b/masterror-knowledge/src/errors/resolution/e0531.rs new file mode 100644 index 0000000..84527d9 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0531.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0531: unknown tuple struct or variant + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0531", + title: LocalizedText::new( + "Unknown tuple struct or variant", + "Неизвестная кортежная структура или вариант", + "알 수 없는 튜플 구조체 또는 변형" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An unknown tuple struct or variant has been used. This error occurs when you +attempt to use a tuple struct or enum variant that either: +- Hasn't been imported into the current scope +- Is misspelled or doesn't exist +- Is referenced without proper qualification + +You need to ensure tuple structs and enum variants are properly accessible.", + "\ +Была использована неизвестная кортежная структура или вариант. Эта ошибка +возникает при попытке использовать кортежную структуру или вариант +перечисления, который: +- Не импортирован в текущую область видимости +- Неправильно написан или не существует +- Указан без правильной квалификации", + "\ +알 수 없는 튜플 구조체 또는 변형이 사용되었습니다. 이 오류는 다음과 같은 +튜플 구조체나 열거형 변형을 사용하려고 할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Import the enum variant into scope", + "Импортировать вариант перечисления в область видимости", + "열거형 변형을 스코프로 가져오기" + ), + code: "enum Foo { Bar(u32) }\nuse Foo::*; // import variants\n\nmatch Type(12) {\n Type(x) => {}\n _ => {}\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use fully qualified path", + "Использовать полный путь", + "완전한 경로 사용" + ), + code: "match val { Foo::Bar(x) => {} }" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0531.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0532.rs b/masterror-knowledge/src/errors/resolution/e0532.rs new file mode 100644 index 0000000..85bedaa --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0532.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0532: pattern arm did not match expected kind + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0532", + title: LocalizedText::new( + "Pattern arm doesn't match expected kind", + "Ветвь образца не соответствует ожидаемому виду", + "패턴 암이 예상 종류와 일치하지 않음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A pattern in a match arm doesn't match the expected pattern type for that +value. This error occurs when you're trying to match a pattern of one kind +(e.g., a unit variant) when the actual value is a different kind (e.g., a +tuple variant). + +Ensure that the pattern in your match arm matches the structure of the variant.", + "\ +Образец в ветви match не соответствует ожидаемому типу образца для этого +значения. Эта ошибка возникает при попытке сопоставить образец одного вида +(например, единичный вариант), когда фактическое значение другого вида +(например, кортежный вариант).", + "\ +매치 암의 패턴이 해당 값에 대해 예상되는 패턴 타입과 일치하지 않습니다. +이 오류는 실제 값이 다른 종류(예: 튜플 변형)일 때 한 종류의 패턴(예: 유닛 변형)을 +매칭하려고 할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match tuple variants with parentheses", + "Сопоставлять кортежные варианты со скобками", + "튜플 변형을 괄호와 함께 매칭" + ), + code: "match *state {\n State::Failed(ref msg) => println!(\"Failed: {}\", msg),\n _ => ()\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0532.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0533.rs b/masterror-knowledge/src/errors/resolution/e0533.rs new file mode 100644 index 0000000..9d8395e --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0533.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0533: method used as pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0533", + title: LocalizedText::new( + "Non-pattern item used as match pattern", + "Не-образцовый элемент использован как образец match", + "비패턴 항목이 매치 패턴으로 사용됨" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An item which isn't a unit struct, a variant, nor a constant has been used as +a match pattern. In Rust, only unit structs, enum variants, and constants can +be used directly in match patterns. + +Methods and other non-pattern items cannot be used as patterns.", + "\ +Элемент, который не является единичной структурой, вариантом или константой, +был использован как образец match. В Rust только единичные структуры, +варианты перечислений и константы могут использоваться напрямую в образцах.", + "\ +유닛 구조체, 변형 또는 상수가 아닌 항목이 매치 패턴으로 사용되었습니다. +Rust에서는 유닛 구조체, 열거형 변형 및 상수만 매치 패턴에서 직접 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a guard clause to compare against method result", + "Использовать охранное выражение для сравнения с результатом метода", + "메서드 결과와 비교하기 위해 가드 절 사용" + ), + code: "match 0u32 {\n x if x == Tortoise.turtle() => {} // bind then compare\n _ => {}\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0533.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0577.rs b/masterror-knowledge/src/errors/resolution/e0577.rs new file mode 100644 index 0000000..2249025 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0577.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0577: non-module in visibility scope + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0577", + title: LocalizedText::new( + "Expected module in visibility path, found something else", + "Ожидался модуль в пути видимости, найдено что-то другое", + "가시성 경로에서 모듈이 예상되었지만 다른 것 발견" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +Something other than a module was found in visibility scope. The +`pub(in path)` syntax requires that the path points to a module, not other +types like enums or structs. + +Additionally, the visibility scope can only be applied to ancestors in the +module hierarchy.", + "\ +В области видимости было найдено что-то, кроме модуля. Синтаксис +`pub(in path)` требует, чтобы путь указывал на модуль, а не на другие +типы, такие как перечисления или структуры. + +Кроме того, область видимости может применяться только к предкам +в иерархии модулей.", + "\ +가시성 스코프에서 모듈이 아닌 다른 것이 발견되었습니다. `pub(in path)` 구문은 +경로가 열거형이나 구조체와 같은 다른 타입이 아닌 모듈을 가리켜야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a module path instead of enum/struct", + "Использовать путь к модулю вместо enum/struct", + "enum/struct 대신 모듈 경로 사용" + ), + code: "pub mod sea {\n pub (in crate::sea) struct Shark; // ok\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0577.html" + }] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0583.rs b/masterror-knowledge/src/errors/resolution/e0583.rs new file mode 100644 index 0000000..7d83b1f --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0583.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0583: file not found for module + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0583", + title: LocalizedText::new( + "File not found for out-of-line module", + "Файл не найден для внешнего модуля", + "아웃오브라인 모듈에 대한 파일을 찾을 수 없음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A file wasn't found for an out-of-line module. This error occurs when you +declare an out-of-line module in Rust but the corresponding file doesn't +exist in the file system. + +For a module named `foo`, you need to create either `foo.rs` or `foo/mod.rs` +in the same directory as the file declaring the module.", + "\ +Файл не был найден для внешнего модуля. Эта ошибка возникает, когда вы +объявляете внешний модуль в Rust, но соответствующий файл не существует +в файловой системе. + +Для модуля с именем `foo` нужно создать либо `foo.rs`, либо `foo/mod.rs`.", + "\ +아웃오브라인 모듈에 대한 파일을 찾을 수 없습니다. 이 오류는 Rust에서 +아웃오브라인 모듈을 선언했지만 해당 파일이 파일 시스템에 존재하지 않을 때 +발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Create the module file", + "Создать файл модуля", + "모듈 파일 생성" + ), + code: "// Create: file_that_doesnt_exist.rs\n// Or: file_that_doesnt_exist/mod.rs" + }], + links: &[ + DocLink { + title: "Modules Chapter", + url: "https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0583.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0601.rs b/masterror-knowledge/src/errors/resolution/e0601.rs new file mode 100644 index 0000000..6abda94 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0601.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0601: no main function found + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0601", + title: LocalizedText::new( + "No main function found in binary crate", + "Функция main не найдена в бинарном крейте", + "바이너리 크레이트에서 main 함수를 찾을 수 없음" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +No `main` function was found in a binary crate. The `main` function is the +entry point for any Rust binary - it's where program execution begins. + +This error occurs when: +- Creating a binary crate without including a `main` function +- Accidentally deleting or commenting out the `main` function +- Attempting to run a library crate as a binary", + "\ +Функция `main` не найдена в бинарном крейте. Функция `main` является +точкой входа для любого бинарного файла Rust - это место, где начинается +выполнение программы. + +Эта ошибка возникает, когда: +- Создаётся бинарный крейт без функции `main` +- Случайно удалена или закомментирована функция `main` +- Попытка запустить библиотечный крейт как бинарный", + "\ +바이너리 크레이트에서 `main` 함수를 찾을 수 없습니다. `main` 함수는 +모든 Rust 바이너리의 진입점입니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add a main function", + "Добавить функцию main", + "main 함수 추가" + ), + code: "fn main() {\n println!(\"Hello world!\");\n}" + }], + links: &[ + DocLink { + title: "The Rust Book", + url: "https://doc.rust-lang.org/book/" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0601.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0602.rs b/masterror-knowledge/src/errors/resolution/e0602.rs new file mode 100644 index 0000000..3defe41 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0602.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0602: unknown lint + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0602", + title: LocalizedText::new( + "Unknown or invalid lint name", + "Неизвестное или недопустимое имя линта", + "알 수 없거나 잘못된 린트 이름" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An unknown or invalid lint name is used on the command line when invoking +the Rust compiler (`rustc`). + +This error is triggered when you: +- Misspell a lint name +- Use a lint that no longer exists in the current Rust version +- Pass an invalid/unrecognized lint to the compiler", + "\ +Неизвестное или недопустимое имя линта используется в командной строке +при вызове компилятора Rust (`rustc`). + +Эта ошибка возникает, когда вы: +- Допускаете опечатку в имени линта +- Используете линт, который больше не существует в текущей версии Rust +- Передаёте недопустимый/нераспознанный линт компилятору", + "\ +Rust 컴파일러(`rustc`)를 호출할 때 명령줄에서 알 수 없거나 잘못된 +린트 이름이 사용되었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Check lint spelling and view valid lints", + "Проверить правописание линта и просмотреть допустимые линты", + "린트 철자 확인 및 유효한 린트 보기" + ), + code: "rustc -W help" + }], + links: &[ + DocLink { + title: "Lints", + url: "https://doc.rust-lang.org/rustc/lints/index.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0602.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0603.rs b/masterror-knowledge/src/errors/resolution/e0603.rs new file mode 100644 index 0000000..b83d105 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0603.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0603: private item used outside its scope + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0603", + title: LocalizedText::new( + "Private item used outside its scope", + "Приватный элемент использован вне своей области", + "비공개 항목이 범위 외부에서 사용됨" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A private item was used outside its scope. Rust's visibility rules prevent +external code from accessing private items by default. + +Items (constants, functions, structs, etc.) are private by default and +can only be accessed from within their defining module unless marked `pub`.", + "\ +Приватный элемент был использован вне своей области видимости. Правила +видимости Rust по умолчанию запрещают внешнему коду доступ к приватным +элементам. + +Элементы (константы, функции, структуры и т.д.) по умолчанию приватны и +могут быть доступны только из определяющего их модуля, если не помечены +`pub`.", + "\ +비공개 항목이 범위 외부에서 사용되었습니다. Rust의 가시성 규칙은 기본적으로 +외부 코드가 비공개 항목에 접근하는 것을 방지합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Make the item public", + "Сделать элемент публичным", + "항목을 공개로 설정" + ), + code: "mod foo {\n pub const VALUE: u32 = 42; // now public\n}" + }], + links: &[ + DocLink { + title: "Visibility and Privacy", + url: "https://doc.rust-lang.org/reference/visibility-and-privacy.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0603.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0615.rs b/masterror-knowledge/src/errors/resolution/e0615.rs new file mode 100644 index 0000000..e00a6dc --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0615.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0615: attempted to access method like a field + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0615", + title: LocalizedText::new( + "Attempted to access a method like a field", + "Попытка доступа к методу как к полю", + "메서드를 필드처럼 접근하려고 시도" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +Attempted to access a method without calling it (i.e., without parentheses), +treating it as if it were a field or property of a struct. + +Methods must be called with parentheses `()` to execute them, while fields +are accessed directly by name.", + "\ +Попытка доступа к методу без его вызова (т.е. без скобок), обращаясь с ним +как с полем или свойством структуры. + +Методы должны вызываться со скобками `()` для их выполнения, тогда как +к полям доступ осуществляется напрямую по имени.", + "\ +메서드를 호출하지 않고(즉, 괄호 없이) 접근하려고 시도했습니다. +메서드는 실행하려면 괄호 `()`로 호출해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Call the method with parentheses", + "Вызвать метод со скобками", + "괄호로 메서드 호출" + ), + code: "f.method(); // call with parentheses" + }], + links: &[ + DocLink { + title: "Method Syntax", + url: "https://doc.rust-lang.org/book/ch05-03-method-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0615.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0616.rs b/masterror-knowledge/src/errors/resolution/e0616.rs new file mode 100644 index 0000000..0419fb3 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0616.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0616: private field access + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0616", + title: LocalizedText::new( + "Attempted to access a private field", + "Попытка доступа к приватному полю", + "비공개 필드에 접근 시도" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +Attempted to access a private field on a struct from outside its module. +In Rust, struct fields are private by default unless explicitly marked +with the `pub` keyword.", + "\ +Попытка доступа к приватному полю структуры извне её модуля. В Rust поля +структур по умолчанию приватны, если явно не помечены ключевым словом `pub`.", + "\ +모듈 외부에서 구조체의 비공개 필드에 접근하려고 시도했습니다. +Rust에서 구조체 필드는 `pub` 키워드로 명시적으로 표시하지 않으면 +기본적으로 비공개입니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Make the field public", + "Сделать поле публичным", + "필드를 공개로 설정" + ), + code: "pub struct Foo {\n pub x: u32, // now public\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Provide a getter method (encapsulation)", + "Предоставить метод-получатель (инкапсуляция)", + "getter 메서드 제공 (캡슐화)" + ), + code: "impl Foo {\n pub fn get_x(&self) -> &u32 { &self.x }\n}" + } + ], + links: &[ + DocLink { + title: "Visibility and Privacy", + url: "https://doc.rust-lang.org/reference/visibility-and-privacy.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0616.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0624.rs b/masterror-knowledge/src/errors/resolution/e0624.rs new file mode 100644 index 0000000..c743909 --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0624.rs @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0624: private item access + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0624", + title: LocalizedText::new( + "Private item used outside of its scope", + "Приватный элемент использован вне своей области", + "비공개 항목이 범위 외부에서 사용됨" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +A private item was used outside of its scope. In Rust, items that aren't +explicitly marked as `pub` (public) are private and can only be accessed +within their defining module or scope. + +This commonly occurs when trying to call a private method from outside +its defining module.", + "\ +Приватный элемент был использован вне своей области видимости. В Rust +элементы, не помеченные явно как `pub` (публичные), являются приватными +и могут быть доступны только в определяющем их модуле или области. + +Это часто происходит при попытке вызвать приватный метод извне +определяющего его модуля.", + "\ +비공개 항목이 범위 외부에서 사용되었습니다. Rust에서 명시적으로 `pub`로 +표시되지 않은 항목은 비공개이며 정의하는 모듈이나 범위 내에서만 +접근할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Make the item public", + "Сделать элемент публичным", + "항목을 공개로 설정" + ), + code: "impl Foo {\n pub fn method(&self) {} // now public\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a public wrapper function", + "Использовать публичную функцию-обёртку", + "공개 래퍼 함수 사용" + ), + code: "pub fn call_method(foo: &Foo) {\n foo.method(); // called within scope\n}" + } + ], + links: &[ + DocLink { + title: "Visibility and Privacy", + url: "https://doc.rust-lang.org/reference/visibility-and-privacy.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0624.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/resolution/e0659.rs b/masterror-knowledge/src/errors/resolution/e0659.rs new file mode 100644 index 0000000..ce2c17c --- /dev/null +++ b/masterror-knowledge/src/errors/resolution/e0659.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0659: ambiguous item usage + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0659", + title: LocalizedText::new( + "Ambiguous item usage", + "Неоднозначное использование элемента", + "모호한 항목 사용" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +An item usage is ambiguous because two or more items with the same name +have been imported into a module, creating a naming conflict. + +This error occurs when: +- Multiple items with identical names are imported into the same module +- These items are reexported via wildcard imports (`pub use module::*`) +- You attempt to reference the ambiguous name without a full path", + "\ +Использование элемента неоднозначно, потому что два или более элемента +с одинаковым именем были импортированы в модуль, создавая конфликт имён. + +Эта ошибка возникает, когда: +- Несколько элементов с одинаковыми именами импортируются в один модуль +- Эти элементы реэкспортируются через подстановочный импорт (`pub use module::*`) +- Вы пытаетесь обратиться к неоднозначному имени без полного пути", + "\ +동일한 이름을 가진 두 개 이상의 항목이 모듈에 가져와져서 이름 충돌이 +발생하여 항목 사용이 모호합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use full path to disambiguate", + "Использовать полный путь для устранения неоднозначности", + "모호성 해소를 위해 전체 경로 사용" + ), + code: "mod collider {\n pub use crate::moon;\n pub use crate::earth;\n}\n\ncrate::collider::moon::foo(); // disambiguated" + }], + links: &[ + DocLink { + title: "Use Declarations", + url: "https://doc.rust-lang.org/reference/items/use-declarations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0659.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/simd.rs b/masterror-knowledge/src/errors/simd.rs new file mode 100644 index 0000000..347a2f5 --- /dev/null +++ b/masterror-knowledge/src/errors/simd.rs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! SIMD related errors. + +mod e0075; +mod e0076; +mod e0077; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[&e0075::ENTRY, &e0076::ENTRY, &e0077::ENTRY]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/simd/e0075.rs b/masterror-knowledge/src/errors/simd/e0075.rs new file mode 100644 index 0000000..6bcde8a --- /dev/null +++ b/masterror-knowledge/src/errors/simd/e0075.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0075: SIMD struct must have single array field + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0075", + title: LocalizedText::new( + "SIMD struct must have single array field", + "SIMD структура должна иметь одно поле-массив", + "SIMD 구조체는 단일 배열 필드를 가져야 함" + ), + category: Category::Simd, + explanation: LocalizedText::new( + "\ +The `#[repr(simd)]` attribute can only be applied to structs with exactly one +field. Empty structs and structs with multiple fields are not allowed. + +Example: + #[repr(simd)] + struct Bad; // Error: empty struct + + #[repr(simd)] + struct Bad2([u32; 1], [u32; 1]); // Error: multiple fields", + "\ +Атрибут `#[repr(simd)]` можно применять только к структурам с ровно одним +полем. Пустые структуры и структуры с несколькими полями не допускаются.", + "\ +`#[repr(simd)]` 속성은 정확히 하나의 필드를 가진 구조체에만 적용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a single array field", + "Использовать одно поле-массив", + "단일 배열 필드 사용" + ), + code: "#[repr(simd)]\nstruct Good([u32; 4]);" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0075.html" + }] +}; diff --git a/masterror-knowledge/src/errors/simd/e0076.rs b/masterror-knowledge/src/errors/simd/e0076.rs new file mode 100644 index 0000000..9321766 --- /dev/null +++ b/masterror-knowledge/src/errors/simd/e0076.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0076: SIMD field must be an array + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0076", + title: LocalizedText::new( + "SIMD field must be an array", + "Поле SIMD должно быть массивом", + "SIMD 필드는 배열이어야 함" + ), + category: Category::Simd, + explanation: LocalizedText::new( + "\ +When using `#[repr(simd)]` on a tuple struct, the field type must be an array. +This is required to represent SIMD vector lanes. + +Example: + #[repr(simd)] + struct Bad(u16); // Error: not an array", + "\ +При использовании `#[repr(simd)]` на tuple struct тип поля должен быть массивом. +Это необходимо для представления SIMD-векторных дорожек.", + "\ +튜플 구조체에 `#[repr(simd)]`를 사용할 때 필드 타입은 배열이어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Wrap in array notation", + "Обернуть в нотацию массива", + "배열 표기법으로 감싸기" + ), + code: "#[repr(simd)]\nstruct Good([u16; 1]); // Single-lane vector" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0076.html" + }] +}; diff --git a/masterror-knowledge/src/errors/simd/e0077.rs b/masterror-knowledge/src/errors/simd/e0077.rs new file mode 100644 index 0000000..46c32b3 --- /dev/null +++ b/masterror-knowledge/src/errors/simd/e0077.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0077: SIMD element must be a machine type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0077", + title: LocalizedText::new( + "SIMD element must be a machine type", + "Элемент SIMD должен быть машинным типом", + "SIMD 요소는 기계 타입이어야 함" + ), + category: Category::Simd, + explanation: LocalizedText::new( + "\ +When using `#[repr(simd)]`, all array elements must be machine types that +can be directly operated on by SIMD instructions (like u32, f64, i16). + +Example: + #[repr(simd)] + struct Bad([String; 2]); // Error: String is not a machine type", + "\ +При использовании `#[repr(simd)]` все элементы массива должны быть машинными +типами, которые могут напрямую обрабатываться SIMD-инструкциями.", + "\ +`#[repr(simd)]`를 사용할 때 모든 배열 요소는 SIMD 명령어로 직접 작동할 수 있는 기계 타입이어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use primitive machine types", + "Использовать примитивные машинные типы", + "원시 기계 타입 사용" + ), + code: "#[repr(simd)]\nstruct Good([u32; 4]); // u32 is a machine type" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0077.html" + }] +}; diff --git a/masterror-knowledge/src/errors/structs.rs b/masterror-knowledge/src/errors/structs.rs new file mode 100644 index 0000000..41ddda4 --- /dev/null +++ b/masterror-knowledge/src/errors/structs.rs @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Struct-related errors. + +mod e0124; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[&e0124::ENTRY]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/structs/e0124.rs b/masterror-knowledge/src/errors/structs/e0124.rs new file mode 100644 index 0000000..efcb4bd --- /dev/null +++ b/masterror-knowledge/src/errors/structs/e0124.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0124: field is already declared + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0124", + title: LocalizedText::new( + "Field is already declared", + "Поле уже объявлено", + "필드가 이미 선언됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A struct was declared with two fields having the same name. +Rust does not allow multiple fields in a struct to share the same identifier. + +Verify that all field names are correctly spelled and unique.", + "\ +Структура была объявлена с двумя полями с одинаковым именем. +Rust не позволяет нескольким полям структуры иметь одинаковый идентификатор. + +Убедитесь, что все имена полей написаны правильно и уникальны.", + "\ +동일한 이름을 가진 두 개의 필드로 구조체가 선언되었습니다. +Rust는 구조체의 여러 필드가 동일한 식별자를 공유하는 것을 허용하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Rename one of the duplicate fields", + "Переименовать одно из дублирующихся полей", + "중복된 필드 중 하나의 이름 변경" + ), + code: "struct Foo {\n field1: i32,\n field2: i32, // not field1: i32\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Defining Structs", + url: "https://doc.rust-lang.org/book/ch05-01-defining-structs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0124.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax.rs b/masterror-knowledge/src/errors/syntax.rs new file mode 100644 index 0000000..b29215a --- /dev/null +++ b/masterror-knowledge/src/errors/syntax.rs @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Syntax and pattern related errors. + +mod e0062; +mod e0063; +mod e0067; +mod e0081; +mod e0084; +mod e0091; +mod e0121; +mod e0124; +mod e0128; +mod e0131; +mod e0133; +mod e0152; +mod e0178; +mod e0229; +mod e0230; +mod e0231; +mod e0232; +mod e0264; +mod e0267; +mod e0268; +mod e0297; +mod e0408; +mod e0409; +mod e0415; +mod e0416; +mod e0519; +mod e0569; +mod e0571; +mod e0572; +mod e0579; +mod e0580; +mod e0586; +mod e0590; +mod e0627; +mod e0628; +mod e0634; +mod e0646; +mod e0648; +mod e0670; +mod e0695; +mod e0696; +mod e0697; +mod e0703; +mod e0704; +mod e0705; +mod e0742; +mod e0748; +mod e0753; +mod e0758; +mod e0762; +mod e0763; +mod e0765; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0062::ENTRY, + &e0063::ENTRY, + &e0067::ENTRY, + &e0081::ENTRY, + &e0084::ENTRY, + &e0091::ENTRY, + &e0121::ENTRY, + &e0124::ENTRY, + &e0128::ENTRY, + &e0131::ENTRY, + &e0133::ENTRY, + &e0152::ENTRY, + &e0178::ENTRY, + &e0229::ENTRY, + &e0230::ENTRY, + &e0231::ENTRY, + &e0232::ENTRY, + &e0264::ENTRY, + &e0267::ENTRY, + &e0268::ENTRY, + &e0297::ENTRY, + &e0408::ENTRY, + &e0409::ENTRY, + &e0415::ENTRY, + &e0416::ENTRY, + &e0519::ENTRY, + &e0569::ENTRY, + &e0571::ENTRY, + &e0572::ENTRY, + &e0579::ENTRY, + &e0580::ENTRY, + &e0586::ENTRY, + &e0590::ENTRY, + &e0627::ENTRY, + &e0628::ENTRY, + &e0634::ENTRY, + &e0646::ENTRY, + &e0648::ENTRY, + &e0670::ENTRY, + &e0695::ENTRY, + &e0696::ENTRY, + &e0697::ENTRY, + &e0703::ENTRY, + &e0704::ENTRY, + &e0705::ENTRY, + &e0742::ENTRY, + &e0748::ENTRY, + &e0753::ENTRY, + &e0758::ENTRY, + &e0762::ENTRY, + &e0763::ENTRY, + &e0765::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/syntax/e0062.rs b/masterror-knowledge/src/errors/syntax/e0062.rs new file mode 100644 index 0000000..95933e1 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0062.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0062: duplicate field in struct initializer + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0062", + title: LocalizedText::new( + "Duplicate field in struct initializer", + "Дублирование поля в инициализаторе структуры", + "구조체 이니셜라이저에서 중복 필드" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when a struct field is specified more than once during +initialization. Each field must be assigned exactly once. + +Example: + struct Foo { x: i32 } + let f = Foo { + x: 0, + x: 0, // Error: field `x` specified twice + };", + "\ +Эта ошибка возникает, когда поле структуры указано более одного раза +при инициализации. Каждое поле должно быть присвоено ровно один раз.", + "\ +이 오류는 구조체 초기화 중 필드가 두 번 이상 지정될 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove duplicate field assignment", + "Удалить дублирующееся присваивание поля", + "중복 필드 할당 제거" + ), + code: "struct Foo { x: i32 }\nlet f = Foo { x: 0 };" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0062.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0063.rs b/masterror-knowledge/src/errors/syntax/e0063.rs new file mode 100644 index 0000000..ab5caf4 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0063.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0063: missing struct field + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0063", + title: LocalizedText::new( + "Missing struct field", + "Отсутствует поле структуры", + "구조체 필드 누락" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when a struct is instantiated without providing values for +all of its fields. Every field must be initialized. + +Example: + struct Foo { x: i32, y: i32 } + let f = Foo { x: 0 }; // Error: missing field `y`", + "\ +Эта ошибка возникает при создании экземпляра структуры без предоставления +значений для всех её полей. Каждое поле должно быть инициализировано.", + "\ +이 오류는 모든 필드에 값을 제공하지 않고 구조체를 인스턴스화할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Provide all required fields", + "Указать все обязательные поля", + "모든 필수 필드 제공" + ), + code: "struct Foo { x: i32, y: i32 }\nlet f = Foo { x: 0, y: 0 };" + }, + FixSuggestion { + description: LocalizedText::new( + "Use struct update syntax with Default", + "Использовать синтаксис обновления структуры с Default", + "Default와 구조체 업데이트 구문 사용" + ), + code: "#[derive(Default)]\nstruct Foo { x: i32, y: i32 }\nlet f = Foo { x: 0, ..Default::default() };" + } + ], + links: &[ + DocLink { + title: "Rust Book: Structs", + url: "https://doc.rust-lang.org/book/ch05-01-defining-structs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0063.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0067.rs b/masterror-knowledge/src/errors/syntax/e0067.rs new file mode 100644 index 0000000..3e35ed4 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0067.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0067: invalid left-hand side in compound assignment + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0067", + title: LocalizedText::new( + "Invalid left-hand side in compound assignment", + "Недопустимое левое значение в составном присваивании", + "복합 할당에서 잘못된 좌변" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when the left-hand side of a compound assignment operator +(+=, -=, etc.) is not a valid assignable expression. + +Example: + 12 += 1; // Error: cannot assign to literal", + "\ +Эта ошибка возникает, когда левая часть оператора составного присваивания +(+=, -= и т.д.) не является допустимым присваиваемым выражением.", + "\ +이 오류는 복합 할당 연산자의 좌변이 유효한 할당 가능 표현식이 아닐 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a mutable variable", + "Использовать изменяемую переменную", + "가변 변수 사용" + ), + code: "let mut x: i8 = 12;\nx += 1;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0067.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0081.rs b/masterror-knowledge/src/errors/syntax/e0081.rs new file mode 100644 index 0000000..684ed67 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0081.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0081: duplicate enum discriminant value + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0081", + title: LocalizedText::new( + "Duplicate enum discriminant value", + "Дублирующееся значение дискриминанта enum", + "중복된 열거형 판별자 값" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when two or more enum variants have the same discriminant +value, making it impossible to distinguish between them. + +Example: + enum Enum { + P = 3, + X = 3, // Error: duplicate discriminant value + } + +Variants without explicit values are auto-numbered starting from 0.", + "\ +Эта ошибка возникает, когда два или более варианта enum имеют одинаковое +значение дискриминанта, что делает невозможным их различение.", + "\ +이 오류는 두 개 이상의 열거형 변형이 같은 판별자 값을 가질 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use unique discriminant values", + "Использовать уникальные значения дискриминантов", + "고유한 판별자 값 사용" + ), + code: "enum Enum {\n P,\n X = 3,\n Y = 5,\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Discriminants", + url: "https://doc.rust-lang.org/reference/items/enumerations.html#discriminants" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0081.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0084.rs b/masterror-knowledge/src/errors/syntax/e0084.rs new file mode 100644 index 0000000..8711b4f --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0084.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0084: repr on zero-variant enum + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0084", + title: LocalizedText::new( + "Repr on zero-variant enum", + "Repr для enum без вариантов", + "변형이 없는 열거형에 repr" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when an integer representation attribute is applied to a +zero-variant enum. Zero-variant enums cannot be instantiated, so there's no +value to represent. + +Example: + #[repr(i32)] + enum Empty {} // Error: zero-variant enum", + "\ +Эта ошибка возникает при применении атрибута целочисленного представления +к enum без вариантов. Такие enum не могут быть инстанцированы.", + "\ +이 오류는 변형이 없는 열거형에 정수 표현 속성을 적용할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add variants to the enum", + "Добавить варианты в enum", + "열거형에 변형 추가" + ), + code: "#[repr(i32)]\nenum NotEmpty {\n First,\n Second,\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Remove the repr attribute", + "Удалить атрибут repr", + "repr 속성 제거" + ), + code: "enum Empty {}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0084.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0091.rs b/masterror-knowledge/src/errors/syntax/e0091.rs new file mode 100644 index 0000000..0b2a58b --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0091.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0091: unused type parameter in type alias + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0091", + title: LocalizedText::new( + "Unused type parameter in type alias", + "Неиспользуемый параметр типа в псевдониме типа", + "타입 별칭에서 사용되지 않은 타입 매개변수" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when a type alias declares type parameters that are never +used in the type definition. + +Example: + type Foo = u32; // Error: T is never used + type Bar = Box; // Error: B is never used", + "\ +Эта ошибка возникает, когда псевдоним типа объявляет параметры типа, +которые никогда не используются в определении типа.", + "\ +이 오류는 타입 별칭이 타입 정의에서 사용되지 않는 타입 매개변수를 선언할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove unused type parameter", + "Удалить неиспользуемый параметр типа", + "사용되지 않은 타입 매개변수 제거" + ), + code: "type Foo = u32;\ntype Bar = Box;" + }, + FixSuggestion { + description: LocalizedText::new( + "Use PhantomData if parameter is needed", + "Использовать PhantomData если параметр нужен", + "매개변수가 필요한 경우 PhantomData 사용" + ), + code: "use std::marker::PhantomData;\nstruct Foo { data: u32, _marker: PhantomData }" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0091.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0121.rs b/masterror-knowledge/src/errors/syntax/e0121.rs new file mode 100644 index 0000000..9d0905e --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0121.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0121: type placeholder _ used in item signature + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0121", + title: LocalizedText::new( + "Type placeholder _ used in item signature", + "Заполнитель типа _ использован в сигнатуре элемента", + "아이템 시그니처에 타입 플레이스홀더 _ 사용됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The type placeholder _ cannot be used within a type on an item's signature. +This applies to function return types and static variable declarations. + +The _ placeholder can be used in variable bindings where the compiler can +infer the type, but not in places where an explicit type is required.", + "\ +Заполнитель типа _ не может использоваться в типе сигнатуры элемента. +Это относится к возвращаемым типам функций и объявлениям статических переменных. + +Заполнитель _ можно использовать в привязках переменных, где компилятор +может вывести тип, но не там, где требуется явный тип.", + "\ +타입 플레이스홀더 _는 아이템 시그니처의 타입에서 사용할 수 없습니다. +이는 함수 반환 타입과 정적 변수 선언에 적용됩니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Provide the type explicitly in function signature", + "Указать тип явно в сигнатуре функции", + "함수 시그니처에 타입을 명시적으로 제공" + ), + code: "fn foo() -> i32 { 5 } // not fn foo() -> _ { 5 }" + }, + FixSuggestion { + description: LocalizedText::new( + "Provide the type explicitly for static", + "Указать тип явно для статической переменной", + "정적 변수에 타입을 명시적으로 제공" + ), + code: "static BAR: &str = \"test\"; // not static BAR: _ = \"test\"" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Type Inference", + url: "https://doc.rust-lang.org/reference/type-inference.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0121.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0124.rs b/masterror-knowledge/src/errors/syntax/e0124.rs new file mode 100644 index 0000000..9be7b4e --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0124.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0124: duplicate field name in struct + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0124", + title: LocalizedText::new( + "Duplicate field name in struct", + "Дублирующееся имя поля в структуре", + "구조체에서 중복 필드 이름" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when a struct is declared with two fields having the same +name. Each field must have a unique name. + +Example: + struct Foo { + field1: i32, + field1: i32, // Error: duplicate field name + }", + "\ +Эта ошибка возникает, когда структура объявлена с двумя полями с одинаковым +именем. Каждое поле должно иметь уникальное имя.", + "\ +이 오류는 구조체에 같은 이름의 필드가 두 개 있을 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use unique field names", + "Использовать уникальные имена полей", + "고유한 필드 이름 사용" + ), + code: "struct Foo {\n field1: i32,\n field2: i32,\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0124.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0128.rs b/masterror-knowledge/src/errors/syntax/e0128.rs new file mode 100644 index 0000000..05451df --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0128.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0128: forward declared generic parameter in default + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0128", + title: LocalizedText::new( + "Forward declared generic parameter in default", + "Опережающее объявление параметра типа в значении по умолчанию", + "기본값에서 전방 선언된 제네릭 매개변수" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +This error occurs when a type parameter's default value references another +type parameter that hasn't been declared yet. + +Example: + struct Foo { ... } // Error: U not declared yet + +Type parameters are evaluated in order, so defaults can only reference +parameters that come before them.", + "\ +Эта ошибка возникает, когда значение по умолчанию параметра типа ссылается +на другой параметр типа, который ещё не объявлен.", + "\ +이 오류는 타입 매개변수의 기본값이 아직 선언되지 않은 다른 타입 매개변수를 참조할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Reorder type parameters", + "Изменить порядок параметров типа", + "타입 매개변수 순서 변경" + ), + code: "struct Foo {\n field1: T,\n field2: U,\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0128.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0131.rs b/masterror-knowledge/src/errors/syntax/e0131.rs new file mode 100644 index 0000000..ff3c297 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0131.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0131: main function is not allowed to have generic parameters + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0131", + title: LocalizedText::new( + "main function is not allowed to have generic parameters", + "Функция main не может иметь обобщённые параметры", + "main 함수는 제네릭 매개변수를 가질 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The main function was defined with generic parameters, which is not allowed. +The main function is the entry point of a Rust program and has special +restrictions - it cannot be generic or accept any parameters.", + "\ +Функция main была определена с обобщёнными параметрами, что не разрешено. +Функция main является точкой входа программы Rust и имеет особые +ограничения - она не может быть обобщённой или принимать параметры.", + "\ +main 함수가 제네릭 매개변수로 정의되었는데, 이는 허용되지 않습니다. +main 함수는 Rust 프로그램의 진입점이며 제네릭이거나 매개변수를 +받을 수 없다는 특별한 제한이 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove generic parameters from main", + "Удалить обобщённые параметры из main", + "main에서 제네릭 매개변수 제거" + ), + code: "fn main() {\n // program entry point\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Entry Point", + url: "https://doc.rust-lang.org/reference/crates-and-source-files.html#main-functions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0131.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0133.rs b/masterror-knowledge/src/errors/syntax/e0133.rs new file mode 100644 index 0000000..d84cfa4 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0133.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0133: unsafe code outside unsafe block + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0133", + title: LocalizedText::new( + "Unsafe code outside unsafe block", + "Небезопасный код вне unsafe блока", + "unsafe 블록 외부의 unsafe 코드" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +Unsafe operations must be wrapped in an `unsafe` block. This includes: +- Dereferencing raw pointers +- Calling unsafe functions +- Calling functions via FFI + +Example: + unsafe fn f() {} + fn main() { + f(); // Error: unsafe function call outside unsafe block + }", + "\ +Небезопасные операции должны быть обёрнуты в блок `unsafe`. Это включает: +- Разыменование сырых указателей +- Вызов unsafe функций +- Вызов функций через FFI", + "\ +안전하지 않은 작업은 `unsafe` 블록으로 감싸야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Wrap in unsafe block", + "Обернуть в unsafe блок", + "unsafe 블록으로 감싸기" + ), + code: "unsafe fn f() {}\n\nfn main() {\n unsafe { f(); }\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Unsafe Rust", + url: "https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0133.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0152.rs b/masterror-knowledge/src/errors/syntax/e0152.rs new file mode 100644 index 0000000..feebdff --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0152.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0152: a lang item was redefined + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0152", + title: LocalizedText::new( + "A lang item was redefined", + "Языковой элемент был переопределён", + "lang 아이템이 재정의됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A lang item was redefined. Lang items are special items in Rust that are +already implemented in the standard library. They provide core functionality +for the language itself. + +Unless you are writing a free-standing application (such as a kernel or +embedded system), you should not provide your own implementations of lang items.", + "\ +Языковой элемент был переопределён. Языковые элементы - это специальные +элементы в Rust, которые уже реализованы в стандартной библиотеке. +Они обеспечивают базовую функциональность языка. + +Если вы не пишете автономное приложение (ядро или встраиваемую систему), +не следует предоставлять собственные реализации языковых элементов.", + "\ +lang 아이템이 재정의되었습니다. lang 아이템은 표준 라이브러리에 이미 +구현된 Rust의 특별한 아이템입니다. 언어 자체의 핵심 기능을 제공합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use #![no_std] for freestanding applications", + "Использовать #![no_std] для автономных приложений", + "독립 실행형 애플리케이션에 #![no_std] 사용" + ), + code: "#![no_std]\n// Now you can define lang items" + }], + links: &[ + DocLink { + title: "Rustonomicon: Lang Items", + url: "https://doc.rust-lang.org/nomicon/beneath-std.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0152.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0178.rs b/masterror-knowledge/src/errors/syntax/e0178.rs new file mode 100644 index 0000000..ba285c3 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0178.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0178: the + type operator was used in an ambiguous context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0178", + title: LocalizedText::new( + "The + type operator was used in an ambiguous context", + "Оператор типа + использован в неоднозначном контексте", + "타입 연산자 +가 모호한 컨텍스트에서 사용됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The + type operator was used without proper parentheses in type annotations. +Since the + operator has low precedence in type contexts, it can create +ambiguity about what the type bounds apply to.", + "\ +Оператор типа + использован без надлежащих скобок в аннотациях типов. +Поскольку оператор + имеет низкий приоритет в контексте типов, это может +создать неоднозначность относительно того, к чему применяются ограничения.", + "\ +타입 주석에서 + 타입 연산자가 적절한 괄호 없이 사용되었습니다. ++ 연산자는 타입 컨텍스트에서 우선순위가 낮기 때문에 타입 바운드가 +무엇에 적용되는지 모호성을 만들 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Wrap trait bounds in parentheses", + "Обернуть ограничения трейтов в скобки", + "트레이트 바운드를 괄호로 감싸기" + ), + code: "trait Foo {}\n\nstruct Bar<'a> {\n x: &'a (dyn Foo + 'a), // ok!\n y: &'a mut (dyn Foo + 'a), // ok!\n z: fn() -> (dyn Foo + 'a), // ok!\n}" + }], + links: &[ + DocLink { + title: "RFC 438: Parentheses in Trait Bounds", + url: "https://github.com/rust-lang/rfcs/pull/438" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0178.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0229.rs b/masterror-knowledge/src/errors/syntax/e0229.rs new file mode 100644 index 0000000..dc106ec --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0229.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0229: associated item constraint in unexpected context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0229", + title: LocalizedText::new( + "Associated item constraint in unexpected context", + "Ограничение ассоциированного элемента в неожиданном контексте", + "예상치 못한 컨텍스트에서 연관 항목 제약" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +An associated item constraint was written in an unexpected context. +Associated type constraints (like `A = Bar`) cannot be used directly +in trait object or cast syntax. + +They must be placed in the appropriate location: either in the type +parameter bounds or the `where` clause.", + "\ +Ограничение ассоциированного элемента было написано в неожиданном контексте. +Ограничения ассоциированных типов (вроде `A = Bar`) нельзя использовать +напрямую в синтаксисе трейт-объектов или приведения типов. + +Они должны быть размещены в параметрах типа или в `where` clause.", + "\ +연관 항목 제약이 예상치 못한 컨텍스트에서 작성되었습니다. +연관 타입 제약은 타입 매개변수 바운드나 where 절에 배치해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Move constraints to type parameter bounds", + "Переместите ограничения в параметры типа", + "제약을 타입 매개변수 바운드로 이동" + ), + code: "fn baz>(x: &::A) {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Move constraints to where clause", + "Переместите ограничения в where clause", + "제약을 where 절로 이동" + ), + code: "fn baz(x: &::A) where I: Foo {}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Trait Bounds", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#trait-bound-syntax" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0229.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0230.rs b/masterror-knowledge/src/errors/syntax/e0230.rs new file mode 100644 index 0000000..62ef28f --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0230.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0230: invalid identifier in rustc_on_unimplemented + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0230", + title: LocalizedText::new( + "Invalid identifier in #[rustc_on_unimplemented]", + "Недопустимый идентификатор в #[rustc_on_unimplemented]", + "#[rustc_on_unimplemented]에서 잘못된 식별자" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +The `#[rustc_on_unimplemented]` attribute contains an identifier in +curly braces that doesn't match any of the following: +- The trait's type parameters +- The string `Self` + +Placeholders in curly braces must be valid - either existing type +parameters or the special `Self` keyword.", + "\ +Атрибут `#[rustc_on_unimplemented]` содержит идентификатор в фигурных +скобках, который не соответствует ни одному из параметров типа трейта +или строке `Self`.", + "\ +`#[rustc_on_unimplemented]` 속성에 중괄호 안의 식별자가 +트레이트의 타입 매개변수나 `Self`와 일치하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use correct type parameter name or Self", + "Используйте правильное имя параметра типа или Self", + "올바른 타입 매개변수 이름 또는 Self 사용" + ), + code: "#[rustc_on_unimplemented = \"error on `{Self}` with param `<{A}>`\"]\ntrait MyTrait {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Escape literal braces with double braces", + "Экранируйте литеральные скобки двойными скобками", + "이중 중괄호로 리터럴 중괄호 이스케이프" + ), + code: "#[rustc_on_unimplemented = \"use {{braces}} literally\"]" + } + ], + links: &[ + DocLink { + title: "Rust Internals: Custom Error Messages", + url: "https://doc.rust-lang.org/unstable-book/language-features/rustc-attrs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0230.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0231.rs b/masterror-knowledge/src/errors/syntax/e0231.rs new file mode 100644 index 0000000..5e9f4e8 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0231.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0231: invalid format string in rustc_on_unimplemented + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0231", + title: LocalizedText::new( + "Invalid format string in #[rustc_on_unimplemented]", + "Недопустимая строка формата в #[rustc_on_unimplemented]", + "#[rustc_on_unimplemented]에서 잘못된 형식 문자열" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +The `#[rustc_on_unimplemented]` attribute has an invalid format string. +Curly braces in the attribute must contain a valid identifier (either +a type parameter name or `{Self}`), not empty braces. + +The format string supports: +- Type parameters: Referenced by name in curly braces (e.g., `{A}`) +- `{Self}`: Refers to the type that failed to implement the trait +- Standard Rust string formatting rules", + "\ +Атрибут `#[rustc_on_unimplemented]` имеет недопустимую строку формата. +Фигурные скобки должны содержать допустимый идентификатор, +а не пустые скобки.", + "\ +`#[rustc_on_unimplemented]` 속성에 잘못된 형식 문자열이 있습니다. +중괄호에는 유효한 식별자가 포함되어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use valid identifier in braces", + "Используйте допустимый идентификатор в скобках", + "중괄호에 유효한 식별자 사용" + ), + code: "#[rustc_on_unimplemented = \"error on `{Self}` with params `<{A}>`\"]\ntrait MyTrait {}" + }], + links: &[ + DocLink { + title: "Rust Internals: Custom Error Messages", + url: "https://doc.rust-lang.org/unstable-book/language-features/rustc-attrs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0231.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0232.rs b/masterror-knowledge/src/errors/syntax/e0232.rs new file mode 100644 index 0000000..0ccd33e --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0232.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0232: invalid rustc_on_unimplemented attribute + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0232", + title: LocalizedText::new( + "Invalid #[rustc_on_unimplemented] attribute", + "Недопустимый атрибут #[rustc_on_unimplemented]", + "잘못된 #[rustc_on_unimplemented] 속성" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +The `#[rustc_on_unimplemented]` attribute is used incorrectly on a trait. +This attribute is used to specify a custom error message when a trait +is not implemented on a type that requires it. + +The attribute requires a note to be specified. An empty attribute or +one without meaningful content will trigger this error.", + "\ +Атрибут `#[rustc_on_unimplemented]` использован неправильно. +Этот атрибут используется для указания пользовательского сообщения об ошибке. + +Атрибут требует указания примечания. Пустой атрибут вызовет эту ошибку.", + "\ +`#[rustc_on_unimplemented]` 속성이 잘못 사용되었습니다. +이 속성은 트레이트가 구현되지 않았을 때 사용자 정의 오류 메시지를 지정합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add helpful note or remove attribute", + "Добавьте полезное примечание или удалите атрибут", + "유용한 노트 추가 또는 속성 제거" + ), + code: "#[rustc_on_unimplemented(message = \"Custom message for {Self}\")]\ntrait MyTrait {}" + }], + links: &[ + DocLink { + title: "Rust Internals: Custom Error Messages", + url: "https://doc.rust-lang.org/unstable-book/language-features/rustc-attrs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0232.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0264.rs b/masterror-knowledge/src/errors/syntax/e0264.rs new file mode 100644 index 0000000..1e2963f --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0264.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0264: unknown external lang item + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0264", + title: LocalizedText::new( + "Unknown external lang item", + "Неизвестный внешний элемент языка", + "알 수 없는 외부 lang 항목" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +An unknown external lang item was used. + +The Rust compiler has a predefined set of valid external language items +that can be declared with the `#[lang]` attribute. If you try to use +a lang item name that doesn't exist in this set, the compiler will +reject it. + +The complete list of available external lang items can be found in +`compiler/rustc_hir/src/weak_lang_items.rs` in the Rust source code.", + "\ +Использован неизвестный внешний элемент языка. + +Компилятор Rust имеет предопределённый набор допустимых внешних +элементов языка, которые можно объявить с атрибутом `#[lang]`.", + "\ +알 수 없는 외부 lang 항목이 사용되었습니다. +`#[lang]` 속성으로 선언할 수 있는 유효한 항목만 사용해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use valid external lang item", + "Используйте допустимый внешний элемент языка", + "유효한 외부 lang 항목 사용" + ), + code: "#[lang = \"panic_impl\"] // valid lang item\nfn panic() {}" + }], + links: &[ + DocLink { + title: "Rust Internals: Lang Items", + url: "https://doc.rust-lang.org/unstable-book/language-features/lang-items.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0264.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0267.rs b/masterror-knowledge/src/errors/syntax/e0267.rs new file mode 100644 index 0000000..49869e2 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0267.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0267: break or continue inside closure but outside loop + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0267", + title: LocalizedText::new( + "Loop keyword used inside closure but outside loop", + "Ключевое слово цикла использовано внутри замыкания, но вне цикла", + "클로저 내부에서 루프 외부에 루프 키워드 사용" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A loop keyword (`break` or `continue`) was used inside a closure but +outside of any loop. + +Loop control keywords are designed to control loop flow. Using them +in a closure without an enclosing loop has no valid target to break +from or continue to, making it a syntax error.", + "\ +Ключевое слово цикла (`break` или `continue`) было использовано внутри +замыкания, но вне какого-либо цикла. + +Ключевые слова управления циклом предназначены для управления потоком +цикла. Использование их в замыкании без охватывающего цикла является +синтаксической ошибкой.", + "\ +루프 키워드(`break` 또는 `continue`)가 클로저 내부에서 루프 외부에 사용되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use break/continue inside a loop in the closure", + "Используйте break/continue внутри цикла в замыкании", + "클로저 내 루프 안에서 break/continue 사용" + ), + code: "let w = || {\n for _ in 0..10 {\n break; // valid - inside loop\n }\n};" + }, + FixSuggestion { + description: LocalizedText::new( + "Use return to exit closure early", + "Используйте return для раннего выхода из замыкания", + "클로저를 일찍 종료하려면 return 사용" + ), + code: "let w = || {\n return; // halts closure execution\n};" + } + ], + links: &[ + DocLink { + title: "Rust Book: Loops", + url: "https://doc.rust-lang.org/book/ch03-05-control-flow.html#repetition-with-loops" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0267.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0268.rs b/masterror-knowledge/src/errors/syntax/e0268.rs new file mode 100644 index 0000000..16351da --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0268.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0268: break or continue outside of a loop + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0268", + title: LocalizedText::new( + "Loop keyword outside of a loop", + "Ключевое слово цикла вне цикла", + "루프 외부에서 루프 키워드 사용" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A loop control keyword (`break` or `continue`) was used outside of a +loop context. + +The `break` and `continue` keywords are only valid inside loop +constructs (such as `for`, `while`, or `loop`). Using them outside +a loop has no sensible meaning, so Rust rejects this code.", + "\ +Ключевое слово управления циклом (`break` или `continue`) было использовано +вне контекста цикла. + +Ключевые слова `break` и `continue` допустимы только внутри конструкций +цикла (таких как `for`, `while` или `loop`).", + "\ +루프 제어 키워드(`break` 또는 `continue`)가 루프 컨텍스트 외부에서 사용되었습니다. +이 키워드들은 루프 구조 내에서만 유효합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use break/continue inside a loop", + "Используйте break/continue внутри цикла", + "루프 내에서 break/continue 사용" + ), + code: "fn some_func() {\n for _ in 0..10 {\n break; // valid inside loop\n }\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Loops", + url: "https://doc.rust-lang.org/book/ch03-05-control-flow.html#repetition-with-loops" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0268.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0297.rs b/masterror-knowledge/src/errors/syntax/e0297.rs new file mode 100644 index 0000000..e73267d --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0297.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0297: refutable pattern in for loop + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0297", + title: LocalizedText::new( + "Refutable pattern in for loop", + "Опровержимый паттерн в цикле for", + "for 루프에서 반박 가능한 패턴" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +Patterns used to bind names in loops are refutable (don't guarantee +a match in all cases). Patterns in loops must be irrefutable, meaning +they must successfully extract a name in every iteration. + +For example, `for Some(x) in xs` is refutable because it only matches +`Some` variants but not `None`. When the loop encounters `None`, the +pattern fails to bind anything. + +Note: This error code is no longer emitted by the compiler.", + "\ +Паттерны, используемые для связывания имён в циклах, являются опровержимыми +(не гарантируют совпадение во всех случаях). Паттерны в циклах должны +быть неопровержимыми. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +루프에서 이름을 바인딩하는 데 사용된 패턴이 반박 가능합니다. +루프의 패턴은 반박 불가능해야 합니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use if let inside the loop", + "Используйте if let внутри цикла", + "루프 내에서 if let 사용" + ), + code: "for item in xs {\n if let Some(x) = item {\n // use x\n }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use match inside the loop", + "Используйте match внутри цикла", + "루프 내에서 match 사용" + ), + code: "for item in xs {\n match item {\n Some(x) => {},\n None => {},\n }\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Refutability", + url: "https://doc.rust-lang.org/book/ch18-02-refutability.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0297.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0408.rs b/masterror-knowledge/src/errors/syntax/e0408.rs new file mode 100644 index 0000000..a5b20b4 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0408.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0408: variable not bound in all patterns + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0408", + title: LocalizedText::new( + "Variable not bound in all patterns of or-pattern", + "Переменная не связана во всех вариантах или-паттерна", + "or 패턴의 모든 분기에서 변수가 바인딩되지 않음" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +When using an or-pattern (|) in a match expression, any variables bound in one +branch must also be bound in all other branches. If a variable exists in some +patterns but not others, the compiler cannot guarantee it will have a value +in the match arm body.", + "\ +При использовании или-паттерна (|) в выражении match любые переменные, +связанные в одной ветви, должны быть связаны и во всех остальных. +Если переменная существует в одних паттернах, но не в других, компилятор +не может гарантировать, что она будет иметь значение.", + "\ +match 표현식에서 or 패턴(|)을 사용할 때, 한 분기에서 바인딩된 변수는 +다른 모든 분기에서도 바인딩되어야 합니다. 변수가 일부 패턴에만 +존재하면 컴파일러가 값의 존재를 보장할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Split into separate match arms", + "Разделить на отдельные ветви match", + "별도의 match 분기로 분리" + ), + code: "match x {\n Some(y) => { /* use y */ }\n None => { /* ... */ }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Bind variables consistently in all patterns", + "Связать переменные одинаково во всех паттернах", + "모든 패턴에서 일관되게 변수 바인딩" + ), + code: "match x {\n (0, y) | (y, 0) => { /* y bound in both */ }\n _ => {}\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0408.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0409.rs b/masterror-knowledge/src/errors/syntax/e0409.rs new file mode 100644 index 0000000..d7d9322 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0409.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0409: inconsistent binding modes in or-pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0409", + title: LocalizedText::new( + "Inconsistent binding modes in or-pattern", + "Несовместимые режимы связывания в или-паттерне", + "or 패턴에서 일관되지 않은 바인딩 모드" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +In an or-pattern, a variable cannot be bound by-value in one pattern and +by-reference in another. All bindings of the same variable must use the +same binding mode (ref, ref mut, or by-value).", + "\ +В или-паттерне переменная не может быть связана по значению в одном +паттерне и по ссылке в другом. Все связывания одной переменной должны +использовать один режим (ref, ref mut или по значению).", + "\ +or 패턴에서 변수는 한 패턴에서는 값으로, 다른 패턴에서는 참조로 +바인딩될 수 없습니다. 같은 변수의 모든 바인딩은 동일한 바인딩 모드를 +사용해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use consistent binding modes", + "Использовать одинаковый режим связывания", + "일관된 바인딩 모드 사용" + ), + code: "match x {\n (0, ref y) | (ref y, 0) => { /* both ref */ }\n _ => ()\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Split into separate patterns", + "Разделить на отдельные паттерны", + "별도의 패턴으로 분리" + ), + code: "match x {\n (y, 0) => { /* by value */ }\n (0, ref y) => { /* by ref */ }\n _ => ()\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0409.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0415.rs b/masterror-knowledge/src/errors/syntax/e0415.rs new file mode 100644 index 0000000..d919128 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0415.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0415: duplicate function parameter name + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0415", + title: LocalizedText::new( + "More than one function parameter have the same name", + "Несколько параметров функции имеют одинаковое имя", + "여러 함수 매개변수가 같은 이름을 가짐" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A function was declared with multiple parameters that share the same +identifier name. Rust does not allow duplicate parameter names in +a function signature - each parameter must have a unique name.", + "\ +Функция объявлена с несколькими параметрами, имеющими одинаковое имя. +Rust не допускает дублирование имён параметров в сигнатуре функции - +каждый параметр должен иметь уникальное имя.", + "\ +함수가 같은 이름을 가진 여러 매개변수로 선언되었습니다. Rust는 +함수 시그니처에서 매개변수 이름 중복을 허용하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Rename parameters to be unique", + "Переименовать параметры, чтобы они были уникальны", + "매개변수 이름을 고유하게 변경" + ), + code: "fn foo(f: i32, g: i32) {} // Different names" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0415.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0416.rs b/masterror-knowledge/src/errors/syntax/e0416.rs new file mode 100644 index 0000000..217766a --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0416.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0416: identifier bound more than once in pattern + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0416", + title: LocalizedText::new( + "Identifier bound more than once in the same pattern", + "Идентификатор связан более одного раза в паттерне", + "같은 패턴에서 식별자가 두 번 이상 바인딩됨" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +The same identifier was used more than once in a single pattern. Each variable +name can only be bound once within the same pattern. Using the same identifier +multiple times creates ambiguity.", + "\ +Один и тот же идентификатор использован более одного раза в одном паттерне. +Каждое имя переменной может быть связано только один раз в пределах одного +паттерна.", + "\ +같은 패턴에서 동일한 식별자가 두 번 이상 사용되었습니다. 각 변수 이름은 +같은 패턴 내에서 한 번만 바인딩될 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use different variable names", + "Использовать разные имена переменных", + "다른 변수 이름 사용" + ), + code: "match (1, 2) {\n (x, y) => {} // Different names\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use guards to compare values", + "Использовать охранные выражения для сравнения", + "값 비교를 위해 가드 사용" + ), + code: "match (a, b) {\n (x, y) if x == y => { /* equal */ }\n (x, y) => { /* not equal */ }\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0416.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0519.rs b/masterror-knowledge/src/errors/syntax/e0519.rs new file mode 100644 index 0000000..e0f7eaa --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0519.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0519: current crate indistinguishable from dependency + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0519", + title: LocalizedText::new( + "Current crate indistinguishable from dependency", + "Текущий крейт неотличим от зависимости", + "현재 크레이트가 의존성과 구별 불가" + ), + category: Category::Resolution, + explanation: LocalizedText::new( + "\ +The current crate is indistinguishable from one of its dependencies. This +error occurs when the current crate has the same `crate-name` and metadata +as one of its dependencies. + +This creates ambiguity because the compiler cannot distinguish between symbols +(public item names) from the two crates, potentially causing symbol conflicts.", + "\ +Текущий крейт неотличим от одной из его зависимостей. Эта ошибка возникает, +когда текущий крейт имеет то же имя и метаданные, что и одна из его +зависимостей. + +Это создаёт неоднозначность, поскольку компилятор не может различить символы +из двух крейтов.", + "\ +현재 크레이트가 의존성 중 하나와 구별할 수 없습니다. 이 오류는 현재 크레이트가 +의존성 중 하나와 동일한 `crate-name` 및 메타데이터를 가질 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use Cargo to manage crate naming", + "Использовать Cargo для управления именами крейтов", + "크레이트 이름 지정에 Cargo 사용" + ), + code: "// Use Cargo.toml to manage dependencies\n// It handles crate naming automatically" + }, + FixSuggestion { + description: LocalizedText::new( + "Change the crate name to be unique", + "Изменить имя крейта на уникальное", + "크레이트 이름을 고유하게 변경" + ), + code: "#![crate_name = \"my_unique_crate\"]" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0519.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0569.rs b/masterror-knowledge/src/errors/syntax/e0569.rs new file mode 100644 index 0000000..d1a5081 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0569.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0569: may_dangle requires unsafe impl + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0569", + title: LocalizedText::new( + "`#[may_dangle]` requires `unsafe impl`", + "`#[may_dangle]` требует `unsafe impl`", + "`#[may_dangle]`는 `unsafe impl` 필요" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +If an impl has a generic parameter with the `#[may_dangle]` attribute, then +that impl must be declared as an `unsafe impl`. + +The `#[may_dangle]` attribute is used to assert that a destructor will not +access any data of a generic type parameter. Since the compiler does not +verify this assertion, the impl must be explicitly marked as `unsafe` to +indicate that the programmer takes responsibility for the safety.", + "\ +Если реализация имеет обобщённый параметр с атрибутом `#[may_dangle]`, то +эта реализация должна быть объявлена как `unsafe impl`. + +Атрибут `#[may_dangle]` утверждает, что деструктор не будет обращаться +к данным обобщённого типа. Поскольку компилятор не проверяет это, +реализация должна быть помечена как `unsafe`.", + "\ +impl에 `#[may_dangle]` 속성이 있는 제네릭 매개변수가 있으면 해당 impl은 +`unsafe impl`로 선언되어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Mark the impl as unsafe", + "Пометить impl как unsafe", + "impl을 unsafe로 표시" + ), + code: "#![feature(dropck_eyepatch)]\n\nstruct Foo(X);\nunsafe impl<#[may_dangle] X> Drop for Foo {\n fn drop(&mut self) { }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0569.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0571.rs b/masterror-knowledge/src/errors/syntax/e0571.rs new file mode 100644 index 0000000..38ceca5 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0571.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0571: break with value in non-loop + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0571", + title: LocalizedText::new( + "`break` with value from non-`loop` loop", + "`break` со значением в не-`loop` цикле", + "비`loop` 루프에서 값이 있는 `break`" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A `break` statement with an argument appeared in a non-`loop` loop. The +`break` statement can only take an argument (a value to return from the loop) +when used inside `loop` loops. + +It cannot be used with a value in `for`, `while`, or `while let` loops.", + "\ +Оператор `break` с аргументом появился в цикле, отличном от `loop`. +Оператор `break` может принимать аргумент (значение для возврата из цикла) +только внутри циклов `loop`. + +Его нельзя использовать со значением в циклах `for`, `while` или `while let`.", + "\ +`loop`가 아닌 루프에서 인수가 있는 `break` 문이 나타났습니다. `break` 문은 +`loop` 루프 내에서만 인수(루프에서 반환할 값)를 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Change while to loop", + "Изменить while на loop", + "while를 loop로 변경" + ), + code: "let result = loop {\n if satisfied(i) {\n break 2 * i; // ok in loop\n }\n i += 1;\n};" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0571.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0572.rs b/masterror-knowledge/src/errors/syntax/e0572.rs new file mode 100644 index 0000000..136cd3c --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0572.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0572: return statement outside of function body + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0572", + title: LocalizedText::new( + "Return statement outside of function body", + "Оператор return вне тела функции", + "함수 본문 외부의 return 문" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A `return` statement was found in a context where it is not allowed. The +`return` keyword can only be used inside function bodies, not in other +contexts like constant declarations or module-level code.", + "\ +Оператор `return` был найден в контексте, где он не разрешён. Ключевое +слово `return` можно использовать только внутри тел функций, но не в +других контекстах, таких как объявления констант или код на уровне модуля.", + "\ +`return` 문이 허용되지 않는 컨텍스트에서 발견되었습니다. `return` 키워드는 +상수 선언이나 모듈 수준 코드와 같은 다른 컨텍스트가 아닌 함수 본문 내에서만 +사용할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove return from const declaration", + "Удалить return из объявления const", + "const 선언에서 return 제거" + ), + code: "const FOO: u32 = 0; // not: const FOO: u32 = return 0;" + }, + FixSuggestion { + description: LocalizedText::new( + "Move return into a function", + "Переместить return в функцию", + "return을 함수로 이동" + ), + code: "fn some_fn() -> u32 {\n return FOO;\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0572.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0579.rs b/masterror-knowledge/src/errors/syntax/e0579.rs new file mode 100644 index 0000000..ee4e30f --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0579.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0579: lower range not less than upper range + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0579", + title: LocalizedText::new( + "Lower range wasn't less than upper range", + "Нижняя граница диапазона не меньше верхней", + "하한이 상한보다 작지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A lower range wasn't less than the upper range. When matching against an +exclusive range pattern, the compiler verifies that the range is non-empty. + +Exclusive range patterns include the start point but exclude the end point, +which means the start of the range must be strictly less than the end. + +For example, `5..5` is an empty range because 5 is not less than 5.", + "\ +Нижняя граница диапазона не была меньше верхней. При сопоставлении с +исключающим диапазоном компилятор проверяет, что диапазон не пуст. + +Исключающие диапазоны включают начальную точку, но исключают конечную, +поэтому начало должно быть строго меньше конца.", + "\ +하한이 상한보다 작지 않았습니다. 배타적 범위 패턴과 매칭할 때 컴파일러는 +범위가 비어 있지 않은지 확인합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Ensure range start is less than end", + "Убедиться, что начало диапазона меньше конца", + "범위 시작이 끝보다 작은지 확인" + ), + code: "match 5u32 {\n 1..2 => {}\n 5..6 => {} // valid: 5 < 6\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0579.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0580.rs b/masterror-knowledge/src/errors/syntax/e0580.rs new file mode 100644 index 0000000..6386c17 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0580.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0580: main function has wrong type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0580", + title: LocalizedText::new( + "The `main` function has wrong type", + "Функция `main` имеет неправильный тип", + "`main` 함수의 타입이 잘못됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `main` function was incorrectly declared. The `main` function is Rust's +entry point and must have a specific signature. It should not accept any +parameters directly. + +To get command-line arguments, use `std::env::args`. To exit with a specific +code, use `std::process::exit`.", + "\ +Функция `main` была неправильно объявлена. Функция `main` - это точка входа +Rust и должна иметь определённую сигнатуру. Она не должна принимать параметры +напрямую. + +Для получения аргументов командной строки используйте `std::env::args`.", + "\ +`main` 함수가 잘못 선언되었습니다. `main` 함수는 Rust의 진입점이며 +특정 시그니처를 가져야 합니다. 매개변수를 직접 받아서는 안 됩니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use correct main signature", + "Использовать правильную сигнатуру main", + "올바른 main 시그니처 사용" + ), + code: "fn main() {\n // your code\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use std::env::args for command-line arguments", + "Использовать std::env::args для аргументов командной строки", + "명령줄 인수에 std::env::args 사용" + ), + code: "use std::env;\n\nfn main() {\n for arg in env::args() {\n println!(\"{}\", arg);\n }\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0580.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0586.rs b/masterror-knowledge/src/errors/syntax/e0586.rs new file mode 100644 index 0000000..1b60296 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0586.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0586: inclusive range with no end + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0586", + title: LocalizedText::new( + "Inclusive range with no end", + "Включающий диапазон без конца", + "끝이 없는 포함 범위" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An inclusive range was used with no end. An inclusive range (using `..=`) +requires both a start and an end value. The `..=` syntax is specifically +designed to include the end value in the range. + +If you need a range without a specified end, you must use a non-inclusive +range with `..` instead.", + "\ +Был использован включающий диапазон без конца. Включающий диапазон (с `..=`) +требует как начального, так и конечного значения. Синтаксис `..=` специально +предназначен для включения конечного значения в диапазон. + +Если вам нужен диапазон без указанного конца, используйте `..`.", + "\ +끝이 없는 포함 범위가 사용되었습니다. 포함 범위(`..=` 사용)는 시작과 끝 값이 +모두 필요합니다. `..=` 구문은 특별히 범위에 끝 값을 포함하도록 설계되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use non-inclusive range for open-ended", + "Использовать невключающий диапазон для открытого конца", + "열린 끝에 비포함 범위 사용" + ), + code: "let x = &tmp[1..]; // not &tmp[1..=]" + }, + FixSuggestion { + description: LocalizedText::new( + "Provide an end value for inclusive range", + "Указать конечное значение для включающего диапазона", + "포함 범위에 끝 값 제공" + ), + code: "let x = &tmp[1..=3]; // include index 3" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0586.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0590.rs b/masterror-knowledge/src/errors/syntax/e0590.rs new file mode 100644 index 0000000..e16a9b3 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0590.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0590: break/continue in while condition without label + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0590", + title: LocalizedText::new( + "`break`/`continue` in while condition without label", + "`break`/`continue` в условии while без метки", + "레이블 없이 while 조건에서 `break`/`continue`" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +`break` or `continue` keywords were used in a condition of a `while` loop +without a label. When using these keywords inside the condition of a while +loop, you must provide a label to specify which loop is being targeted. + +Using `break` or `continue` without a label in a while condition is ambiguous.", + "\ +Ключевые слова `break` или `continue` были использованы в условии цикла +`while` без метки. При использовании этих ключевых слов внутри условия +цикла while необходимо указать метку, чтобы определить целевой цикл.", + "\ +`break` 또는 `continue` 키워드가 레이블 없이 `while` 루프의 조건에서 +사용되었습니다. while 루프의 조건 내에서 이러한 키워드를 사용할 때 +대상 루프를 지정하는 레이블을 제공해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add a label to the while loop", + "Добавить метку к циклу while", + "while 루프에 레이블 추가" + ), + code: "'foo: while break 'foo {}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0590.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0627.rs b/masterror-knowledge/src/errors/syntax/e0627.rs new file mode 100644 index 0000000..c2d9ba6 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0627.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0627: yield outside coroutine + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0627", + title: LocalizedText::new( + "Yield expression used outside coroutine literal", + "Выражение yield использовано вне литерала сопрограммы", + "yield 표현식이 코루틴 리터럴 외부에서 사용됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A yield expression was used outside of the coroutine literal. The `yield` +keyword is exclusively meant for use within coroutine literals and cannot +be used in regular functions. + +The `yield` keyword allows coroutines to suspend execution and produce +intermediate values.", + "\ +Выражение yield было использовано вне литерала сопрограммы. Ключевое слово +`yield` предназначено исключительно для использования внутри литералов +сопрограмм и не может использоваться в обычных функциях. + +Ключевое слово `yield` позволяет сопрограммам приостанавливать выполнение +и производить промежуточные значения.", + "\ +yield 표현식이 코루틴 리터럴 외부에서 사용되었습니다. `yield` 키워드는 +코루틴 리터럴 내에서만 사용할 수 있으며 일반 함수에서는 사용할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Wrap yield in coroutine literal", + "Обернуть yield в литерал сопрограммы", + "yield를 코루틴 리터럴로 감싸기" + ), + code: "let mut coroutine = #[coroutine] || {\n yield 1;\n return \"foo\"\n};" + }], + links: &[ + DocLink { + title: "Coroutines", + url: "https://doc.rust-lang.org/std/ops/trait.Coroutine.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0627.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0628.rs b/masterror-knowledge/src/errors/syntax/e0628.rs new file mode 100644 index 0000000..42cfb57 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0628.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0628: too many parameters for coroutine + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0628", + title: LocalizedText::new( + "More than one parameter used for coroutine", + "Более одного параметра использовано для сопрограммы", + "코루틴에 둘 이상의 매개변수 사용됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +More than one parameter was used for a coroutine. Rust coroutines are +restricted to accepting either 0 or 1 parameter. + +If you need multiple values, consider using a tuple or struct as a single +parameter.", + "\ +Для сопрограммы было использовано более одного параметра. Сопрограммы Rust +ограничены приёмом 0 или 1 параметра. + +Если вам нужно несколько значений, рассмотрите использование кортежа или +структуры в качестве единственного параметра.", + "\ +코루틴에 둘 이상의 매개변수가 사용되었습니다. Rust 코루틴은 0개 또는 +1개의 매개변수만 받을 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use at most one parameter", + "Использовать не более одного параметра", + "최대 하나의 매개변수 사용" + ), + code: "let coroutine = #[coroutine] |a: i32| {\n yield a;\n};" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a tuple for multiple values", + "Использовать кортеж для нескольких значений", + "여러 값에 튜플 사용" + ), + code: "let coroutine = #[coroutine] |params: (i32, i32)| {\n let (a, b) = params;\n yield a + b;\n};" + } + ], + links: &[ + DocLink { + title: "Coroutines", + url: "https://doc.rust-lang.org/std/ops/trait.Coroutine.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0628.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0634.rs b/masterror-knowledge/src/errors/syntax/e0634.rs new file mode 100644 index 0000000..52a7716 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0634.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0634: conflicting packed representation hints + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0634", + title: LocalizedText::new( + "Conflicting packed representation hints", + "Конфликтующие подсказки packed-представления", + "충돌하는 packed 표현 힌트" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type has conflicting `packed` representation hints. You cannot mix +different `packed` directives on a single struct or type definition. + +Both `packed` (default packing) and `packed(N)` (N-byte packing) cannot +be used together on the same type.", + "\ +Тип имеет конфликтующие подсказки `packed`-представления. Вы не можете +смешивать разные директивы `packed` в одном определении структуры или типа. + +Оба варианта `packed` (упаковка по умолчанию) и `packed(N)` (N-байтовая +упаковка) не могут использоваться вместе для одного типа.", + "\ +타입에 충돌하는 `packed` 표현 힌트가 있습니다. 하나의 구조체나 타입 +정의에서 다른 `packed` 지시문을 혼합할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Choose one packed representation", + "Выбрать одно packed-представление", + "하나의 packed 표현 선택" + ), + code: "#[repr(packed)] // or #[repr(packed(2))]\nstruct Company(i32);" + }], + links: &[ + DocLink { + title: "Type Layout", + url: "https://doc.rust-lang.org/reference/type-layout.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0634.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0646.rs b/masterror-knowledge/src/errors/syntax/e0646.rs new file mode 100644 index 0000000..8acca56 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0646.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0646: main function with where clause + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0646", + title: LocalizedText::new( + "Main function cannot have where clause", + "Функция main не может иметь where-предложение", + "main 함수에는 where 절을 사용할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `main` function is not allowed to have a `where` clause. The Rust +compiler does not permit `where` clauses on the `main` function due to +its special role as the entry point of a program.", + "\ +Функция `main` не может иметь `where`-предложение. Компилятор Rust не +допускает `where`-предложения для функции `main` из-за её особой роли +как точки входа программы.", + "\ +`main` 함수에는 `where` 절을 사용할 수 없습니다. Rust 컴파일러는 +프로그램의 진입점으로서의 특별한 역할 때문에 `main` 함수에 +`where` 절을 허용하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove where clause from main", + "Удалить where-предложение из main", + "main에서 where 절 제거" + ), + code: "fn main() {\n // your code here\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Move generic constraints to helper function", + "Переместить обобщённые ограничения в вспомогательную функцию", + "제네릭 제약 조건을 헬퍼 함수로 이동" + ), + code: "fn helper() { /* ... */ }\n\nfn main() {\n helper();\n}" + } + ], + links: &[ + DocLink { + title: "main Function", + url: "https://doc.rust-lang.org/reference/items/functions.html#main-functions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0646.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0648.rs b/masterror-knowledge/src/errors/syntax/e0648.rs new file mode 100644 index 0000000..259dd96 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0648.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0648: export_name with null character + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0648", + title: LocalizedText::new( + "export_name contains null characters", + "export_name содержит нулевые символы", + "export_name에 null 문자가 포함됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An `export_name` attribute was applied to a function with a null character +(`\\0`) in the export name string. + +The Rust compiler does not permit null bytes in export name strings, as +they are invalid in C symbol names and would cause issues with external +linkage.", + "\ +Атрибут `export_name` был применён к функции с нулевым символом (`\\0`) +в строке имени экспорта. + +Компилятор Rust не допускает нулевые байты в строках имён экспорта, так +как они недопустимы в именах символов C и вызовут проблемы с внешней +компоновкой.", + "\ +`export_name` 속성이 내보내기 이름 문자열에 null 문자(`\\0`)가 있는 +함수에 적용되었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove null characters from export_name", + "Удалить нулевые символы из export_name", + "export_name에서 null 문자 제거" + ), + code: "#[export_name=\"foo\"] // no null characters\npub fn bar() {}" + }], + links: &[ + DocLink { + title: "FFI", + url: "https://doc.rust-lang.org/nomicon/ffi.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0648.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0670.rs b/masterror-knowledge/src/errors/syntax/e0670.rs new file mode 100644 index 0000000..acb9219 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0670.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0670: async fn not permitted in Rust 2015 + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0670", + title: LocalizedText::new( + "async fn not permitted in Rust 2015", + "async fn не разрешён в Rust 2015", + "Rust 2015에서는 async fn이 허용되지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Rust 2015 does not permit the use of `async fn`. The `async fn` feature +was not available in the 2015 edition of Rust. + +The `async fn` syntax and async/await functionality became available +starting with Rust 2018 edition.", + "\ +Rust 2015 не допускает использование `async fn`. Функция `async fn` не +была доступна в редакции Rust 2015. + +Синтаксис `async fn` и функциональность async/await стали доступны +начиная с редакции Rust 2018.", + "\ +Rust 2015에서는 `async fn` 사용이 허용되지 않습니다. `async fn` +기능은 Rust 2015 에디션에서 사용할 수 없었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Switch to Rust 2018 or later edition", + "Переключиться на Rust 2018 или более позднюю редакцию", + "Rust 2018 이상 에디션으로 전환" + ), + code: "# In Cargo.toml:\n[package]\nedition = \"2021\"" + }], + links: &[ + DocLink { + title: "Editions", + url: "https://doc.rust-lang.org/edition-guide/" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0670.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0695.rs b/masterror-knowledge/src/errors/syntax/e0695.rs new file mode 100644 index 0000000..5e13dd4 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0695.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0695: unlabeled break inside labeled block + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0695", + title: LocalizedText::new( + "Unlabeled break inside labeled block", + "Немаркированный break внутри маркированного блока", + "레이블이 지정된 블록 내 레이블 없는 break" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A `break` statement without a label appeared inside a labeled block. +The compiler cannot determine which loop or block you intend to break +out of. + +When you have a labeled block with a `break` statement inside it, Rust +requires the `break` to be explicitly labeled to clarify which construct +should be exited.", + "\ +Оператор `break` без метки появился внутри маркированного блока. +Компилятор не может определить, из какого цикла или блока вы намерены +выйти. + +Когда у вас есть маркированный блок с оператором `break` внутри, Rust +требует, чтобы `break` был явно помечен, чтобы уточнить, из какой +конструкции следует выйти.", + "\ +레이블이 없는 `break` 문이 레이블이 지정된 블록 내에 나타났습니다. +컴파일러는 어떤 루프나 블록에서 벗어나려는지 결정할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Label the break statement", + "Добавить метку к оператору break", + "break 문에 레이블 지정" + ), + code: "'outer: loop {\n 'inner: {\n break 'outer; // explicit label\n }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Break the labeled block", + "Выйти из маркированного блока", + "레이블이 지정된 블록에서 break" + ), + code: "loop {\n 'a: {\n break 'a; // break labeled block\n }\n break;\n}" + } + ], + links: &[ + DocLink { + title: "Loop Labels", + url: "https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0695.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0696.rs b/masterror-knowledge/src/errors/syntax/e0696.rs new file mode 100644 index 0000000..758351c --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0696.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0696: continue outside loop + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0696", + title: LocalizedText::new( + "continue used incorrectly", + "continue использован неправильно", + "continue가 잘못 사용됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A function is using `continue` keyword incorrectly. The `continue` keyword +can only be used inside loops (`loop`, `while`, `for`). + +Using `continue` in a labeled block that is NOT a loop causes this error. +Using `continue` to jump to a labeled block (rather than a loop) is also +invalid.", + "\ +Функция использует ключевое слово `continue` неправильно. Ключевое слово +`continue` может использоваться только внутри циклов (`loop`, `while`, `for`). + +Использование `continue` в маркированном блоке, который НЕ является циклом, +вызывает эту ошибку. Использование `continue` для перехода к маркированному +блоку (а не к циклу) также недопустимо.", + "\ +함수가 `continue` 키워드를 잘못 사용하고 있습니다. `continue` 키워드는 +루프(`loop`, `while`, `for`) 내에서만 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use continue inside a loop", + "Использовать continue внутри цикла", + "루프 내에서 continue 사용" + ), + code: "'b: loop {\n continue 'b; // ok - 'b is a loop\n}" + }], + links: &[ + DocLink { + title: "continue Expression", + url: "https://doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0696.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0697.rs b/masterror-knowledge/src/errors/syntax/e0697.rs new file mode 100644 index 0000000..e7a3318 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0697.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0697: static closure + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0697", + title: LocalizedText::new( + "Closure cannot be used as static", + "Замыкание нельзя использовать как static", + "클로저를 static으로 사용할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A closure has been used as `static`. Closures cannot be declared as +`static` because of fundamental incompatibilities with how closures +and statics work. + +Closures are designed to capture and save their environment. A `static` +item must have a fixed value determined at compile time and stored in +the binary. A static closure would need to save only a static environment, +which defeats the purpose of using a closure.", + "\ +Замыкание было использовано как `static`. Замыкания не могут быть +объявлены как `static` из-за фундаментальной несовместимости с тем, +как работают замыкания и статические элементы. + +Замыкания предназначены для захвата и сохранения своего окружения. +Статический элемент должен иметь фиксированное значение, определённое +во время компиляции и хранящееся в бинарном файле.", + "\ +클로저가 `static`으로 사용되었습니다. 클로저와 static의 근본적인 +비호환성으로 인해 클로저를 `static`으로 선언할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove the static keyword", + "Удалить ключевое слово static", + "static 키워드 제거" + ), + code: "let closure = || {}; // regular closure" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a function instead", + "Использовать функцию вместо этого", + "대신 함수 사용" + ), + code: "fn regular_function() {}" + } + ], + links: &[ + DocLink { + title: "Closures", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0697.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0703.rs b/masterror-knowledge/src/errors/syntax/e0703.rs new file mode 100644 index 0000000..1154917 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0703.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0703: invalid ABI + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0703", + title: LocalizedText::new("Invalid ABI", "Недопустимый ABI", "잘못된 ABI"), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +An invalid ABI (Application Binary Interface) was used in the code. + +Only predefined ABIs can be used in Rust, such as: +- `Rust` (default) +- `C` +- `system` +- `cdecl`, `stdcall`, `fastcall`, `vectorcall` (Windows) +- `aapcs` (ARM) +- `win64`, `sysv64` (x86_64)", + "\ +В коде использован недопустимый ABI. + +В Rust можно использовать только предопределённые ABI: +`Rust`, `C`, `system` и другие.", + "\ +잘못된 ABI가 코드에서 사용되었습니다. + +Rust에서는 사전 정의된 ABI만 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a valid ABI", + "Используйте допустимый ABI", + "유효한 ABI 사용" + ), + code: "extern \"C\" fn foo() {} // valid ABI" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0703.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0704.rs b/masterror-knowledge/src/errors/syntax/e0704.rs new file mode 100644 index 0000000..948ac07 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0704.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0704: incorrect visibility restriction + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0704", + title: LocalizedText::new( + "Incorrect visibility restriction", + "Неправильное ограничение видимости", + "잘못된 가시성 제한" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +An incorrect visibility restriction syntax was used. + +When trying to restrict visibility to a module, the `in` keyword must be used +with the `pub` keyword: `pub(in path)` instead of `pub(module_name)`.", + "\ +Использован неправильный синтаксис ограничения видимости. + +При ограничении видимости модулем нужно использовать `in`: +`pub(in path)` вместо `pub(module_name)`.", + "\ +잘못된 가시성 제한 구문이 사용되었습니다. + +모듈에 가시성을 제한할 때 `in` 키워드를 사용해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use pub(in path) syntax", + "Используйте синтаксис pub(in path)", + "pub(in path) 구문 사용" + ), + code: "mod foo {\n pub(in crate::foo) struct Bar {\n x: i32\n }\n}" + }], + links: &[DocLink { + title: "Rust Reference: Visibility", + url: "https://doc.rust-lang.org/reference/visibility-and-privacy.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0705.rs b/masterror-knowledge/src/errors/syntax/e0705.rs new file mode 100644 index 0000000..0bcaaa5 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0705.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0705: feature stable in current edition (no longer emitted) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0705", + title: LocalizedText::new( + "Feature stable in current edition", + "Функция стабильна в текущей редакции", + "현재 에디션에서 안정화된 기능" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +Note: This error code is no longer emitted by the compiler. + +A `#![feature]` attribute was used for a feature that is stable in the +current edition. The feature gate is unnecessary since the feature is +already available.", + "\ +Примечание: Эта ошибка больше не выдаётся компилятором. + +Атрибут `#![feature]` использован для функции, стабильной в текущей редакции.", + "\ +참고: 이 오류 코드는 더 이상 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove unnecessary feature gate", + "Удалите ненужный feature gate", + "불필요한 기능 게이트 제거" + ), + code: "// Remove: #![feature(already_stable_feature)]" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0705.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0742.rs b/masterror-knowledge/src/errors/syntax/e0742.rs new file mode 100644 index 0000000..ea95902 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0742.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0742: visibility restricted to non-ancestor module + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0742", + title: LocalizedText::new( + "Visibility restricted to non-ancestor module", + "Видимость ограничена модулем, не являющимся предком", + "조상이 아닌 모듈로 가시성 제한" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +Visibility is restricted to a module which isn't an ancestor of the current item. + +The `pub(in path)` syntax can only restrict visibility to an ancestor module, +not to sibling or unrelated modules.", + "\ +Видимость ограничена модулем, который не является предком текущего элемента. + +Синтаксис `pub(in path)` может ограничивать видимость только предком.", + "\ +현재 항목의 조상이 아닌 모듈로 가시성이 제한되었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Move item inside the target module", + "Переместите элемент внутрь целевого модуля", + "대상 모듈 내부로 항목 이동" + ), + code: "pub mod earth {\n pub mod sea {\n pub(in crate::earth) struct Shark; // ok\n }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0742.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0748.rs b/masterror-knowledge/src/errors/syntax/e0748.rs new file mode 100644 index 0000000..65d9e6f --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0748.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0748: raw string not terminated + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0748", + title: LocalizedText::new( + "Raw string not correctly terminated", + "Сырая строка неправильно завершена", + "raw 문자열이 올바르게 종료되지 않음" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A raw string isn't correctly terminated because the trailing `#` count +doesn't match its leading `#` count. + +The number of hash symbols (`#`) at the end must exactly match the number +at the beginning.", + "\ +Сырая строка неправильно завершена, так как количество `#` в конце +не соответствует количеству в начале.", + "\ +raw 문자열이 올바르게 종료되지 않았습니다. 끝의 `#` 개수가 +시작의 `#` 개수와 일치해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match trailing hash count", + "Выровняйте количество # в конце", + "끝의 해시 개수 맞추기" + ), + code: "let s = r#\"Hello\"#; // one # at start and end" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0748.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0753.rs b/masterror-knowledge/src/errors/syntax/e0753.rs new file mode 100644 index 0000000..38ebb2b --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0753.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0753: inner doc comment in invalid context + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0753", + title: LocalizedText::new( + "Inner doc comment in invalid context", + "Внутренний doc-комментарий в неправильном месте", + "잘못된 컨텍스트의 내부 문서 주석" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +An inner doc comment (`//!`) was used in an invalid context. + +Inner doc comments can only be used before items, typically at the beginning +of a module or crate to document the module itself.", + "\ +Внутренний doc-комментарий (`//!`) использован в неправильном месте. + +Такие комментарии можно использовать только перед элементами, +обычно в начале модуля для документирования самого модуля.", + "\ +내부 문서 주석(`//!`)이 잘못된 컨텍스트에서 사용되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use outer doc comment for items", + "Используйте внешний doc-комментарий для элементов", + "항목에 외부 문서 주석 사용" + ), + code: "/// I am an outer doc comment\nfn foo() {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use inner comment at module start", + "Используйте внутренний комментарий в начале модуля", + "모듈 시작에 내부 주석 사용" + ), + code: "//! Module documentation\nfn foo() {}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0753.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0758.rs b/masterror-knowledge/src/errors/syntax/e0758.rs new file mode 100644 index 0000000..cee4f83 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0758.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0758: unterminated multi-line comment + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0758", + title: LocalizedText::new( + "Unterminated multi-line comment", + "Незавершённый многострочный комментарий", + "종료되지 않은 여러 줄 주석" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A multi-line comment (either regular `/* */` or doc comment `/*! */`) +is unterminated. + +Multi-line comments must be properly closed with `*/`.", + "\ +Многострочный комментарий (обычный `/* */` или doc `/*! */`) +не завершён. + +Многострочные комментарии должны заканчиваться на `*/`.", + "\ +여러 줄 주석(`/* */` 또는 문서 주석 `/*! */`)이 종료되지 않았습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Close the comment with */", + "Закройте комментарий с помощью */", + "*/로 주석 닫기" + ), + code: "/* This is a\n multi-line comment */" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0758.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0762.rs b/masterror-knowledge/src/errors/syntax/e0762.rs new file mode 100644 index 0000000..c9f26a6 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0762.rs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0762: unterminated character literal + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0762", + title: LocalizedText::new( + "Unterminated character literal", + "Незавершённый символьный литерал", + "종료되지 않은 문자 리터럴" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A character literal wasn't ended with a quote. + +Character literals must be enclosed in single quotes.", + "\ +Символьный литерал не завершён кавычкой. + +Символьные литералы должны быть заключены в одинарные кавычки.", + "\ +문자 리터럴이 따옴표로 끝나지 않았습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add closing quote", + "Добавьте закрывающую кавычку", + "닫는 따옴표 추가" + ), + code: "static C: char = 'a'; // closed properly" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0762.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0763.rs b/masterror-knowledge/src/errors/syntax/e0763.rs new file mode 100644 index 0000000..030f415 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0763.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0763: unterminated byte literal + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0763", + title: LocalizedText::new( + "Unterminated byte literal", + "Незавершённый байтовый литерал", + "종료되지 않은 바이트 리터럴" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A byte constant wasn't correctly ended. + +Byte literals (prefixed with `b`) must be properly terminated with a +closing quote.", + "\ +Байтовый литерал не завершён правильно. + +Байтовые литералы (с префиксом `b`) должны заканчиваться кавычкой.", + "\ +바이트 상수가 올바르게 종료되지 않았습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add closing quote", + "Добавьте закрывающую кавычку", + "닫는 따옴표 추가" + ), + code: "let c = b'a'; // closed properly" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0763.html" + }] +}; diff --git a/masterror-knowledge/src/errors/syntax/e0765.rs b/masterror-knowledge/src/errors/syntax/e0765.rs new file mode 100644 index 0000000..8a779a4 --- /dev/null +++ b/masterror-knowledge/src/errors/syntax/e0765.rs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0765: unterminated string + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0765", + title: LocalizedText::new( + "Unterminated string", + "Незавершённая строка", + "종료되지 않은 문자열" + ), + category: Category::Syntax, + explanation: LocalizedText::new( + "\ +A double quote string was not terminated. + +String literals must be closed with a matching double quote.", + "\ +Строка в двойных кавычках не завершена. + +Строковые литералы должны заканчиваться двойной кавычкой.", + "\ +큰따옴표 문자열이 종료되지 않았습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add closing double quote", + "Добавьте закрывающую двойную кавычку", + "닫는 큰따옴표 추가" + ), + code: "let s = \"hello\"; // closed properly" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0765.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits.rs b/masterror-knowledge/src/errors/traits.rs new file mode 100644 index 0000000..e4737f6 --- /dev/null +++ b/masterror-knowledge/src/errors/traits.rs @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Trait-related errors. + +mod e0034; +mod e0038; +mod e0040; +mod e0046; +mod e0049; +mod e0050; +mod e0053; +mod e0116; +mod e0117; +mod e0118; +mod e0119; +mod e0120; +mod e0183; +mod e0184; +mod e0185; +mod e0186; +mod e0191; +mod e0200; +mod e0201; +mod e0204; +mod e0205; +mod e0206; +mod e0207; +mod e0210; +mod e0220; +mod e0221; +mod e0222; +mod e0223; +mod e0224; +mod e0225; +mod e0271; +mod e0275; +mod e0276; +mod e0282; +mod e0404; +mod e0405; +mod e0407; +mod e0437; +mod e0438; +mod e0520; +mod e0525; +mod e0567; +mod e0568; +mod e0576; +mod e0592; +mod e0593; +mod e0638; +mod e0639; +mod e0642; +mod e0665; +mod e0802; +mod e0804; +mod e0805; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0034::ENTRY, + &e0038::ENTRY, + &e0040::ENTRY, + &e0046::ENTRY, + &e0049::ENTRY, + &e0050::ENTRY, + &e0053::ENTRY, + &e0116::ENTRY, + &e0117::ENTRY, + &e0118::ENTRY, + &e0119::ENTRY, + &e0120::ENTRY, + &e0183::ENTRY, + &e0184::ENTRY, + &e0185::ENTRY, + &e0186::ENTRY, + &e0191::ENTRY, + &e0200::ENTRY, + &e0201::ENTRY, + &e0204::ENTRY, + &e0205::ENTRY, + &e0206::ENTRY, + &e0207::ENTRY, + &e0210::ENTRY, + &e0220::ENTRY, + &e0221::ENTRY, + &e0222::ENTRY, + &e0223::ENTRY, + &e0224::ENTRY, + &e0225::ENTRY, + &e0271::ENTRY, + &e0275::ENTRY, + &e0276::ENTRY, + &e0282::ENTRY, + &e0404::ENTRY, + &e0405::ENTRY, + &e0407::ENTRY, + &e0437::ENTRY, + &e0438::ENTRY, + &e0520::ENTRY, + &e0525::ENTRY, + &e0567::ENTRY, + &e0568::ENTRY, + &e0576::ENTRY, + &e0592::ENTRY, + &e0593::ENTRY, + &e0638::ENTRY, + &e0639::ENTRY, + &e0642::ENTRY, + &e0665::ENTRY, + &e0802::ENTRY, + &e0804::ENTRY, + &e0805::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/traits/e0034.rs b/masterror-knowledge/src/errors/traits/e0034.rs new file mode 100644 index 0000000..a6a75a5 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0034.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0034: ambiguous method call + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0034", + title: LocalizedText::new( + "Ambiguous method call", + "Неоднозначный вызов метода", + "모호한 메서드 호출" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +This error occurs when multiple traits define methods with the same name, +and you call the method without specifying which trait's implementation to use. + +Example: + trait Foo { fn method(&self); } + trait Bar { fn method(&self); } + impl Foo for MyType { ... } + impl Bar for MyType { ... } + + my_value.method(); // Error: ambiguous - Foo::method or Bar::method?", + "\ +Эта ошибка возникает, когда несколько трейтов определяют методы с одинаковым +именем, и вы вызываете метод без указания, какую реализацию использовать.", + "\ +이 오류는 여러 트레이트가 같은 이름의 메서드를 정의하고, 어떤 구현을 사용할지 +지정하지 않고 메서드를 호출할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use fully qualified syntax", + "Использовать полный синтаксис", + "완전한 한정 구문 사용" + ), + code: "::method(&my_value);\n// or\nFoo::method(&my_value);" + }], + links: &[ + DocLink { + title: "Rust Book: Fully Qualified Syntax", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0034.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0038.rs b/masterror-knowledge/src/errors/traits/e0038.rs new file mode 100644 index 0000000..9055739 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0038.rs @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0038", + title: LocalizedText::new( + "Trait cannot be made into an object", + "Трейт не может быть превращён в объект", + "트레이트를 객체로 만들 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "This trait is not object-safe - it can't be used as `dyn Trait`.", + "Этот трейт не объектно-безопасен - его нельзя использовать как `dyn Trait`.", + "이 트레이트는 객체 안전하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new("Use generics", "Использовать обобщения", "제네릭 사용"), + code: "fn process(item: T) { ... }" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0038.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0040.rs b/masterror-knowledge/src/errors/traits/e0040.rs new file mode 100644 index 0000000..e1b8450 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0040.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0040: explicit destructor call + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0040", + title: LocalizedText::new( + "Explicit destructor call", + "Явный вызов деструктора", + "명시적 소멸자 호출" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Rust does not allow explicit calls to the `drop()` method. The `Drop` trait's +destructor is called automatically when a value goes out of scope. + +Example: + let x = MyType::new(); + x.drop(); // Error: explicit use of destructor method", + "\ +Rust не позволяет явно вызывать метод `drop()`. Деструктор трейта Drop +вызывается автоматически, когда значение выходит из области видимости.", + "\ +Rust는 `drop()` 메서드를 명시적으로 호출하는 것을 허용하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use std::mem::drop() function", + "Использовать функцию std::mem::drop()", + "std::mem::drop() 함수 사용" + ), + code: "let x = MyType::new();\ndrop(x); // Takes ownership and drops" + }], + links: &[ + DocLink { + title: "Rust Book: Drop Trait", + url: "https://doc.rust-lang.org/book/ch15-03-drop.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0040.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0046.rs b/masterror-knowledge/src/errors/traits/e0046.rs new file mode 100644 index 0000000..8da4f7b --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0046.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0046: missing trait implementation items + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0046", + title: LocalizedText::new( + "Missing trait implementation items", + "Отсутствуют элементы реализации трейта", + "트레이트 구현 항목 누락" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +This error occurs when implementing a trait but failing to provide +implementations for all required items (methods, types, constants). + +Example: + trait Foo { fn foo(&self); } + impl Foo for Bar {} // Error: missing method `foo`", + "\ +Эта ошибка возникает при реализации трейта без предоставления реализаций +для всех обязательных элементов (методов, типов, констант).", + "\ +이 오류는 트레이트를 구현할 때 필수 항목의 구현을 제공하지 않으면 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Implement all required trait methods", + "Реализовать все обязательные методы трейта", + "모든 필수 트레이트 메서드 구현" + ), + code: "impl Foo for Bar {\n fn foo(&self) {\n // implementation\n }\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Implementing Traits", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0046.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0049.rs b/masterror-knowledge/src/errors/traits/e0049.rs new file mode 100644 index 0000000..19325a0 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0049.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0049: wrong number of type parameters in trait impl + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0049", + title: LocalizedText::new( + "Wrong type parameter count in impl", + "Неверное количество параметров типа в impl", + "impl에서 잘못된 타입 매개변수 수" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +This error occurs when a trait method implementation has a different number +of type parameters than the trait definition. + +Example: + trait Foo { fn foo(x: T); } + impl Foo for Bar { + fn foo(x: bool) {} // Error: expected 1 type parameter, found 0 + }", + "\ +Эта ошибка возникает, когда реализация метода трейта имеет другое количество +параметров типа, чем определение трейта.", + "\ +이 오류는 트레이트 메서드 구현의 타입 매개변수 수가 정의와 다를 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match trait's type parameter count", + "Соответствовать количеству параметров типа трейта", + "트레이트의 타입 매개변수 수와 일치" + ), + code: "impl Foo for Bar {\n fn foo(x: T) { }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0049.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0050.rs b/masterror-knowledge/src/errors/traits/e0050.rs new file mode 100644 index 0000000..e8f9652 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0050.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0050: wrong number of parameters in trait impl method + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0050", + title: LocalizedText::new( + "Wrong parameter count in impl method", + "Неверное количество параметров в методе impl", + "impl 메서드에서 잘못된 매개변수 수" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +This error occurs when a trait method implementation has a different number +of parameters than the trait definition. + +Example: + trait Foo { fn foo(&self, x: u8) -> bool; } + impl Foo for Bar { + fn foo(&self) -> bool { true } // Error: expected 2 params, found 1 + }", + "\ +Эта ошибка возникает, когда реализация метода трейта имеет другое количество +параметров, чем определение трейта.", + "\ +이 오류는 트레이트 메서드 구현의 매개변수 수가 정의와 다를 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match trait's parameter count", + "Соответствовать количеству параметров трейта", + "트레이트의 매개변수 수와 일치" + ), + code: "impl Foo for Bar {\n fn foo(&self, x: u8) -> bool { true }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0050.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0053.rs b/masterror-knowledge/src/errors/traits/e0053.rs new file mode 100644 index 0000000..f8e6cb5 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0053.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0053: method parameter type mismatch in trait impl + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0053", + title: LocalizedText::new( + "Parameter type mismatch in impl", + "Несоответствие типов параметров в impl", + "impl에서 매개변수 타입 불일치" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +This error occurs when a trait method implementation has parameter types or +mutability that don't match the trait definition. + +Example: + trait Foo { fn foo(x: u16); fn bar(&self); } + impl Foo for Bar { + fn foo(x: i16) { } // Error: expected u16, found i16 + fn bar(&mut self) { } // Error: mutability mismatch + }", + "\ +Эта ошибка возникает, когда типы параметров или изменяемость в реализации +метода трейта не соответствуют определению трейта.", + "\ +이 오류는 트레이트 메서드 구현의 매개변수 타입이나 가변성이 정의와 일치하지 않을 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match trait's exact parameter types", + "Точно соответствовать типам параметров трейта", + "트레이트의 정확한 매개변수 타입과 일치" + ), + code: "impl Foo for Bar {\n fn foo(x: u16) { }\n fn bar(&self) { }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0053.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0116.rs b/masterror-knowledge/src/errors/traits/e0116.rs new file mode 100644 index 0000000..6a9e984 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0116.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0116: cannot define inherent impl for a type outside of the crate + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0116", + title: LocalizedText::new( + "Cannot define inherent impl for a type outside of the crate", + "Нельзя определить собственную реализацию для типа из другого крейта", + "다른 크레이트의 타입에 대한 고유 구현을 정의할 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An inherent implementation was defined for a type outside the current crate. +Rust's orphan rules only allow you to implement methods directly on types +that you own (defined in your crate). + +Note: Using type aliases does not work around this restriction.", + "\ +Собственная реализация была определена для типа из другого крейта. +Правила сирот Rust позволяют реализовывать методы только для типов, +определённых в вашем крейте. + +Примечание: использование псевдонимов типов не обходит это ограничение.", + "\ +현재 크레이트 외부의 타입에 대한 고유 구현이 정의되었습니다. +Rust의 고아 규칙은 자신의 크레이트에서 정의된 타입에만 메서드를 +직접 구현할 수 있도록 허용합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Define and implement a trait for the type", + "Определить и реализовать трейт для типа", + "타입에 대한 트레이트 정의 및 구현" + ), + code: "trait MyTrait {\n fn my_method(&self);\n}\nimpl MyTrait for Vec {\n fn my_method(&self) { }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Create a wrapper type (newtype pattern)", + "Создать тип-обёртку (паттерн newtype)", + "래퍼 타입 생성 (newtype 패턴)" + ), + code: "struct MyBytes(Vec);\nimpl MyBytes {\n fn my_method(&self) { }\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Newtype Pattern", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0116.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0117.rs b/masterror-knowledge/src/errors/traits/e0117.rs new file mode 100644 index 0000000..927e190 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0117.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0117: only traits defined in the current crate can be implemented for +//! arbitrary types + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0117", + title: LocalizedText::new( + "Only traits defined in the current crate can be implemented for arbitrary types", + "Только трейты из текущего крейта можно реализовать для произвольных типов", + "현재 크레이트에서 정의된 트레이트만 임의 타입에 구현 가능" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +This is a violation of Rust's orphan rules for trait implementations. +You cannot implement a foreign trait (defined in another crate) when: +- The type implementing the trait is foreign (not defined in your crate), AND +- All type parameters passed to the trait are also foreign + +This rule ensures coherence - preventing conflicting implementations across crates.", + "\ +Это нарушение правил сирот Rust для реализаций трейтов. +Нельзя реализовать внешний трейт (из другого крейта) когда: +- Тип, реализующий трейт, внешний (не из вашего крейта), И +- Все параметры типа, переданные трейту, тоже внешние + +Это правило обеспечивает согласованность и предотвращает конфликты реализаций.", + "\ +이것은 트레이트 구현에 대한 Rust의 고아 규칙 위반입니다. +다음 경우에 외부 트레이트를 구현할 수 없습니다: +- 트레이트를 구현하는 타입이 외부 타입이고 +- 트레이트에 전달된 모든 타입 매개변수도 외부인 경우" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Implement the trait on a local type", + "Реализовать трейт для локального типа", + "로컬 타입에 트레이트 구현" + ), + code: "pub struct Foo;\n\nimpl Drop for Foo {\n fn drop(&mut self) { }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Define a local trait instead", + "Определить локальный трейт", + "대신 로컬 트레이트 정의" + ), + code: "trait Bar {\n fn get(&self) -> usize;\n}\n\nimpl Bar for u32 {\n fn get(&self) -> usize { 0 }\n}" + } + ], + links: &[ + DocLink { + title: "RFC 1023: Rebalancing Coherence", + url: "https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0117.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0118.rs b/masterror-knowledge/src/errors/traits/e0118.rs new file mode 100644 index 0000000..ac0457c --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0118.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0118: no nominal type found for inherent implementation + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0118", + title: LocalizedText::new( + "No nominal type found for inherent implementation", + "Номинальный тип не найден для собственной реализации", + "고유 구현을 위한 명목적 타입을 찾을 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An inherent implementation was defined for something which isn't a struct, +enum, union, or trait object. Inherent implementations can only be created +for these specific nominal types. + +You cannot define an inherent impl for generic type parameters like T.", + "\ +Собственная реализация была определена для чего-то, что не является +структурой, перечислением, объединением или трейт-объектом. +Собственные реализации можно создавать только для этих номинальных типов. + +Нельзя определить собственную реализацию для параметров типа вроде T.", + "\ +구조체, 열거형, 공용체 또는 트레이트 객체가 아닌 것에 대해 고유 구현이 +정의되었습니다. 고유 구현은 이러한 명목적 타입에만 생성할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Implement a trait instead", + "Реализовать трейт вместо этого", + "대신 트레이트 구현" + ), + code: "trait MyTrait {\n fn get_state(&self) -> String;\n}\n\nimpl MyTrait for T {\n fn get_state(&self) -> String {\n \"state\".to_owned()\n }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Create a newtype wrapper", + "Создать тип-обёртку", + "newtype 래퍼 생성" + ), + code: "struct TypeWrapper(T);\n\nimpl TypeWrapper {\n fn get_state(&self) -> String {\n \"state\".to_owned()\n }\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Implementations", + url: "https://doc.rust-lang.org/reference/items/implementations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0118.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0119.rs b/masterror-knowledge/src/errors/traits/e0119.rs new file mode 100644 index 0000000..d4f05f2 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0119.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0119: conflicting implementations of trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0119", + title: LocalizedText::new( + "Conflicting implementations of trait", + "Конфликтующие реализации трейта", + "트레이트의 충돌하는 구현" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +There are multiple conflicting trait implementations for the same type. +Rust cannot allow a trait to be implemented more than once for a given type. + +A common scenario is when you implement a trait for a generic type T +(covering all types) and then try to implement the same trait for a +specific concrete type. This creates a conflict because the concrete +implementation overlaps with the generic implementation.", + "\ +Существует несколько конфликтующих реализаций трейта для одного типа. +Rust не позволяет реализовать трейт более одного раза для данного типа. + +Типичный сценарий - когда вы реализуете трейт для обобщённого типа T +(покрывающего все типы), а затем пытаетесь реализовать тот же трейт +для конкретного типа. Это создаёт конфликт, так как конкретная +реализация пересекается с обобщённой.", + "\ +동일한 타입에 대해 여러 개의 충돌하는 트레이트 구현이 있습니다. +Rust는 주어진 타입에 대해 트레이트를 두 번 이상 구현하는 것을 허용하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove the conflicting implementation", + "Удалить конфликтующую реализацию", + "충돌하는 구현 제거" + ), + code: "trait MyTrait {\n fn get(&self) -> usize;\n}\n\n// Keep only one implementation\nimpl MyTrait for T {\n fn get(&self) -> usize { 0 }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use specialization (nightly only)", + "Использовать специализацию (только nightly)", + "특수화 사용 (nightly만 해당)" + ), + code: "#![feature(specialization)]\n\nimpl MyTrait for T {\n default fn get(&self) -> usize { 0 }\n}\n\nimpl MyTrait for Foo {\n fn get(&self) -> usize { self.value }\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Traits", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0119.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0120.rs b/masterror-knowledge/src/errors/traits/e0120.rs new file mode 100644 index 0000000..dca1473 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0120.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0120: Drop implemented on trait object or reference + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0120", + title: LocalizedText::new( + "Drop implemented on trait object or reference", + "Drop реализован для трейт-объекта или ссылки", + "트레이트 객체 또는 참조에 Drop 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Drop was implemented on a trait object or reference, which is not allowed. +Only structs, enums, and unions can implement the Drop trait. + +The Drop trait is used for cleanup when a value goes out of scope, and +it only makes sense for owned types, not for references or trait objects.", + "\ +Drop был реализован для трейт-объекта или ссылки, что не разрешено. +Только структуры, перечисления и объединения могут реализовать трейт Drop. + +Трейт Drop используется для очистки когда значение выходит из области +видимости и имеет смысл только для владеющих типов.", + "\ +트레이트 객체 또는 참조에 Drop이 구현되었는데, 이는 허용되지 않습니다. +구조체, 열거형, 공용체만 Drop 트레이트를 구현할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a wrapper struct with generic type bound", + "Использовать структуру-обёртку с ограничением типа", + "제네릭 타입 바운드가 있는 래퍼 구조체 사용" + ), + code: "trait MyTrait {}\nstruct MyWrapper { foo: T }\n\nimpl Drop for MyWrapper {\n fn drop(&mut self) {}\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a wrapper containing trait object", + "Использовать обёртку с трейт-объектом", + "트레이트 객체를 포함하는 래퍼 사용" + ), + code: "trait MyTrait {}\n\nstruct MyWrapper<'a> { foo: &'a dyn MyTrait }\n\nimpl<'a> Drop for MyWrapper<'a> {\n fn drop(&mut self) {}\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Drop Trait", + url: "https://doc.rust-lang.org/book/ch15-03-drop.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0120.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0183.rs b/masterror-knowledge/src/errors/traits/e0183.rs new file mode 100644 index 0000000..af5128d --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0183.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0183: manual implementation of a Fn* trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0183", + title: LocalizedText::new( + "Manual implementation of a Fn* trait", + "Ручная реализация трейта Fn*", + "Fn* 트레이트의 수동 구현" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +You attempted to manually implement Fn, FnMut, or FnOnce traits without +enabling the required unstable features. These trait implementations are +unstable and require the feature flags fn_traits and unboxed_closures.", + "\ +Вы попытались вручную реализовать трейты Fn, FnMut или FnOnce без +включения необходимых нестабильных функций. Эти реализации трейтов +нестабильны и требуют флагов fn_traits и unboxed_closures.", + "\ +필요한 불안정 기능을 활성화하지 않고 Fn, FnMut 또는 FnOnce 트레이트를 +수동으로 구현하려고 했습니다. 이러한 트레이트 구현은 불안정하며 +fn_traits 및 unboxed_closures 기능 플래그가 필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Enable the required features", + "Включить необходимые функции", + "필요한 기능 활성화" + ), + code: "#![feature(fn_traits, unboxed_closures)]\n\nstruct MyClosure {\n foo: i32\n}\n\nimpl FnOnce<()> for MyClosure {\n type Output = ();\n extern \"rust-call\" fn call_once(self, args: ()) -> Self::Output {\n println!(\"{}\", self.foo);\n }\n}" + }], + links: &[ + DocLink { + title: "Tracking Issue: fn_traits", + url: "https://github.com/rust-lang/rust/issues/29625" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0183.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0184.rs b/masterror-knowledge/src/errors/traits/e0184.rs new file mode 100644 index 0000000..238cd92 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0184.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0184: the Copy trait was implemented on a type with a Drop implementation + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0184", + title: LocalizedText::new( + "The Copy trait was implemented on a type with a Drop implementation", + "Трейт Copy реализован для типа с реализацией Drop", + "Drop 구현이 있는 타입에 Copy 트레이트가 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Explicitly implementing both Drop and Copy traits on a type is currently +disallowed. While this might make sense in theory, the current implementation +is incorrect and can lead to memory unsafety, so it has been disabled. + +A type that implements Copy is bitwise-copied, meaning Drop would never be +called, leading to resource leaks or double-frees.", + "\ +Явная реализация обоих трейтов Drop и Copy для одного типа запрещена. +Хотя это может иметь смысл в теории, текущая реализация некорректна и +может привести к небезопасности памяти. + +Тип, реализующий Copy, копируется побитово, что означает, что Drop +никогда не будет вызван.", + "\ +현재 타입에 Drop과 Copy 트레이트를 모두 명시적으로 구현하는 것은 +허용되지 않습니다. 이론적으로는 의미가 있을 수 있지만 현재 구현은 +올바르지 않으며 메모리 안전성 문제를 일으킬 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove either Copy or Drop implementation", + "Удалить реализацию Copy или Drop", + "Copy 또는 Drop 구현 제거" + ), + code: "// Choose one:\n\n// Option 1: Keep Copy, remove Drop\n#[derive(Copy, Clone)]\nstruct Foo;\n\n// Option 2: Keep Drop, remove Copy\nstruct Bar;\n\nimpl Drop for Bar {\n fn drop(&mut self) {}\n}" + }], + links: &[ + DocLink { + title: "Issue #20126", + url: "https://github.com/rust-lang/rust/issues/20126" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0184.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0185.rs b/masterror-knowledge/src/errors/traits/e0185.rs new file mode 100644 index 0000000..5ae8c20 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0185.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0185: method has a self declaration in the impl, but not in the trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0185", + title: LocalizedText::new( + "Method has a self declaration in the impl, but not in the trait", + "Метод имеет объявление self в impl, но не в трейте", + "메서드가 impl에는 self 선언이 있지만 트레이트에는 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated function in a trait is defined as static (taking no self +parameter), but the implementation declares it as a method (taking a self +parameter). Trait implementations must match the exact signature of the +trait definition.", + "\ +Ассоциированная функция в трейте определена как статическая (без параметра +self), но реализация объявляет её как метод (с параметром self). +Реализации трейтов должны точно соответствовать сигнатуре определения трейта.", + "\ +트레이트의 연관 함수가 정적(self 매개변수 없음)으로 정의되어 있지만 +구현은 메서드(self 매개변수 있음)로 선언합니다. 트레이트 구현은 +트레이트 정의의 정확한 시그니처와 일치해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match the trait signature - remove self parameter", + "Соответствовать сигнатуре трейта - удалить параметр self", + "트레이트 시그니처와 일치 - self 매개변수 제거" + ), + code: "trait Foo {\n fn foo();\n}\n\nstruct Bar;\n\nimpl Foo for Bar {\n fn foo() {} // ok! matches trait\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Implementing a Trait", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0185.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0186.rs b/masterror-knowledge/src/errors/traits/e0186.rs new file mode 100644 index 0000000..974815e --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0186.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0186: method has a self declaration in the trait, but not in the impl + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0186", + title: LocalizedText::new( + "Method has a self declaration in the trait, but not in the impl", + "Метод имеет объявление self в трейте, но не в impl", + "메서드가 트레이트에는 self 선언이 있지만 impl에는 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated function for a trait was defined to be a method (taking a self +parameter), but an implementation of the trait declared the same function to +be static (without self). The function signature must match exactly.", + "\ +Ассоциированная функция трейта определена как метод (с параметром self), +но реализация трейта объявила ту же функцию как статическую (без self). +Сигнатура функции должна точно совпадать.", + "\ +트레이트의 연관 함수가 메서드(self 매개변수 있음)로 정의되어 있지만 +트레이트 구현은 동일한 함수를 정적(self 없음)으로 선언합니다. +함수 시그니처는 정확히 일치해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match the trait signature - add self parameter", + "Соответствовать сигнатуре трейта - добавить параметр self", + "트레이트 시그니처와 일치 - self 매개변수 추가" + ), + code: "trait Foo {\n fn foo(&self);\n}\n\nstruct Bar;\n\nimpl Foo for Bar {\n fn foo(&self) {} // ok! matches trait\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Implementing a Trait", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0186.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0191.rs b/masterror-knowledge/src/errors/traits/e0191.rs new file mode 100644 index 0000000..d0af514 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0191.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0191: associated type wasn't specified for a trait object + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0191", + title: LocalizedText::new( + "Associated type wasn't specified for a trait object", + "Ассоциированный тип не указан для трейт-объекта", + "트레이트 객체에 대한 연관 타입이 지정되지 않음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +You attempted to create a trait object without specifying all required +associated types. Trait objects must have all their associated types +explicitly defined.", + "\ +Вы попытались создать трейт-объект без указания всех необходимых +ассоциированных типов. Трейт-объекты должны иметь все свои +ассоциированные типы явно определёнными.", + "\ +필요한 모든 연관 타입을 지정하지 않고 트레이트 객체를 생성하려고 +했습니다. 트레이트 객체는 모든 연관 타입이 명시적으로 정의되어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Specify all associated types", + "Указать все ассоциированные типы", + "모든 연관 타입 지정" + ), + code: "trait Trait {\n type Bar;\n}\n\ntype Foo = dyn Trait; // specify associated type" + }], + links: &[ + DocLink { + title: "Rust Book: Associated Types", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0191.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0200.rs b/masterror-knowledge/src/errors/traits/e0200.rs new file mode 100644 index 0000000..016236b --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0200.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0200: unsafe trait implemented without unsafe impl + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0200", + title: LocalizedText::new( + "Unsafe trait implemented without unsafe impl", + "Небезопасный трейт реализован без unsafe impl", + "unsafe impl 없이 unsafe 트레이트 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An unsafe trait was implemented without an unsafe implementation block. +Rust requires that any implementation of an unsafe trait must also be +declared as `unsafe` to indicate that the implementer understands and +accepts the safety responsibilities. + +When implementing an unsafe trait, you must explicitly mark the +implementation with the `unsafe` keyword to acknowledge you're +implementing code that may have safety implications.", + "\ +Небезопасный трейт был реализован без блока unsafe impl. +Rust требует, чтобы любая реализация небезопасного трейта также была +объявлена как `unsafe`, чтобы показать, что разработчик понимает +и принимает ответственность за безопасность.", + "\ +unsafe 트레이트가 unsafe impl 블록 없이 구현되었습니다. +Rust는 unsafe 트레이트의 모든 구현이 `unsafe`로 선언되어야 +안전 책임을 이해하고 수용함을 나타냅니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add unsafe keyword to impl block", + "Добавить ключевое слово unsafe к блоку impl", + "impl 블록에 unsafe 키워드 추가" + ), + code: "unsafe impl Bar for Foo { }" + }], + links: &[ + DocLink { + title: "Rust Reference: Unsafe Traits", + url: "https://doc.rust-lang.org/reference/items/traits.html#unsafe-traits" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0200.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0201.rs b/masterror-knowledge/src/errors/traits/e0201.rs new file mode 100644 index 0000000..cad4510 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0201.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0201: duplicate associated items in impl block + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0201", + title: LocalizedText::new( + "Duplicate associated items in impl block", + "Дублирующиеся ассоциированные элементы в блоке impl", + "impl 블록에 중복된 연관 항목" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Two associated items (methods, associated types, or associated functions) +are defined with the same identifier within the same `impl` block or trait +implementation. + +You cannot have duplicate names for associated items in a single +implementation. This applies to methods, associated types, and +associated functions. + +Note: Items with the same name ARE allowed in separate `impl` blocks +for different types.", + "\ +Два ассоциированных элемента (методы, ассоциированные типы или функции) +определены с одинаковым идентификатором в одном блоке `impl` или +реализации трейта. + +Нельзя иметь дублирующиеся имена для ассоциированных элементов +в одной реализации.", + "\ +동일한 `impl` 블록 또는 트레이트 구현 내에서 두 개의 연관 항목 +(메서드, 연관 타입 또는 연관 함수)이 같은 식별자로 정의되었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove duplicate or rename one of the items", + "Удалить дубликат или переименовать один из элементов", + "중복을 제거하거나 항목 중 하나의 이름 변경" + ), + code: "impl Foo {\n fn bar(&self) -> bool { self.0 > 5 }\n fn baz() {} // renamed from bar\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Implementations", + url: "https://doc.rust-lang.org/reference/items/implementations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0201.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0204.rs b/masterror-knowledge/src/errors/traits/e0204.rs new file mode 100644 index 0000000..f7bf6a4 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0204.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0204: Copy trait on type with non-Copy fields + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0204", + title: LocalizedText::new( + "Copy trait on type with non-Copy fields", + "Трейт Copy для типа с не-Copy полями", + "non-Copy 필드를 가진 타입에 Copy 트레이트" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Cannot implement `Copy` trait on types containing non-`Copy` fields. +The `Copy` trait can only be implemented on types whose ALL fields +implement `Copy`. + +Common non-Copy types include: +- Vec, String, Box +- Mutable references (&mut T) +- Types containing the above", + "\ +Нельзя реализовать трейт `Copy` для типов, содержащих не-`Copy` поля. +Трейт `Copy` может быть реализован только для типов, ВСЕ поля которых +реализуют `Copy`. + +Распространённые не-Copy типы: +- Vec, String, Box +- Изменяемые ссылки (&mut T)", + "\ +non-`Copy` 필드를 포함하는 타입에는 `Copy` 트레이트를 구현할 수 없습니다. +모든 필드가 `Copy`를 구현해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Ensure all fields implement Copy", + "Убедитесь, что все поля реализуют Copy", + "모든 필드가 Copy를 구현하는지 확인" + ), + code: "struct Foo {\n x: i32, // Copy\n y: bool, // Copy\n}\nimpl Copy for Foo {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use Clone instead of Copy", + "Используйте Clone вместо Copy", + "Copy 대신 Clone 사용" + ), + code: "#[derive(Clone)]\nstruct Foo {\n data: Vec,\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Copy Trait", + url: "https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ways-variables-and-data-interact-clone" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0204.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0205.rs b/masterror-knowledge/src/errors/traits/e0205.rs new file mode 100644 index 0000000..b6e5115 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0205.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0205: Copy trait on enum with non-Copy variants + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0205", + title: LocalizedText::new( + "Copy trait on enum with non-Copy variants", + "Трейт Copy для enum с не-Copy вариантами", + "non-Copy 변형을 가진 enum에 Copy 트레이트" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Cannot implement `Copy` trait for enum where one or more variants contain +types that do not implement `Copy`. + +For an enum to be `Copy`, ALL of its variants must contain only `Copy` types. +If any variant holds a non-`Copy` type, the implementation will fail. + +Note: This error code is no longer emitted by the compiler.", + "\ +Нельзя реализовать трейт `Copy` для enum, где один или более вариантов +содержат типы, не реализующие `Copy`. + +Чтобы enum был `Copy`, ВСЕ его варианты должны содержать только +`Copy` типы.", + "\ +하나 이상의 변형이 `Copy`를 구현하지 않는 타입을 포함하는 enum에는 +`Copy` 트레이트를 구현할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Ensure all variants contain Copy types", + "Убедитесь, что все варианты содержат Copy типы", + "모든 변형이 Copy 타입을 포함하는지 확인" + ), + code: "#[derive(Copy, Clone)]\nenum Foo {\n Bar(i32),\n Baz(bool),\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use Clone instead of Copy", + "Используйте Clone вместо Copy", + "Copy 대신 Clone 사용" + ), + code: "#[derive(Clone)]\nenum Foo {\n Bar(Vec),\n Baz,\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Copy", + url: "https://doc.rust-lang.org/std/marker/trait.Copy.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0205.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0206.rs b/masterror-knowledge/src/errors/traits/e0206.rs new file mode 100644 index 0000000..9cb2968 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0206.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0206: Copy trait on invalid type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0206", + title: LocalizedText::new( + "Copy trait implemented on invalid type", + "Трейт Copy реализован для недопустимого типа", + "잘못된 타입에 Copy 트레이트 구현" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +The `Copy` trait was implemented on a type which is neither a struct, +an enum, nor a union. + +The `Copy` trait can only be derived or manually implemented for these +three composite types. You cannot implement `Copy` for references, +primitives, or other types.", + "\ +Трейт `Copy` был реализован для типа, который не является ни структурой, +ни перечислением, ни объединением. + +Трейт `Copy` может быть реализован только для этих трёх составных типов.", + "\ +`Copy` 트레이트가 struct, enum, union이 아닌 타입에 구현되었습니다. +`Copy`는 이 세 가지 복합 타입에만 구현할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Implement Copy only on struct, enum, or union", + "Реализуйте Copy только для struct, enum или union", + "struct, enum 또는 union에만 Copy 구현" + ), + code: "#[derive(Copy, Clone)]\nstruct Bar;\n\n// Don't do: impl Copy for &'static mut Bar {}" + }], + links: &[ + DocLink { + title: "Rust Reference: Copy", + url: "https://doc.rust-lang.org/std/marker/trait.Copy.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0206.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0207.rs b/masterror-knowledge/src/errors/traits/e0207.rs new file mode 100644 index 0000000..20583e5 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0207.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0207: unconstrained type parameter in impl + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0207", + title: LocalizedText::new( + "Unconstrained type parameter in impl", + "Неограниченный параметр типа в impl", + "impl에서 제약되지 않은 타입 매개변수" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A type, const, or lifetime parameter specified for `impl` is not constrained. +Rust requires that all parameters in an `impl` must be 'constrained' by: + +1. Appearing in the implementing type (e.g., `impl Foo`) +2. Appearing in the implemented trait (e.g., `impl SomeTrait for Foo`) +3. Being bound as an associated type + +If a type parameter appears only in method signatures, not in the impl +parameters or the type being implemented for, you get this error.", + "\ +Параметр типа, константы или времени жизни, указанный для `impl`, +не ограничен. Rust требует, чтобы все параметры в `impl` были +ограничены появлением в реализуемом типе или трейте.", + "\ +`impl`에 지정된 타입, const 또는 수명 매개변수가 제약되지 않았습니다. +모든 매개변수는 구현 타입이나 트레이트에 나타나야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Move type parameter to method", + "Переместить параметр типа в метод", + "타입 매개변수를 메서드로 이동" + ), + code: "impl Foo {\n fn get(&self) -> T {\n T::default()\n }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use PhantomData to carry the type", + "Используйте PhantomData для переноса типа", + "PhantomData를 사용하여 타입 전달" + ), + code: "use std::marker::PhantomData;\n\nstruct Foo(PhantomData);\n\nimpl Foo {\n fn get(&self) -> T { T::default() }\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Implementations", + url: "https://doc.rust-lang.org/reference/items/implementations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0207.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0210.rs b/masterror-knowledge/src/errors/traits/e0210.rs new file mode 100644 index 0000000..4104de3 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0210.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0210: orphan rules violation + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0210", + title: LocalizedText::new( + "Orphan rules violation for trait implementation", + "Нарушение правил сирот при реализации трейта", + "트레이트 구현의 고아 규칙 위반" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +This error occurs when implementing a foreign trait for a foreign type +in a way that violates Rust's orphan rules. + +Type parameters must be 'covered' by a local type when implementing +a foreign trait. A local type must appear BEFORE any use of type +parameters in the trait implementation. + +For impl ForeignTrait for T0: +1. At least one of T0..=Tn must be a local type (Ti) +2. No uncovered type parameters may appear in T0..Ti (excluding Ti)", + "\ +Ошибка возникает при реализации внешнего трейта для внешнего типа +с нарушением правил сирот Rust. + +Параметры типов должны быть 'покрыты' локальным типом. +Локальный тип должен появиться ДО использования параметров типов.", + "\ +외부 트레이트를 외부 타입에 구현할 때 Rust의 고아 규칙을 위반하면 +이 오류가 발생합니다. 로컬 타입이 타입 매개변수보다 먼저 나타나야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Wrap the type parameter in a local type", + "Обернуть параметр типа в локальный тип", + "타입 매개변수를 로컬 타입으로 래핑" + ), + code: "struct MyType(T);\nimpl ForeignTrait for MyType { }" + }, + FixSuggestion { + description: LocalizedText::new( + "Put local type first in trait parameters", + "Поставить локальный тип первым в параметрах трейта", + "트레이트 매개변수에서 로컬 타입을 먼저 배치" + ), + code: "impl ForeignTrait2, T> for MyType2 { }" + } + ], + links: &[ + DocLink { + title: "Rust Book: Orphan Rule", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0210.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0220.rs b/masterror-knowledge/src/errors/traits/e0220.rs new file mode 100644 index 0000000..0b0158c --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0220.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0220: associated type not found in trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0220", + title: LocalizedText::new( + "Associated type not found in trait", + "Ассоциированный тип не найден в трейте", + "트레이트에서 연관 타입을 찾을 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +The associated type used was not defined in the trait. + +Common causes: +1. Using an associated type that doesn't exist +2. Misspelling the associated type name +3. Using the wrong trait + +Ensure that any associated type you use is properly declared in +the trait body using the `type` keyword.", + "\ +Используемый ассоциированный тип не был определён в трейте. + +Частые причины: +1. Использование несуществующего ассоциированного типа +2. Опечатка в имени ассоциированного типа +3. Использование неправильного трейта", + "\ +사용된 연관 타입이 트레이트에 정의되지 않았습니다. +연관 타입이 트레이트 본문에 `type` 키워드로 선언되었는지 확인하세요." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use correct associated type name", + "Используйте правильное имя ассоциированного типа", + "올바른 연관 타입 이름 사용" + ), + code: "trait T1 {\n type Bar;\n}\n\ntype Foo = T1; // use Bar, not F" + }, + FixSuggestion { + description: LocalizedText::new( + "Declare the associated type in trait", + "Объявите ассоциированный тип в трейте", + "트레이트에 연관 타입 선언" + ), + code: "trait T2 {\n type Bar;\n type Baz; // declare it\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Associated Types", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0220.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0221.rs b/masterror-knowledge/src/errors/traits/e0221.rs new file mode 100644 index 0000000..e253cd5 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0221.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0221: ambiguous associated type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0221", + title: LocalizedText::new( + "Ambiguous associated type", + "Неоднозначный ассоциированный тип", + "모호한 연관 타입" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated type is ambiguous due to multiple traits defining +associated types with the same name. + +When a trait inherits from another trait and both define an associated +type with the same name, using `Self::A` becomes ambiguous - the +compiler cannot determine which trait's associated type you're +referring to.", + "\ +Ассоциированный тип неоднозначен, так как несколько трейтов определяют +ассоциированные типы с одинаковым именем. + +Когда трейт наследует от другого трейта и оба определяют ассоциированный +тип с одинаковым именем, использование `Self::A` становится неоднозначным.", + "\ +여러 트레이트가 같은 이름의 연관 타입을 정의하여 연관 타입이 모호합니다. +`Self::A`를 사용할 때 컴파일러가 어떤 트레이트의 연관 타입인지 결정할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Rename one of the associated types", + "Переименуйте один из ассоциированных типов", + "연관 타입 중 하나의 이름 변경" + ), + code: "trait Bar : Foo {\n type B: T2; // renamed from A\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use fully qualified syntax", + "Используйте полностью квалифицированный синтаксис", + "완전 정규화 구문 사용" + ), + code: "fn do_something() {\n let _: ::A; // explicitly specify Bar's A\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Fully Qualified Syntax", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0221.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0222.rs b/masterror-knowledge/src/errors/traits/e0222.rs new file mode 100644 index 0000000..8ebd86d --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0222.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0222: invalid associated type constraint + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0222", + title: LocalizedText::new( + "Invalid associated type constraint", + "Недопустимое ограничение ассоциированного типа", + "잘못된 연관 타입 제약" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An attempt was made to constrain an associated type directly in a +function signature using the syntax `TraitName`, +which is not allowed in this context. + +When a trait inherits from multiple supertraits that define the same +associated type name, there's ambiguity. You cannot use the direct +constraint syntax in function parameters with trait objects.", + "\ +Была попытка ограничить ассоциированный тип напрямую в сигнатуре функции +с использованием синтаксиса `TraitName`, +что не допускается в этом контексте.", + "\ +함수 시그니처에서 `TraitName` 구문으로 연관 타입을 +직접 제약하려고 했으나, 이 컨텍스트에서는 허용되지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use where clause with type parameter", + "Используйте where с параметром типа", + "타입 매개변수와 where 절 사용" + ), + code: "fn foo(\n c: CAR,\n) where\n CAR: BoxCar,\n CAR: Vehicle,\n CAR: Box\n{}" + }], + links: &[ + DocLink { + title: "Rust Book: Trait Bounds", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#trait-bound-syntax" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0222.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0223.rs b/masterror-knowledge/src/errors/traits/e0223.rs new file mode 100644 index 0000000..9c759bc --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0223.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0223: ambiguous associated type retrieval + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0223", + title: LocalizedText::new( + "Ambiguous associated type retrieval", + "Неоднозначное получение ассоциированного типа", + "모호한 연관 타입 조회" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Attempting to retrieve an associated type from a trait directly is +ambiguous because the associated type is only made concrete in +specific implementations of the trait. + +Associated types are defined in traits but only have concrete types +when the trait is implemented for a specific struct or type. You +cannot access an associated type directly from the trait itself +without specifying which implementation you want.", + "\ +Попытка получить ассоциированный тип напрямую из трейта неоднозначна, +потому что ассоциированный тип становится конкретным только в +определённых реализациях трейта. + +Вы не можете получить доступ к ассоциированному типу напрямую из +трейта без указания конкретной реализации.", + "\ +트레이트에서 연관 타입을 직접 조회하는 것은 모호합니다. +연관 타입은 특정 구현에서만 구체적인 타입을 갖기 때문입니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use fully qualified syntax", + "Используйте полностью квалифицированный синтаксис", + "완전 정규화 구문 사용" + ), + code: "let foo: ::X;" + }], + links: &[ + DocLink { + title: "Rust Book: Fully Qualified Syntax", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0223.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0224.rs b/masterror-knowledge/src/errors/traits/e0224.rs new file mode 100644 index 0000000..ed7cf17 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0224.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0224: trait object with no traits + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0224", + title: LocalizedText::new( + "Trait object declared with no traits", + "Трейт-объект объявлен без трейтов", + "트레이트 없이 트레이트 객체 선언됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A trait object was declared with no traits. Rust requires that trait +objects must have at least one trait specified. + +The `dyn` keyword must be followed by at least one actual trait. +Having only a lifetime bound without any trait is not allowed.", + "\ +Трейт-объект был объявлен без трейтов. Rust требует, чтобы +трейт-объекты имели хотя бы один указанный трейт. + +За ключевым словом `dyn` должен следовать хотя бы один трейт.", + "\ +트레이트 없이 트레이트 객체가 선언되었습니다. +`dyn` 키워드 뒤에는 최소 하나의 트레이트가 지정되어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add at least one trait", + "Добавьте хотя бы один трейт", + "최소 하나의 트레이트 추가" + ), + code: "type Foo = dyn 'static + Copy;" + }], + links: &[ + DocLink { + title: "Rust Book: Trait Objects", + url: "https://doc.rust-lang.org/book/ch17-02-trait-objects.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0224.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0225.rs b/masterror-knowledge/src/errors/traits/e0225.rs new file mode 100644 index 0000000..3af8c2e --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0225.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0225: multiple non-auto trait bounds + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0225", + title: LocalizedText::new( + "Multiple non-auto traits in trait object", + "Несколько не-auto трейтов в трейт-объекте", + "트레이트 객체에 여러 non-auto 트레이트" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Multiple types were used as bounds for a closure or trait object. +Rust does not currently support using multiple non-auto trait types +as bounds for a trait object. + +You can only have ONE non-builtin trait as a bound for a trait object. +However, you CAN add any number of auto traits (Send, Sync, etc.) +in addition to that single trait.", + "\ +Несколько типов были использованы как ограничения для замыкания или +трейт-объекта. Rust не поддерживает множественные не-auto трейты +в качестве ограничений для трейт-объекта. + +Можно использовать только ОДИН не встроенный трейт, но можно добавить +любое количество auto-трейтов (Send, Sync и т.д.).", + "\ +클로저나 트레이트 객체에 여러 타입이 바운드로 사용되었습니다. +트레이트 객체에는 하나의 non-auto 트레이트만 바운드로 사용할 수 있습니다. +단, auto 트레이트(Send, Sync 등)는 추가로 사용할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use one non-auto trait with auto traits", + "Используйте один не-auto трейт с auto трейтами", + "하나의 non-auto 트레이트와 auto 트레이트 사용" + ), + code: "let _: Box;" + }], + links: &[ + DocLink { + title: "Rust Book: Trait Objects", + url: "https://doc.rust-lang.org/book/ch17-02-trait-objects.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0225.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0271.rs b/masterror-knowledge/src/errors/traits/e0271.rs new file mode 100644 index 0000000..8b522ac --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0271.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0271: type mismatch with associated types + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0271", + title: LocalizedText::new( + "Type mismatch with associated type", + "Несоответствие типов с ассоциированным типом", + "연관 타입과 타입 불일치" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A type mismatched an associated type of a trait. + +When a trait defines an associated type, implementations must assign +a concrete type. If you constrain a generic parameter with a specific +associated type requirement (e.g., `T: Trait`), +the actual type used must satisfy that constraint.", + "\ +Тип не соответствует ассоциированному типу трейта. + +Когда трейт определяет ассоциированный тип, реализации должны назначить +конкретный тип. Если вы ограничиваете параметр требованием к +ассоциированному типу, фактический тип должен удовлетворять этому +ограничению.", + "\ +타입이 트레이트의 연관 타입과 일치하지 않습니다. +연관 타입 요구사항을 충족하는 구현을 사용해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Change constraint to match implementation", + "Измените ограничение, чтобы соответствовать реализации", + "구현과 일치하도록 제약 변경" + ), + code: "fn foo(t: T) where T: Trait { }" + }, + FixSuggestion { + description: LocalizedText::new( + "Change implementation to match constraint", + "Измените реализацию, чтобы соответствовать ограничению", + "제약과 일치하도록 구현 변경" + ), + code: "impl Trait for i8 { type AssociatedType = u32; }" + } + ], + links: &[ + DocLink { + title: "Rust Book: Associated Types", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0271.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0275.rs b/masterror-knowledge/src/errors/traits/e0275.rs new file mode 100644 index 0000000..7624805 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0275.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0275: trait requirement overflow + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0275", + title: LocalizedText::new( + "Trait requirement overflow", + "Переполнение требований трейта", + "트레이트 요구사항 오버플로우" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An evaluation of a trait requirement overflows due to infinite recursion. + +The error happens when there is an unbounded recursion in resolving +type bounds that creates a circular dependency, causing the trait +resolution process to loop infinitely. + +Example: impl Foo for T where Bar: Foo +- To check if T implements Foo, compiler checks if Bar implements Foo +- To check Bar, it checks if Bar> implements Foo +- This continues infinitely...", + "\ +Оценка требования трейта переполняется из-за бесконечной рекурсии. + +Ошибка возникает при неограниченной рекурсии в разрешении ограничений +типов, создающей циклическую зависимость.", + "\ +트레이트 요구사항 평가가 무한 재귀로 인해 오버플로우됩니다. +타입 바운드 해결에서 순환 종속성이 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove self-referential trait bounds", + "Удалите самоссылающиеся ограничения трейтов", + "자기 참조 트레이트 바운드 제거" + ), + code: "trait Foo {}\n\nimpl Foo for i32 {} // concrete implementation instead" + }], + links: &[ + DocLink { + title: "Rust Reference: Trait Bounds", + url: "https://doc.rust-lang.org/reference/trait-bounds.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0275.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0276.rs b/masterror-knowledge/src/errors/traits/e0276.rs new file mode 100644 index 0000000..241ee5e --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0276.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0276: trait implementation has stricter requirements + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0276", + title: LocalizedText::new( + "Trait implementation has stricter requirements", + "Реализация трейта имеет более строгие требования", + "트레이트 구현이 더 엄격한 요구사항을 가짐" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A trait implementation has stricter requirements than the trait definition. + +This error occurs when a trait implementation adds additional trait +bounds to a method that aren't present in the original trait definition, +making the implementation stricter than the contract defined by the trait. + +The implementation must honor the original trait contract without +introducing additional constraints.", + "\ +Реализация трейта имеет более строгие требования, чем определение трейта. + +Ошибка возникает, когда реализация трейта добавляет дополнительные +ограничения трейтов к методу, которых нет в исходном определении трейта.", + "\ +트레이트 구현이 트레이트 정의보다 더 엄격한 요구사항을 가집니다. +구현은 원래 트레이트 계약을 준수해야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove extra bounds from implementation", + "Удалите дополнительные ограничения из реализации", + "구현에서 추가 바운드 제거" + ), + code: "impl Foo for bool {\n fn foo(x: T) {} // no extra where clause\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Add bounds to original trait definition", + "Добавьте ограничения в исходное определение трейта", + "원래 트레이트 정의에 바운드 추가" + ), + code: "trait Foo {\n fn foo(x: T); // add bound to trait\n}" + } + ], + links: &[ + DocLink { + title: "Rust Book: Trait Implementations", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0276.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0282.rs b/masterror-knowledge/src/errors/traits/e0282.rs new file mode 100644 index 0000000..1861285 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0282.rs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0282", + title: LocalizedText::new( + "Type annotations needed", + "Требуются аннотации типа", + "타입 어노테이션이 필요함" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "The compiler cannot infer the type. Provide an explicit type annotation.", + "Компилятор не может вывести тип. Укажите явную аннотацию типа.", + "컴파일러가 타입을 추론할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add type annotation", + "Добавить аннотацию", + "타입 어노테이션 추가" + ), + code: "let numbers: Vec = input.parse().unwrap();" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0282.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0321.rs b/masterror-knowledge/src/errors/traits/e0321.rs new file mode 100644 index 0000000..0ceca73 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0321.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0321: cross-crate opt-out trait implemented on invalid type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0321", + title: LocalizedText::new( + "Cross-crate opt-out trait on invalid type", + "Cross-crate opt-out трейт на недопустимом типе", + "잘못된 타입에 대한 크로스 크레이트 opt-out 트레이트" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A cross-crate opt-out trait (like Send or Sync from core::marker) was +implemented on something that isn't a struct or enum type. + +Only structs and enums are permitted to implement Send, Sync, and other +opt-out traits. The struct or enum must be local to the current crate. +Generic types or references to external types cannot implement these traits.", + "\ +Cross-crate opt-out трейт (например Send или Sync из core::marker) был +реализован на чём-то, что не является структурой или перечислением. + +Только структуры и перечисления могут реализовывать Send, Sync и другие +opt-out трейты. Тип должен быть локальным для текущего крейта.", + "\ +크로스 크레이트 opt-out 트레이트(core::marker의 Send, Sync 등)가 +구조체나 열거형이 아닌 타입에 구현되었습니다. + +Send, Sync 및 기타 opt-out 트레이트는 구조체와 열거형만 구현할 수 있습니다. +구조체나 열거형은 현재 크레이트에 로컬이어야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Implement on local struct or enum type only", + "Реализовать только на локальных структурах/enum", + "로컬 구조체 또는 열거형 타입에만 구현" + ), + code: "struct Foo;\n\nimpl !Sync for Foo {} // ok - local struct" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Send and Sync", + url: "https://doc.rust-lang.org/nomicon/send-and-sync.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0321.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0322.rs b/masterror-knowledge/src/errors/traits/e0322.rs new file mode 100644 index 0000000..6484a10 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0322.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0322: built-in trait cannot be explicitly implemented + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0322", + title: LocalizedText::new( + "Built-in trait cannot be explicitly implemented", + "Встроенный трейт нельзя реализовать явно", + "내장 트레이트는 명시적으로 구현할 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +All implementations of built-in traits are provided automatically by the +compiler. Built-in traits cannot be explicitly implemented by user code. + +The Sized trait is a special trait built into the compiler for types with +a constant size known at compile-time. This trait is automatically implemented +for types as needed by the compiler.", + "\ +Все реализации встроенных трейтов предоставляются автоматически компилятором. +Встроенные трейты нельзя явно реализовать в пользовательском коде. + +Трейт Sized - специальный встроенный трейт для типов с известным на этапе +компиляции постоянным размером. Он автоматически реализуется компилятором.", + "\ +내장 트레이트의 모든 구현은 컴파일러가 자동으로 제공합니다. +내장 트레이트는 사용자 코드에서 명시적으로 구현할 수 없습니다. + +Sized 트레이트는 컴파일 시점에 상수 크기가 알려진 타입을 위한 +컴파일러에 내장된 특별한 트레이트입니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove the explicit implementation", + "Удалить явную реализацию", + "명시적 구현 제거" + ), + code: "struct Foo;\n// impl Sized for Foo {} // Remove this - compiler handles it" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Sized Trait", + url: "https://doc.rust-lang.org/std/marker/trait.Sized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0322.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0323.rs b/masterror-knowledge/src/errors/traits/e0323.rs new file mode 100644 index 0000000..c68da51 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0323.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0323: associated const implemented when type expected + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0323", + title: LocalizedText::new( + "Associated const implemented when type expected", + "Реализована константа вместо ожидаемого типа", + "타입이 예상되었지만 연관 상수가 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated constant (const) was implemented in a trait implementation, +but the trait definition expects a different kind of associated item +(typically an associated type). + +The item name exists in the trait, but it's defined as a type, not a const.", + "\ +Ассоциированная константа (const) была реализована в реализации трейта, +но определение трейта ожидает другой вид ассоциированного элемента +(обычно ассоциированный тип). + +Имя элемента существует в трейте, но определено как тип, а не константа.", + "\ +연관 상수(const)가 트레이트 구현에서 구현되었지만, 트레이트 정의는 +다른 종류의 연관 항목(일반적으로 연관 타입)을 예상합니다. + +항목 이름이 트레이트에 존재하지만 const가 아닌 type으로 정의되어 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use type instead of const if trait expects type", + "Использовать type вместо const", + "트레이트가 타입을 예상하면 const 대신 type 사용" + ), + code: "trait Foo {\n type N;\n}\n\nimpl Foo for Bar {\n type N = u32; // not const N\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Associated Types", + url: "https://doc.rust-lang.org/reference/items/associated-items.html#associated-types" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0323.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0324.rs b/masterror-knowledge/src/errors/traits/e0324.rs new file mode 100644 index 0000000..85911c8 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0324.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0324: method implemented when another trait item expected + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0324", + title: LocalizedText::new( + "Method implemented when another trait item expected", + "Реализован метод вместо ожидаемого элемента трейта", + "다른 트레이트 항목이 예상되었지만 메서드가 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A method was implemented when another trait item was expected. +This happens when you implement a trait item with the wrong kind of definition. + +For example, if a trait declares N as a constant (const N: u32), but the +implementation defines it as a method (fn N() {}), this error occurs.", + "\ +Метод был реализован, когда ожидался другой элемент трейта. +Это происходит, когда вы реализуете элемент трейта с неправильным определением. + +Например, если трейт объявляет N как константу (const N: u32), а реализация +определяет его как метод (fn N() {}), возникает эта ошибка.", + "\ +다른 트레이트 항목이 예상되었지만 메서드가 구현되었습니다. +트레이트 항목을 잘못된 종류의 정의로 구현할 때 발생합니다. + +예를 들어, 트레이트가 N을 상수(const N: u32)로 선언했지만 +구현이 메서드(fn N() {})로 정의하면 이 오류가 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Match the trait definition - use const for const, fn for fn", + "Соответствовать определению трейта", + "트레이트 정의에 맞추기 - const에는 const, fn에는 fn" + ), + code: "trait Foo {\n const N: u32;\n fn M();\n}\n\nimpl Foo for Bar {\n const N: u32 = 0; // const, not fn\n fn M() {}\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Trait Implementations", + url: "https://doc.rust-lang.org/reference/items/implementations.html#trait-implementations" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0324.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0325.rs b/masterror-knowledge/src/errors/traits/e0325.rs new file mode 100644 index 0000000..139bf80 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0325.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0325: associated type implemented when const expected + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0325", + title: LocalizedText::new( + "Associated type implemented when const expected", + "Реализован тип вместо ожидаемой константы", + "상수가 예상되었지만 연관 타입이 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated type was implemented in a trait implementation, but the trait +definition expects a constant. The item name exists in the trait, but it's +defined as a const, not a type. + +Verify that the trait item name isn't misspelled and ensure your implementation +matches the exact kind of item defined in the trait.", + "\ +Ассоциированный тип был реализован в реализации трейта, но определение трейта +ожидает константу. Имя элемента существует в трейте, но определено как const, +а не type. + +Проверьте правильность написания имени и соответствие типа элемента.", + "\ +연관 타입이 트레이트 구현에서 구현되었지만, 트레이트 정의는 상수를 예상합니다. +항목 이름이 트레이트에 존재하지만 type이 아닌 const로 정의되어 있습니다. + +트레이트 항목 이름의 철자가 맞는지 확인하고 구현이 트레이트에 정의된 +정확한 종류의 항목과 일치하는지 확인하세요." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use const instead of type if trait expects const", + "Использовать const вместо type", + "트레이트가 const를 예상하면 type 대신 const 사용" + ), + code: "trait Foo {\n const N: u32;\n}\n\nimpl Foo for Bar {\n const N: u32 = 0; // not type N = u32\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Associated Constants", + url: "https://doc.rust-lang.org/reference/items/associated-items.html#associated-constants" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0325.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0326.rs b/masterror-knowledge/src/errors/traits/e0326.rs new file mode 100644 index 0000000..294ccb6 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0326.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0326: associated constant type doesn't match trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0326", + title: LocalizedText::new( + "Associated constant type doesn't match trait", + "Тип ассоциированной константы не соответствует трейту", + "연관 상수 타입이 트레이트와 일치하지 않음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +When implementing a trait, any associated constants must have types that +exactly match the types declared in the trait definition. If the type of +an associated constant in the implementation differs from the trait +definition, this error is raised. + +Example: trait declares const BAR: bool but implementation uses const BAR: u32.", + "\ +При реализации трейта все ассоциированные константы должны иметь типы, +точно соответствующие типам в определении трейта. Если тип константы +в реализации отличается от определения трейта, возникает эта ошибка. + +Пример: трейт объявляет const BAR: bool, а реализация использует const BAR: u32.", + "\ +트레이트를 구현할 때 모든 연관 상수의 타입은 트레이트 정의에 선언된 +타입과 정확히 일치해야 합니다. 구현의 연관 상수 타입이 트레이트 정의와 +다르면 이 오류가 발생합니다. + +예: 트레이트가 const BAR: bool을 선언했지만 구현이 const BAR: u32를 사용함." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Match the type from trait definition", + "Соответствовать типу из определения трейта", + "트레이트 정의의 타입과 일치시키기" + ), + code: "trait Foo {\n const BAR: bool;\n}\n\nimpl Foo for Bar {\n const BAR: bool = true; // matches trait\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Associated Constants", + url: "https://doc.rust-lang.org/reference/items/associated-items.html#associated-constants" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0326.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0328.rs b/masterror-knowledge/src/errors/traits/e0328.rs new file mode 100644 index 0000000..83165c7 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0328.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0328: Unsize trait should not be implemented directly + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0328", + title: LocalizedText::new( + "Unsize trait should not be implemented directly", + "Трейт Unsize не должен реализовываться напрямую", + "Unsize 트레이트는 직접 구현하면 안 됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +The Unsize trait is automatically implemented by the compiler and should +not be manually implemented by users. All implementations of Unsize are +provided automatically. + +If you're defining a custom smart pointer type and want to enable conversion +from a sized to an unsized type, use CoerceUnsized instead.", + "\ +Трейт Unsize автоматически реализуется компилятором и не должен +реализовываться вручную пользователями. + +Если вы определяете собственный умный указатель и хотите включить +преобразование из sized в unsized тип, используйте CoerceUnsized.", + "\ +Unsize 트레이트는 컴파일러가 자동으로 구현하며 사용자가 직접 +구현해서는 안 됩니다. + +사용자 정의 스마트 포인터 타입을 정의하고 sized에서 unsized 타입으로의 +변환을 활성화하려면 대신 CoerceUnsized를 사용하세요." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use CoerceUnsized instead of Unsize", + "Использовать CoerceUnsized вместо Unsize", + "Unsize 대신 CoerceUnsized 사용" + ), + code: "#![feature(coerce_unsized)]\nuse std::ops::CoerceUnsized;\n\npub struct MyType {\n field: T,\n}\n\nimpl CoerceUnsized> for MyType\n where T: CoerceUnsized {}" + } + ], + links: &[ + DocLink { + title: "Rust std::ops::CoerceUnsized", + url: "https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0328.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0371.rs b/masterror-knowledge/src/errors/traits/e0371.rs new file mode 100644 index 0000000..8742187 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0371.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0371: trait implemented on another that already automatically implements it + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0371", + title: LocalizedText::new( + "Trait already automatically implements supertrait", + "Трейт уже автоматически реализует супертрейт", + "트레이트가 이미 슈퍼트레이트를 자동으로 구현함" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +When Trait2 is a subtrait of Trait1 (defined as trait Trait2: Trait1 { ... }), +it is not allowed to implement Trait1 for Trait2. This is because Trait2 +already automatically implements Trait1 by definition through inheritance, +making an explicit implementation redundant and not useful. + +Example: impl Bar for Baz {} is invalid if trait Baz: Bar {}.", + "\ +Когда Trait2 является подтрейтом Trait1 (trait Trait2: Trait1 { ... }), +нельзя реализовать Trait1 для Trait2. Trait2 уже автоматически реализует +Trait1 по определению через наследование, делая явную реализацию избыточной. + +Пример: impl Bar for Baz {} недопустим, если trait Baz: Bar {}.", + "\ +Trait2가 Trait1의 서브트레이트일 때(trait Trait2: Trait1 { ... }로 정의), +Trait2에 대해 Trait1을 구현하는 것은 허용되지 않습니다. Trait2는 이미 +상속을 통해 정의상 Trait1을 자동으로 구현하므로 명시적 구현은 중복됩니다. + +예: trait Baz: Bar {}이면 impl Bar for Baz {}는 유효하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove redundant implementation", + "Удалить избыточную реализацию", + "중복 구현 제거" + ), + code: "trait Foo { fn foo(&self) {} }\ntrait Bar: Foo {}\ntrait Baz: Bar {}\n\n// impl Bar for Baz {} // Remove - already implemented\n// impl Foo for Baz {} // Remove - already implemented via Bar" + } + ], + links: &[ + DocLink { + title: "Rust Book: Supertraits", + url: "https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-supertraits-to-require-one-traits-functionality-within-another-trait" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0371.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0374.rs b/masterror-knowledge/src/errors/traits/e0374.rs new file mode 100644 index 0000000..9d9aa13 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0374.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0374: CoerceUnsized on struct without unsized fields + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0374", + title: LocalizedText::new( + "CoerceUnsized on struct without unsized fields", + "CoerceUnsized на структуре без unsized полей", + "unsized 필드가 없는 구조체에 CoerceUnsized" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +CoerceUnsized or DispatchFromDyn was implemented on a struct that doesn't +contain any fields that are being unsized. + +CoerceUnsized is used to coerce structs with unsizable fields (e.g., +MyBox to MyBox). If a struct has no unsized fields, there +is no meaningful coercion to perform, making the trait implementation invalid. + +These traits are primarily used by smart pointers like Box, Rc, and Arc.", + "\ +CoerceUnsized или DispatchFromDyn был реализован на структуре, которая не +содержит полей, которые делаются unsized. + +CoerceUnsized используется для приведения структур с unsized полями. +Если структура не имеет unsized полей, нет осмысленного приведения, +делая реализацию трейта недействительной.", + "\ +CoerceUnsized 또는 DispatchFromDyn이 unsized 필드가 없는 구조체에 구현되었습니다. + +CoerceUnsized는 unsized 필드가 있는 구조체를 강제 변환하는 데 사용됩니다 +(예: MyBox를 MyBox로). 구조체에 unsized 필드가 없으면 +수행할 의미있는 강제 변환이 없어 트레이트 구현이 유효하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add an unsized field to the struct", + "Добавить unsized поле в структуру", + "구조체에 unsized 필드 추가" + ), + code: "#![feature(coerce_unsized)]\nuse std::ops::CoerceUnsized;\n\nstruct Foo {\n a: i32,\n b: T, // unsized field\n}\n\nimpl CoerceUnsized> for Foo\n where T: CoerceUnsized {}" + } + ], + links: &[ + DocLink { + title: "Rust std::ops::CoerceUnsized", + url: "https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0374.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0375.rs b/masterror-knowledge/src/errors/traits/e0375.rs new file mode 100644 index 0000000..0b55f62 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0375.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0375: CoerceUnsized with multiple unsized fields + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0375", + title: LocalizedText::new( + "CoerceUnsized with multiple unsized fields", + "CoerceUnsized с несколькими unsized полями", + "여러 unsized 필드가 있는 CoerceUnsized" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +CoerceUnsized or DispatchFromDyn was implemented on a struct that contains +more than one field that is being unsized. + +CoerceUnsized is designed to coerce structs with a single unsized field. +When multiple fields can be unsized, the compiler cannot generate a valid +implementation because it doesn't know which field(s) to coerce. + +These traits are typically used by smart pointers like Box, Rc, and Arc.", + "\ +CoerceUnsized или DispatchFromDyn был реализован на структуре с более чем +одним полем, которое делается unsized. + +CoerceUnsized предназначен для приведения структур с одним unsized полем. +Когда несколько полей могут быть unsized, компилятор не может сгенерировать +корректную реализацию.", + "\ +CoerceUnsized 또는 DispatchFromDyn이 둘 이상의 unsized 필드가 있는 +구조체에 구현되었습니다. + +CoerceUnsized는 단일 unsized 필드가 있는 구조체를 강제 변환하도록 설계되었습니다. +여러 필드가 unsized될 수 있을 때 컴파일러는 어떤 필드를 강제 변환할지 알 수 없어 +유효한 구현을 생성할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Ensure struct has only one unsized field", + "Убедитесь, что структура имеет только одно unsized поле", + "구조체에 unsized 필드가 하나만 있도록 보장" + ), + code: "struct Foo {\n a: i32,\n b: T, // only one unsized field\n}" + } + ], + links: &[ + DocLink { + title: "Rust std::ops::CoerceUnsized", + url: "https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0375.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0376.rs b/masterror-knowledge/src/errors/traits/e0376.rs new file mode 100644 index 0000000..8b80979 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0376.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0376: CoerceUnsized implemented between non-struct types + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0376", + title: LocalizedText::new( + "CoerceUnsized implemented between non-struct types", + "CoerceUnsized реализован между не-struct типами", + "비구조체 타입 간에 CoerceUnsized가 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +CoerceUnsized or DispatchFromDyn was implemented between types that are not +structs. These traits can only be implemented between structs. + +Both the source and target types of the implementation must be structs. +This error occurs when trying to implement these traits for generic type +parameters, references, or other non-struct types.", + "\ +CoerceUnsized или DispatchFromDyn был реализован между типами, которые не +являются структурами. Эти трейты могут быть реализованы только между структурами. + +И исходный, и целевой типы реализации должны быть структурами.", + "\ +CoerceUnsized 또는 DispatchFromDyn이 구조체가 아닌 타입 간에 구현되었습니다. +이러한 트레이트는 구조체 간에만 구현될 수 있습니다. + +구현의 소스 타입과 대상 타입 모두 구조체여야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Implement only between struct types", + "Реализовать только между struct типами", + "구조체 타입 간에만 구현" + ), + code: "#![feature(coerce_unsized)]\nuse std::ops::CoerceUnsized;\n\nstruct Foo { a: T }\nstruct Bar { a: T }\n\n// impl CoerceUnsized for Foo {} // Error: U is not a struct\nimpl CoerceUnsized> for Foo\n where T: CoerceUnsized {} // OK: both are structs" + } + ], + links: &[ + DocLink { + title: "Rust std::ops::CoerceUnsized", + url: "https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0376.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0377.rs b/masterror-knowledge/src/errors/traits/e0377.rs new file mode 100644 index 0000000..d3090ac --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0377.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0377: CoerceUnsized may only be implemented between same struct + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0377", + title: LocalizedText::new( + "CoerceUnsized only between same struct type", + "CoerceUnsized только между одинаковыми struct типами", + "CoerceUnsized는 동일한 구조체 타입 간에만 가능" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +CoerceUnsized or DispatchFromDyn was implemented between different struct types. +These traits can only be validly implemented between the same struct with +different generic parameters, not between entirely different structs. + +Example: impl CoerceUnsized> for Foo is invalid because Foo and Bar +are different struct types. It should be Foo to Foo.", + "\ +CoerceUnsized или DispatchFromDyn был реализован между разными типами структур. +Эти трейты могут быть корректно реализованы только между одной и той же +структурой с разными параметрами, не между разными структурами. + +Пример: impl CoerceUnsized> for Foo недопустим.", + "\ +CoerceUnsized 또는 DispatchFromDyn이 서로 다른 구조체 타입 간에 구현되었습니다. +이러한 트레이트는 완전히 다른 구조체 간이 아니라 다른 제네릭 매개변수를 가진 +동일한 구조체 간에만 유효하게 구현될 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Implement between same struct with different type params", + "Реализовать между одной структурой с разными параметрами", + "다른 타입 매개변수를 가진 동일한 구조체 간에 구현" + ), + code: "#![feature(coerce_unsized)]\nuse std::ops::CoerceUnsized;\n\nstruct Foo { field: T }\n\nimpl CoerceUnsized> for Foo\n where T: CoerceUnsized {}" + } + ], + links: &[ + DocLink { + title: "Rust std::ops::CoerceUnsized", + url: "https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0377.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0378.rs b/masterror-knowledge/src/errors/traits/e0378.rs new file mode 100644 index 0000000..67f1cbf --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0378.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0378: DispatchFromDyn trait implemented on invalid type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0378", + title: LocalizedText::new( + "DispatchFromDyn on invalid type", + "DispatchFromDyn на недопустимом типе", + "잘못된 타입에 DispatchFromDyn" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +The DispatchFromDyn trait was implemented on something which is not a pointer +or a newtype wrapper around a pointer. + +DispatchFromDyn can only be implemented for: +- Built-in pointer types +- Structs that are newtype wrappers around pointers (single field, except + PhantomData, where that field implements DispatchFromDyn)", + "\ +Трейт DispatchFromDyn был реализован на чём-то, что не является указателем +или newtype обёрткой вокруг указателя. + +DispatchFromDyn может быть реализован только для: +- Встроенных типов указателей +- Структур-обёрток вокруг указателей (одно поле, кроме PhantomData)", + "\ +DispatchFromDyn 트레이트가 포인터나 포인터를 감싸는 newtype 래퍼가 아닌 +타입에 구현되었습니다. + +DispatchFromDyn은 다음에만 구현될 수 있습니다: +- 내장 포인터 타입 +- 포인터를 감싸는 newtype 래퍼 구조체(PhantomData를 제외한 단일 필드)" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Implement on pointer wrapper with single field", + "Реализовать на обёртке указателя с одним полем", + "단일 필드가 있는 포인터 래퍼에 구현" + ), + code: "#![feature(dispatch_from_dyn, unsize)]\nuse std::{marker::Unsize, ops::DispatchFromDyn};\n\nstruct Ptr(*const T);\n\nimpl DispatchFromDyn> for Ptr\nwhere T: Unsize {}" + } + ], + links: &[ + DocLink { + title: "Rust std::ops::DispatchFromDyn", + url: "https://doc.rust-lang.org/std/ops/trait.DispatchFromDyn.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0378.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0379.rs b/masterror-knowledge/src/errors/traits/e0379.rs new file mode 100644 index 0000000..5cb9b51 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0379.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0379: trait method declared const + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0379", + title: LocalizedText::new( + "Trait method cannot be declared const", + "Метод трейта не может быть объявлен const", + "트레이트 메서드는 const로 선언할 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Trait methods cannot be declared as const by design. This is a fundamental +restriction in Rust's type system. + +The const qualifier is not allowed on trait method declarations or their +implementations. For details, see RFC 911.", + "\ +Методы трейтов не могут быть объявлены как const по дизайну. Это фундаментальное +ограничение в системе типов Rust. + +Квалификатор const не разрешён в объявлениях методов трейтов или их реализациях.", + "\ +트레이트 메서드는 설계상 const로 선언할 수 없습니다. 이는 Rust 타입 시스템의 +근본적인 제한입니다. + +const 한정자는 트레이트 메서드 선언이나 그 구현에 허용되지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove const keyword from trait method", + "Удалить const из метода трейта", + "트레이트 메서드에서 const 키워드 제거" + ), + code: "trait Foo {\n fn bar() -> u32; // not const fn\n}\n\nimpl Foo for () {\n fn bar() -> u32 { 0 }\n}" + } + ], + links: &[ + DocLink { + title: "RFC 911: const_fn", + url: "https://github.com/rust-lang/rfcs/pull/911" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0379.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0380.rs b/masterror-knowledge/src/errors/traits/e0380.rs new file mode 100644 index 0000000..db13331 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0380.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0380: auto trait declared with method or associated item + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0380", + title: LocalizedText::new( + "Auto trait cannot have methods or associated items", + "Auto trait не может иметь методы или ассоциированные элементы", + "auto trait는 메서드나 연관 항목을 가질 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Auto traits cannot have methods or associated items. They are special traits +designed to be automatically implemented for types that meet certain criteria, +and they cannot define any members. + +Auto traits like Send and Sync are implemented automatically by the compiler +based on the type's structure.", + "\ +Auto traits не могут иметь методы или ассоциированные элементы. Это специальные +трейты, предназначенные для автоматической реализации для типов, соответствующих +определённым критериям, и они не могут определять никаких членов. + +Auto traits как Send и Sync реализуются автоматически компилятором.", + "\ +auto trait는 메서드나 연관 항목을 가질 수 없습니다. 특정 기준을 충족하는 타입에 +자동으로 구현되도록 설계된 특별한 트레이트이며, 어떤 멤버도 정의할 수 없습니다. + +Send와 Sync 같은 auto trait는 타입의 구조에 따라 컴파일러가 자동으로 구현합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove methods and associated items from auto trait", + "Удалить методы и элементы из auto trait", + "auto trait에서 메서드와 연관 항목 제거" + ), + code: "unsafe auto trait MyTrait {\n // Empty - no methods or associated items allowed\n}" + } + ], + links: &[ + DocLink { + title: "RFC 19: Opt-in Builtin Traits", + url: "https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0380.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0390.rs b/masterror-knowledge/src/errors/traits/e0390.rs new file mode 100644 index 0000000..f1c6994 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0390.rs @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0390: cannot define inherent impl for primitive types + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0390", + title: LocalizedText::new( + "Cannot define inherent impl for primitive types", + "Нельзя определить inherent impl для примитивных типов", + "기본 타입에 대한 고유 impl을 정의할 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A method or constant was implemented on a primitive type using an inherent +implementation (direct impl block). This is not allowed in Rust. + +You cannot create inherent implementations directly on primitive types like +raw pointers (*mut Foo). Rust restricts this to prevent conflicts and +maintain type system coherence. + +Use a trait implementation instead, or for references, move the reference +into the method signature.", + "\ +Метод или константа была реализована на примитивном типе с использованием +inherent реализации (прямой impl блок). Это не разрешено в Rust. + +Нельзя создавать inherent реализации на примитивных типах как сырые указатели. +Используйте реализацию трейта вместо этого.", + "\ +메서드나 상수가 고유 구현(직접 impl 블록)을 사용하여 기본 타입에 구현되었습니다. +이는 Rust에서 허용되지 않습니다. + +원시 포인터(*mut Foo)와 같은 기본 타입에 직접 고유 구현을 만들 수 없습니다. +대신 트레이트 구현을 사용하세요." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a trait implementation instead", + "Использовать реализацию трейта вместо этого", + "대신 트레이트 구현 사용" + ), + code: "struct Foo { x: i32 }\n\ntrait Bar {\n fn bar();\n}\n\nimpl Bar for *mut Foo {\n fn bar() {} // ok!\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Move reference into method signature", + "Переместить ссылку в сигнатуру метода", + "참조를 메서드 시그니처로 이동" + ), + code: "struct Foo;\n\nimpl Foo {\n fn bar(&self, other: &Self) {} // not impl &Foo\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Implementations", + url: "https://doc.rust-lang.org/reference/items/implementations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0390.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0404.rs b/masterror-knowledge/src/errors/traits/e0404.rs new file mode 100644 index 0000000..162c01b --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0404.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0404: expected trait, found type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0404", + title: LocalizedText::new( + "Expected trait, found type", + "Ожидался трейт, найден тип", + "트레이트가 예상되었으나 타입이 발견됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A type that is not a trait was used in a trait position, such as a bound +or impl declaration. Traits are required in certain contexts like: +- Trait bounds: +- impl declarations: impl SomeType for MyStruct + +Using a struct or type alias in these positions is invalid.", + "\ +Тип, не являющийся трейтом, использован там, где ожидается трейт, +например, в ограничении или объявлении impl. Трейты требуются в: +- Ограничениях типа: +- Объявлениях impl: impl SomeType for MyStruct", + "\ +트레이트가 아닌 타입이 트레이트 위치에 사용되었습니다. 트레이트는 +다음 컨텍스트에서 필요합니다: +- 트레이트 바운드: +- impl 선언: impl SomeType for MyStruct" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Define an actual trait", + "Определить настоящий трейт", + "실제 트레이트 정의" + ), + code: "trait Foo { }\nstruct Bar;\nimpl Foo for Bar { }" + }, + FixSuggestion { + description: LocalizedText::new( + "Use trait alias (nightly)", + "Использовать псевдоним трейта (nightly)", + "트레이트 별칭 사용 (nightly)" + ), + code: "#![feature(trait_alias)]\ntrait Foo = Iterator;\nfn bar(t: T) {}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0404.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0404.rs.bak b/masterror-knowledge/src/errors/traits/e0404.rs.bak new file mode 100644 index 0000000..697ffbc --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0404.rs.bak @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0404: expected trait, found type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0404", + title: LocalizedText::new( + "Expected trait, found type", + "Ожидался трейт, найден тип", + "트레이트가 예상되었으나 타입이 발견됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A type that is not a trait was used in a trait position, such as a bound +or impl declaration. Traits are required in certain contexts like: +- Trait bounds: +- impl declarations: impl SomeType for MyStruct + +Using a struct or type alias in these positions is invalid.", + "\ +Тип, не являющийся трейтом, использован там, где ожидается трейт, +например, в ограничении или объявлении impl. Трейты требуются в: +- Ограничениях типа: +- Объявлениях impl: impl SomeType for MyStruct", + "\ +트레이트가 아닌 타입이 트레이트 위치에 사용되었습니다. 트레이트는 +다음 컨텍스트에서 필요합니다: +- 트레이트 바운드: +- impl 선언: impl SomeType for MyStruct" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Define an actual trait", + "Определить настоящий трейт", + "실제 트레이트 정의" + ), + code: "trait Foo { }\nstruct Bar;\nimpl Foo for Bar { }" + }, + FixSuggestion { + description: LocalizedText::new( + "Use trait alias (nightly)", + "Использовать псевдоним трейта (nightly)", + "트레이트 별칭 사용 (nightly)" + ), + code: "#![feature(trait_alias)]\ntrait Foo = Iterator;\nfn bar(t: T) {}" + } + ], + links: &[ + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0404.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0405.rs b/masterror-knowledge/src/errors/traits/e0405.rs new file mode 100644 index 0000000..6b873f0 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0405.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0405: trait not in scope + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0405", + title: LocalizedText::new( + "Trait not in scope", + "Трейт не в области видимости", + "트레이트가 스코프에 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An attempt was made to implement a trait that hasn't been imported or +defined in the current scope. The compiler cannot find the trait you're +referencing. + +This can happen due to: +- Misspelled trait name +- Missing import statement +- Trait defined in a different module", + "\ +Попытка реализовать трейт, который не импортирован или не определён +в текущей области видимости. Компилятор не может найти трейт. + +Это может произойти из-за: +- Опечатки в имени трейта +- Отсутствия оператора use +- Трейт определён в другом модуле", + "\ +현재 스코프에 가져오거나 정의되지 않은 트레이트를 구현하려고 +시도했습니다. 컴파일러가 참조하는 트레이트를 찾을 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Import the trait with use statement", + "Импортировать трейт с помощью use", + "use 문으로 트레이트 가져오기" + ), + code: "use some_module::SomeTrait;\n\nimpl SomeTrait for Foo { }" + }, + FixSuggestion { + description: LocalizedText::new( + "Define the trait in current scope", + "Определить трейт в текущей области видимости", + "현재 스코프에 트레이트 정의" + ), + code: "trait SomeTrait {\n // methods\n}\n\nimpl SomeTrait for Foo { }" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0405.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0407.rs b/masterror-knowledge/src/errors/traits/e0407.rs new file mode 100644 index 0000000..d0d58e5 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0407.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0407: method not in trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0407", + title: LocalizedText::new( + "Method not a member of trait", + "Метод не является членом трейта", + "메서드가 트레이트의 멤버가 아님" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A method was defined in a trait implementation that doesn't exist in the +trait definition itself. When implementing a trait, you can only define +methods that are declared in the trait.", + "\ +В реализации трейта определён метод, которого нет в определении трейта. +При реализации трейта можно определять только те методы, которые +объявлены в трейте.", + "\ +트레이트 구현에서 트레이트 정의에 존재하지 않는 메서드가 정의되었습니다. +트레이트를 구현할 때는 트레이트에 선언된 메서드만 정의할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add the method to the trait definition", + "Добавить метод в определение трейта", + "트레이트 정의에 메서드 추가" + ), + code: "trait Foo {\n fn a();\n fn b(); // Add missing method\n}\n\nimpl Foo for Bar {\n fn a() {}\n fn b() {}\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Implement in a separate impl block", + "Реализовать в отдельном блоке impl", + "별도의 impl 블록에서 구현" + ), + code: "impl Foo for Bar {\n fn a() {}\n}\n\nimpl Bar {\n fn b() {} // Separate impl for extra methods\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0407.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0437.rs b/masterror-knowledge/src/errors/traits/e0437.rs new file mode 100644 index 0000000..b07fb52 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0437.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0437: associated type not in trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0437", + title: LocalizedText::new( + "Associated type not in trait", + "Ассоциированный тип не в трейте", + "연관 타입이 트레이트에 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated type was defined in a trait implementation that doesn't +exist in the original trait definition. When implementing a trait, you +can only define associated types that are explicitly declared in the trait.", + "\ +В реализации трейта определён ассоциированный тип, которого нет в +исходном определении трейта. При реализации трейта можно определять +только те ассоциированные типы, которые объявлены в трейте.", + "\ +트레이트 구현에서 원래 트레이트 정의에 존재하지 않는 연관 타입이 +정의되었습니다. 트레이트에 선언된 연관 타입만 정의할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove the extraneous associated type", + "Удалить лишний ассоциированный тип", + "불필요한 연관 타입 제거" + ), + code: "trait Foo {}\n\nimpl Foo for i32 {} // Remove type Bar = bool;" + }, + FixSuggestion { + description: LocalizedText::new( + "Add associated type to trait definition", + "Добавить ассоциированный тип в определение трейта", + "트레이트 정의에 연관 타입 추가" + ), + code: "trait Foo {\n type Bar;\n}\n\nimpl Foo for i32 {\n type Bar = bool;\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0437.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0438.rs b/masterror-knowledge/src/errors/traits/e0438.rs new file mode 100644 index 0000000..eb7434e --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0438.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0438: associated constant not in trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0438", + title: LocalizedText::new( + "Associated constant not in trait", + "Ассоциированная константа не в трейте", + "연관 상수가 트레이트에 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated constant was defined in a trait implementation that doesn't +exist in the trait definition. When implementing a trait, you can only +define associated constants that are explicitly declared in the trait.", + "\ +В реализации трейта определена ассоциированная константа, которой нет +в определении трейта. При реализации трейта можно определять только +те константы, которые объявлены в трейте.", + "\ +트레이트 구현에서 트레이트 정의에 존재하지 않는 연관 상수가 +정의되었습니다. 트레이트에 선언된 연관 상수만 정의할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove the extraneous associated constant", + "Удалить лишнюю ассоциированную константу", + "불필요한 연관 상수 제거" + ), + code: "trait Foo {}\n\nimpl Foo for i32 {} // Remove const BAR: bool = true;" + }, + FixSuggestion { + description: LocalizedText::new( + "Add associated constant to trait definition", + "Добавить ассоциированную константу в определение трейта", + "트레이트 정의에 연관 상수 추가" + ), + code: "trait Foo {\n const BAR: bool;\n}\n\nimpl Foo for i32 {\n const BAR: bool = true;\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0438.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0520.rs b/masterror-knowledge/src/errors/traits/e0520.rs new file mode 100644 index 0000000..889c606 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0520.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0520: specialization requires parent impl to be `default` + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0520", + title: LocalizedText::new( + "Specialization requires parent impl to be `default`", + "Специализация требует, чтобы родительская реализация была `default`", + "특수화는 부모 impl이 `default`이어야 함" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A non-default implementation was already made on this type so it cannot be +specialized further. When using the `specialization` feature, you can only +override a parent implementation if that parent is marked as `default`. + +The specialization feature allows more specific implementations to override +generic ones, but all intermediate implementations in the hierarchy must be +marked `default` to permit further specialization.", + "\ +Не-default реализация уже была сделана для этого типа, поэтому её нельзя +специализировать дальше. При использовании функции `specialization` можно +переопределить родительскую реализацию, только если она помечена как `default`.", + "\ +이 타입에 대해 이미 non-default 구현이 만들어졌으므로 더 이상 특수화할 수 +없습니다. `specialization` 기능을 사용할 때 부모 구현이 `default`로 +표시된 경우에만 재정의할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Mark parent implementations as `default`", + "Пометить родительские реализации как `default`", + "부모 구현을 `default`로 표시" + ), + code: "impl SpaceLlama for T {\n default fn fly(&self) {} // add default\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0520.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0525.rs b/masterror-knowledge/src/errors/traits/e0525.rs new file mode 100644 index 0000000..382a675 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0525.rs @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0525: closure doesn't implement required Fn trait + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0525", + title: LocalizedText::new( + "Closure doesn't implement required `Fn` trait", + "Замыкание не реализует требуемый трейт `Fn`", + "클로저가 필요한 `Fn` 트레이트를 구현하지 않음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A closure was used but didn't implement the expected trait. This error occurs +when a closure is passed to a function that expects a closure implementing a +specific trait (like `Fn`), but the closure only implements a less capable +trait (like `FnOnce`). + +In Rust, there are three closure traits: +- `FnOnce` - can be called once, may consume captured values +- `FnMut` - can be called multiple times, may mutate captured values +- `Fn` - can be called multiple times, borrows captured values immutably + +When a closure captures a value that isn't `Copy` or `Clone`, it becomes +`FnOnce` because it must consume the captured value when called.", + "\ +Замыкание было использовано, но не реализует ожидаемый трейт. Эта ошибка +возникает, когда замыкание передаётся функции, ожидающей замыкание с +определённым трейтом (например, `Fn`), но замыкание реализует только менее +способный трейт (например, `FnOnce`).", + "\ +클로저가 사용되었지만 예상되는 트레이트를 구현하지 않았습니다. 이 오류는 +특정 트레이트(예: `Fn`)를 구현하는 클로저를 예상하는 함수에 클로저가 +전달되었지만, 클로저가 더 제한적인 트레이트(예: `FnOnce`)만 구현할 때 +발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Implement Copy and Clone on captured types", + "Реализовать Copy и Clone для захваченных типов", + "캡처된 타입에 Copy와 Clone 구현" + ), + code: "#[derive(Clone, Copy)]\nstruct X;\n\nlet closure = |_| foo(x); // now Fn-compatible" + }], + links: &[ + DocLink { + title: "Closures Chapter", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0525.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0567.rs b/masterror-knowledge/src/errors/traits/e0567.rs new file mode 100644 index 0000000..87fe37a --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0567.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0567: auto traits cannot have generic parameters + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0567", + title: LocalizedText::new( + "Auto traits cannot have generic parameters", + "Автоматические трейты не могут иметь обобщённые параметры", + "자동 트레이트는 제네릭 매개변수를 가질 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Generics have been used on an auto trait. Auto traits cannot have generic +parameters because they are automatically implemented on all existing types. +The compiler cannot infer what types should be used for the trait's generic +parameters, creating ambiguity. + +Auto traits are special traits that are automatically implemented for all +types that meet certain criteria.", + "\ +Обобщённые параметры были использованы в автоматическом трейте. +Автоматические трейты не могут иметь обобщённые параметры, поскольку они +автоматически реализуются для всех существующих типов. Компилятор не может +определить, какие типы использовать для параметров трейта.", + "\ +자동 트레이트에 제네릭이 사용되었습니다. 자동 트레이트는 모든 기존 타입에 +자동으로 구현되기 때문에 제네릭 매개변수를 가질 수 없습니다. 컴파일러는 +트레이트의 제네릭 매개변수에 어떤 타입을 사용해야 하는지 추론할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove generic parameters from auto trait", + "Удалить обобщённые параметры из автоматического трейта", + "자동 트레이트에서 제네릭 매개변수 제거" + ), + code: "#![feature(auto_traits)]\n\nauto trait Generic {} // no type parameters" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0567.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0568.rs b/masterror-knowledge/src/errors/traits/e0568.rs new file mode 100644 index 0000000..b406933 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0568.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0568: auto traits cannot have super traits + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0568", + title: LocalizedText::new( + "Auto traits cannot have super traits", + "Автоматические трейты не могут иметь супертрейты", + "자동 트레이트는 슈퍼트레이트를 가질 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A super trait has been added to an auto trait. Auto traits are automatically +implemented for all existing types. Adding a super trait (a required trait +bound) would restrict which types can implement it, defeating the purpose of +an auto trait. + +This creates a contradiction since auto traits should apply universally to +all types, but a super trait bound would restrict that.", + "\ +Супертрейт был добавлен к автоматическому трейту. Автоматические трейты +реализуются для всех существующих типов автоматически. Добавление супертрейта +(требуемого ограничения трейта) ограничит типы, которые могут его реализовать, +что противоречит цели автоматического трейта.", + "\ +자동 트레이트에 슈퍼트레이트가 추가되었습니다. 자동 트레이트는 모든 기존 타입에 +자동으로 구현됩니다. 슈퍼트레이트(필수 트레이트 바운드)를 추가하면 구현할 수 +있는 타입이 제한되어 자동 트레이트의 목적에 어긋납니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove super trait from auto trait", + "Удалить супертрейт из автоматического трейта", + "자동 트레이트에서 슈퍼트레이트 제거" + ), + code: "#![feature(auto_traits)]\n\nauto trait Bound {} // no : Copy" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0568.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0576.rs b/masterror-knowledge/src/errors/traits/e0576.rs new file mode 100644 index 0000000..dffedd4 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0576.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0576: associated item not found in type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0576", + title: LocalizedText::new( + "Associated item not found in type", + "Ассоциированный элемент не найден в типе", + "타입에서 연관 항목을 찾을 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An associated item wasn't found in the given type. The compiler cannot find +the specified associated item (such as a type or method) that you're trying +to access. + +This usually happens when referencing an associated type or constant that +doesn't exist in the trait or impl.", + "\ +Ассоциированный элемент не был найден в данном типе. Компилятор не может +найти указанный ассоциированный элемент (например, тип или метод), к которому +вы пытаетесь получить доступ.", + "\ +주어진 타입에서 연관 항목을 찾을 수 없습니다. 컴파일러가 접근하려는 +지정된 연관 항목(예: 타입 또는 메서드)을 찾을 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use the correct associated type name", + "Использовать правильное имя ассоциированного типа", + "올바른 연관 타입 이름 사용" + ), + code: "trait Hello {\n type Who;\n fn hello() -> ::Who; // not ::You\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0576.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0592.rs b/masterror-knowledge/src/errors/traits/e0592.rs new file mode 100644 index 0000000..31929a2 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0592.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0592: duplicate method/associated function definition + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0592", + title: LocalizedText::new( + "Duplicate method or associated function definition", + "Дублирующееся определение метода или ассоциированной функции", + "중복된 메서드 또는 연관 함수 정의" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Methods or associated functions with the same name were defined in separate +`impl` blocks for the same struct/type. Each function must have a unique name +within the implementation scope. + +This is different from E0201, which occurs when duplicate definitions appear +in a single declaration block.", + "\ +Методы или ассоциированные функции с одинаковым именем были определены +в отдельных блоках `impl` для одной и той же структуры/типа. Каждая функция +должна иметь уникальное имя в области реализации.", + "\ +같은 이름의 메서드나 연관 함수가 같은 구조체/타입에 대해 별도의 `impl` +블록에서 정의되었습니다. 각 함수는 구현 범위 내에서 고유한 이름을 +가져야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Give each function a unique name", + "Дать каждой функции уникальное имя", + "각 함수에 고유한 이름 부여" + ), + code: "impl Foo {\n fn bar() {}\n}\nimpl Foo {\n fn baz() {} // different name\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0592.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0593.rs b/masterror-knowledge/src/errors/traits/e0593.rs new file mode 100644 index 0000000..4eb7624 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0593.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0593: closure/function argument count mismatch + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0593", + title: LocalizedText::new( + "Closure/function has wrong number of arguments", + "Замыкание/функция имеет неправильное количество аргументов", + "클로저/함수의 인수 수가 잘못됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +You supplied an `Fn`-based type with an incorrect number of arguments compared +to what was expected. The closure or function signature doesn't match the +required number of parameters. + +This error occurs when the closure or function provided has a different arity +(number of parameters) than what the trait bound specifies.", + "\ +Вы передали тип на основе `Fn` с неправильным количеством аргументов +по сравнению с ожидаемым. Сигнатура замыкания или функции не соответствует +требуемому количеству параметров.", + "\ +예상보다 잘못된 수의 인수를 가진 `Fn` 기반 타입을 제공했습니다. +클로저 또는 함수 시그니처가 필요한 매개변수 수와 일치하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match the expected argument count", + "Сопоставить ожидаемое количество аргументов", + "예상 인수 수와 일치" + ), + code: "fn foo(x: F) { }\n\nfoo(|| { }); // 0 arguments, matching Fn()" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0593.html" + }] +}; diff --git a/masterror-knowledge/src/errors/traits/e0638.rs b/masterror-knowledge/src/errors/traits/e0638.rs new file mode 100644 index 0000000..5db0c26 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0638.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0638: non-exhaustive type matched exhaustively + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0638", + title: LocalizedText::new( + "Non-exhaustive type must be matched non-exhaustively", + "Неисчерпывающий тип должен сопоставляться неисчерпывающе", + "비완전 타입은 비완전하게 매치해야 함" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A struct, enum, or enum variant marked with `#[non_exhaustive]` was +matched exhaustively. The `#[non_exhaustive]` attribute allows library +authors to add new variants or fields in future versions without breaking +downstream code. + +Downstream crates must: +- Use a wildcard `_` pattern when matching non-exhaustive enums +- Use the `..` pattern when matching non-exhaustive structs", + "\ +Структура, enum или вариант enum, помеченный `#[non_exhaustive]`, был +сопоставлен исчерпывающе. Атрибут `#[non_exhaustive]` позволяет авторам +библиотек добавлять новые варианты или поля в будущих версиях, не ломая +зависимый код. + +Зависимые крейты должны: +- Использовать шаблон подстановки `_` при сопоставлении non-exhaustive enums +- Использовать шаблон `..` при сопоставлении non-exhaustive структур", + "\ +`#[non_exhaustive]`로 표시된 구조체, enum 또는 enum 변형이 +완전하게 매치되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use wildcard pattern for enums", + "Использовать шаблон подстановки для enums", + "enum에 와일드카드 패턴 사용" + ), + code: "match error {\n Error::Message(s) => {},\n Error::Other => {},\n _ => {}, // required for non_exhaustive\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use .. pattern for structs", + "Использовать шаблон .. для структур", + "구조체에 .. 패턴 사용" + ), + code: "match my_struct {\n MyStruct { field1, .. } => {},\n}" + } + ], + links: &[ + DocLink { + title: "Non-exhaustive Attribute", + url: "https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0638.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0639.rs b/masterror-knowledge/src/errors/traits/e0639.rs new file mode 100644 index 0000000..087eca2 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0639.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0639: cannot instantiate non-exhaustive type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0639", + title: LocalizedText::new( + "Cannot instantiate non-exhaustive type from outside crate", + "Невозможно создать экземпляр неисчерпывающего типа извне крейта", + "크레이트 외부에서 비완전 타입을 인스턴스화할 수 없음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Attempted to instantiate a struct, enum, or enum variant from outside its +defining crate when it has been marked with `#[non_exhaustive]`. + +The `#[non_exhaustive]` attribute signals that a type may have additional +fields or variants added in future versions. To preserve backward +compatibility, Rust prevents external code from directly instantiating +these types using struct literals.", + "\ +Попытка создать экземпляр структуры, enum или варианта enum извне его +определяющего крейта, когда он помечен `#[non_exhaustive]`. + +Атрибут `#[non_exhaustive]` сигнализирует, что тип может иметь +дополнительные поля или варианты, добавленные в будущих версиях. Для +сохранения обратной совместимости Rust запрещает внешнему коду напрямую +создавать экземпляры этих типов с помощью литералов структур.", + "\ +`#[non_exhaustive]`로 표시된 구조체, enum 또는 enum 변형을 +정의하는 크레이트 외부에서 인스턴스화하려고 시도했습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use the constructor function provided by the crate", + "Использовать функцию-конструктор, предоставленную крейтом", + "크레이트에서 제공하는 생성자 함수 사용" + ), + code: "// Check the crate's documentation for a `new` or similar constructor\nlet instance = SomeType::new();" + }], + links: &[ + DocLink { + title: "Non-exhaustive Attribute", + url: "https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0639.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0642.rs b/masterror-knowledge/src/errors/traits/e0642.rs new file mode 100644 index 0000000..f8856f5 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0642.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0642: patterns not allowed in trait methods + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0642", + title: LocalizedText::new( + "Patterns not allowed in trait methods", + "Шаблоны не допускаются в методах трейтов", + "트레이트 메서드에서 패턴 허용되지 않음" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +Trait methods currently cannot take patterns as arguments. Rust does not +allow pattern matching in trait method signatures. + +While you can use destructuring patterns in regular function parameters, +trait method declarations must use single parameter names with their +full types.", + "\ +Методы трейтов в настоящее время не могут принимать шаблоны в качестве +аргументов. Rust не допускает сопоставление с шаблоном в сигнатурах +методов трейтов. + +Хотя вы можете использовать деструктурирующие шаблоны в параметрах +обычных функций, объявления методов трейтов должны использовать +одиночные имена параметров с их полными типами.", + "\ +트레이트 메서드는 현재 인수로 패턴을 받을 수 없습니다. Rust는 트레이트 +메서드 시그니처에서 패턴 매칭을 허용하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use single parameter name with full type", + "Использовать одиночное имя параметра с полным типом", + "전체 타입과 함께 단일 매개변수 이름 사용" + ), + code: "trait Foo {\n fn foo(x_and_y: (i32, i32)); // ok\n}" + }], + links: &[ + DocLink { + title: "Traits", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0642.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0665.rs b/masterror-knowledge/src/errors/traits/e0665.rs new file mode 100644 index 0000000..2a59f13 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0665.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0665: Default derive on enum without default variant + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0665", + title: LocalizedText::new( + "Default derived on enum without specifying default variant", + "Default производный для enum без указания варианта по умолчанию", + "기본 변형을 지정하지 않고 enum에 Default 파생" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +The `Default` trait was derived on an enum without explicitly designating +which variant should be used as the default value. + +The Rust compiler cannot automatically determine which enum variant should +be the default because enums can have multiple variants. Unlike structs +(where `Default` can be derived if all fields implement `Default`), there's +no obvious choice for which variant to use.", + "\ +Трейт `Default` был выведен для enum без явного указания, какой вариант +должен использоваться как значение по умолчанию. + +Компилятор Rust не может автоматически определить, какой вариант enum +должен быть по умолчанию, потому что у enum может быть несколько вариантов. +В отличие от структур (где `Default` может быть выведен, если все поля +реализуют `Default`), нет очевидного выбора для варианта.", + "\ +어떤 변형이 기본값으로 사용되어야 하는지 명시적으로 지정하지 않고 +enum에서 `Default` 트레이트가 파생되었습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Annotate the default variant", + "Аннотировать вариант по умолчанию", + "기본 변형 주석 추가" + ), + code: "#[derive(Default)]\nenum Food {\n #[default]\n Sweet,\n Salty,\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Manually implement Default", + "Реализовать Default вручную", + "Default 수동 구현" + ), + code: "impl Default for Food {\n fn default() -> Food {\n Food::Sweet\n }\n}" + } + ], + links: &[ + DocLink { + title: "Default Trait", + url: "https://doc.rust-lang.org/std/default/trait.Default.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0665.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0802.rs b/masterror-knowledge/src/errors/traits/e0802.rs new file mode 100644 index 0000000..c07dc37 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0802.rs @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0802: invalid CoercePointee derive target + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0802", + title: LocalizedText::new( + "Invalid CoercePointee derive target", + "Недопустимая цель для derive(CoercePointee)", + "잘못된 CoercePointee derive 대상" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +The target of `derive(CoercePointee)` macro has inadmissible specification. + +The `CoercePointee` macro requires ALL of the following: +1. Must be a `struct` (not enum or other type) +2. Must be generic over at least one type parameter +3. Must have `#[repr(transparent)]` layout +4. Must have at least one data field +5. Must designate exactly one generic type as pointee with `#[pointee]` +6. The pointee type must be marked `?Sized`", + "\ +Цель макроса `derive(CoercePointee)` имеет недопустимую спецификацию. + +Макрос `CoercePointee` требует ВСЕ из следующего: +1. Должна быть `struct` (не enum или другой тип) +2. Должна быть обобщённой хотя бы по одному параметру типа +3. Должна иметь атрибут `#[repr(transparent)]` +4. Должна иметь хотя бы одно поле данных +5. Ровно один обобщённый тип должен быть помечен `#[pointee]` +6. Тип pointee должен быть помечен `?Sized`", + "\ +`derive(CoercePointee)` 매크로의 대상이 허용되지 않는 사양을 가지고 있습니다. +모든 요구 사항을 충족해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Correct CoercePointee usage", + "Правильное использование CoercePointee", + "올바른 CoercePointee 사용법" + ), + code: "\ +#[derive(CoercePointee)] +#[repr(transparent)] +struct MyPointer<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +}" + }], + links: &[ + DocLink { + title: "CoercePointee Documentation", + url: "https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0802.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0804.rs b/masterror-knowledge/src/errors/traits/e0804.rs new file mode 100644 index 0000000..9dd99c5 --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0804.rs @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0804: cannot add auto trait via pointer cast + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0804", + title: LocalizedText::new( + "Cannot add auto trait via pointer cast", + "Нельзя добавить auto trait через приведение указателя", + "포인터 캐스트로 auto trait 추가 불가" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An auto trait cannot be added to the bounds of a `dyn Trait` type via a +pointer cast. + +Adding an auto trait through a pointer cast can make the vtable invalid, +potentially causing undefined behavior in safe code. The vtable associated +with a trait object may not have entries for all methods when an auto trait +is added after the fact. + +Example of invalid code: +`let ptr: *const dyn Any = &();` +`_ = ptr as *const (dyn Any + Send);` // E0804 + +This is dangerous because the vtable for the original trait object may not +contain entries for methods that require the auto trait bound.", + "\ +Auto trait нельзя добавить к границам типа `dyn Trait` через приведение +указателя. + +Добавление auto trait через приведение указателя может сделать vtable +недействительной, что потенциально вызовет неопределённое поведение. +Vtable, связанная с trait object, может не иметь записей для всех методов, +когда auto trait добавляется постфактум. + +Пример неверного кода: +`let ptr: *const dyn Any = &();` +`_ = ptr as *const (dyn Any + Send);` // E0804", + "\ +포인터 캐스트를 통해 `dyn Trait` 타입의 바운드에 auto trait를 추가할 수 없습니다. +이는 vtable을 무효화하여 정의되지 않은 동작을 일으킬 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Ensure trait object has correct bounds from start", + "Убедиться, что trait object имеет правильные границы с самого начала", + "처음부터 올바른 바운드로 trait object 생성" + ), + code: "\ +// Create trait object with correct bounds from the start +let ptr: *const (dyn Any + Send) = &();" + }], + links: &[ + DocLink { + title: "Trait Objects", + url: "https://doc.rust-lang.org/book/ch17-02-trait-objects.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0804.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/traits/e0805.rs b/masterror-knowledge/src/errors/traits/e0805.rs new file mode 100644 index 0000000..9579ebc --- /dev/null +++ b/masterror-knowledge/src/errors/traits/e0805.rs @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0805: invalid number of attribute arguments + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0805", + title: LocalizedText::new( + "Invalid number of attribute arguments", + "Неверное количество аргументов атрибута", + "잘못된 속성 인수 개수" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An attribute was given an invalid number of arguments. + +Rust attributes have specific requirements for the number of arguments +they accept. For example, the `#[inline]` attribute can either have +no arguments or exactly one argument. + +Invalid examples: +- `#[inline()]` - empty parentheses not allowed +- `#[inline(always, never)]` - too many arguments + +Valid examples: +- `#[inline]` - no arguments +- `#[inline(always)]` - single argument", + "\ +Атрибуту было передано неверное количество аргументов. + +Атрибуты Rust имеют определённые требования к количеству аргументов. +Например, атрибут `#[inline]` может либо не иметь аргументов, +либо иметь ровно один аргумент. + +Неверные примеры: +- `#[inline()]` - пустые скобки не разрешены +- `#[inline(always, never)]` - слишком много аргументов + +Верные примеры: +- `#[inline]` - без аргументов +- `#[inline(always)]` - один аргумент", + "\ +속성에 잘못된 수의 인수가 전달되었습니다. +Rust 속성은 허용하는 인수 수에 대해 특정 요구 사항이 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use attribute without parentheses", + "Использовать атрибут без скобок", + "괄호 없이 속성 사용" + ), + code: "#[inline]\nfn foo() {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use attribute with single argument", + "Использовать атрибут с одним аргументом", + "단일 인수로 속성 사용" + ), + code: "#[inline(always)]\nfn foo() {}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Attributes", + url: "https://doc.rust-lang.org/reference/attributes.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0805.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types.rs b/masterror-knowledge/src/errors/types.rs new file mode 100644 index 0000000..60d9877 --- /dev/null +++ b/masterror-knowledge/src/errors/types.rs @@ -0,0 +1,141 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Type-related errors. + +mod e0054; +mod e0055; +mod e0057; +mod e0061; +mod e0069; +mod e0070; +mod e0071; +mod e0072; +mod e0161; +mod e0203; +mod e0208; +mod e0211; +mod e0212; +mod e0214; +mod e0243; +mod e0244; +mod e0277; +mod e0281; +mod e0283; +mod e0284; +mod e0308; +mod e0391; +mod e0472; +mod e0476; +mod e0511; +mod e0512; +mod e0516; +mod e0527; +mod e0528; +mod e0529; +mod e0559; +mod e0560; +mod e0561; +mod e0562; +mod e0573; +mod e0574; +mod e0575; +mod e0591; +mod e0599; +mod e0600; +mod e0604; +mod e0605; +mod e0606; +mod e0607; +mod e0608; +mod e0609; +mod e0610; +mod e0614; +mod e0617; +mod e0618; +mod e0620; +mod e0631; +mod e0641; +mod e0643; +mod e0644; +mod e0666; +mod e0689; +mod e0690; +mod e0691; +mod e0692; +mod e0693; +mod e0800; +mod e0801; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0054::ENTRY, + &e0055::ENTRY, + &e0057::ENTRY, + &e0061::ENTRY, + &e0069::ENTRY, + &e0070::ENTRY, + &e0071::ENTRY, + &e0072::ENTRY, + &e0161::ENTRY, + &e0203::ENTRY, + &e0208::ENTRY, + &e0211::ENTRY, + &e0212::ENTRY, + &e0214::ENTRY, + &e0243::ENTRY, + &e0244::ENTRY, + &e0277::ENTRY, + &e0281::ENTRY, + &e0283::ENTRY, + &e0284::ENTRY, + &e0308::ENTRY, + &e0391::ENTRY, + &e0472::ENTRY, + &e0476::ENTRY, + &e0511::ENTRY, + &e0512::ENTRY, + &e0516::ENTRY, + &e0527::ENTRY, + &e0528::ENTRY, + &e0529::ENTRY, + &e0559::ENTRY, + &e0560::ENTRY, + &e0561::ENTRY, + &e0562::ENTRY, + &e0573::ENTRY, + &e0574::ENTRY, + &e0575::ENTRY, + &e0591::ENTRY, + &e0599::ENTRY, + &e0600::ENTRY, + &e0604::ENTRY, + &e0605::ENTRY, + &e0606::ENTRY, + &e0607::ENTRY, + &e0608::ENTRY, + &e0609::ENTRY, + &e0610::ENTRY, + &e0614::ENTRY, + &e0617::ENTRY, + &e0618::ENTRY, + &e0620::ENTRY, + &e0631::ENTRY, + &e0641::ENTRY, + &e0643::ENTRY, + &e0644::ENTRY, + &e0666::ENTRY, + &e0689::ENTRY, + &e0690::ENTRY, + &e0691::ENTRY, + &e0692::ENTRY, + &e0693::ENTRY, + &e0800::ENTRY, + &e0801::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/types/e0054.rs b/masterror-knowledge/src/errors/types/e0054.rs new file mode 100644 index 0000000..f9250d4 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0054.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0054: cannot cast to bool + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0054", + title: LocalizedText::new( + "Cannot cast to bool", + "Нельзя преобразовать в bool", + "bool로 캐스트할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Rust does not allow casting values directly to `bool` using the `as` operator. + +Example: + let x = 5; + let b = x as bool; // Error: cannot cast to bool", + "\ +Rust не позволяет напрямую преобразовывать значения в `bool` с помощью +оператора `as`.", + "\ +Rust는 `as` 연산자를 사용하여 값을 `bool`로 직접 캐스트하는 것을 허용하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a comparison instead", + "Использовать сравнение вместо приведения", + "대신 비교 사용" + ), + code: "let x = 5;\nlet b = x != 0; // true if x is nonzero" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0054.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0055.rs b/masterror-knowledge/src/errors/types/e0055.rs new file mode 100644 index 0000000..8071a29 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0055.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0055: auto-deref recursion limit exceeded + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0055", + title: LocalizedText::new( + "Auto-deref recursion limit exceeded", + "Превышен лимит рекурсии автоматического разыменования", + "자동 역참조 재귀 한도 초과" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when automatic dereferencing during method calls exceeds the +compiler's recursion limit. Rust automatically dereferences values to match +method receivers, but has a limit on how deep this can go. + +Example: + let ref_foo = &&&&&Foo; + ref_foo.method(); // Error if recursion limit is less than 5", + "\ +Эта ошибка возникает, когда автоматическое разыменование при вызове методов +превышает лимит рекурсии компилятора.", + "\ +이 오류는 메서드 호출 중 자동 역참조가 컴파일러의 재귀 한도를 초과할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Increase recursion limit", + "Увеличить лимит рекурсии", + "재귀 한도 증가" + ), + code: "#![recursion_limit=\"128\"]" + }, + FixSuggestion { + description: LocalizedText::new( + "Manually dereference", + "Разыменовать вручную", + "수동으로 역참조" + ), + code: "let ref_foo = &&&&&Foo;\n(*****ref_foo).method();" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0055.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0057.rs b/masterror-knowledge/src/errors/types/e0057.rs new file mode 100644 index 0000000..7fc552b --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0057.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0057: wrong number of closure arguments + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0057", + title: LocalizedText::new( + "Wrong number of closure arguments", + "Неверное количество аргументов замыкания", + "잘못된 클로저 인수 수" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when calling a closure with the wrong number of arguments. + +Example: + let f = |x| x * 3; + f(); // Error: expects 1 argument, got 0 + f(2, 3); // Error: expects 1 argument, got 2", + "\ +Эта ошибка возникает при вызове замыкания с неверным количеством аргументов.", + "\ +이 오류는 잘못된 수의 인수로 클로저를 호출할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Pass the correct number of arguments", + "Передать правильное количество аргументов", + "올바른 수의 인수 전달" + ), + code: "let f = |x| x * 3;\nlet result = f(4); // Correct: 1 argument" + }], + links: &[ + DocLink { + title: "Rust Book: Closures", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0057.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0061.rs b/masterror-knowledge/src/errors/types/e0061.rs new file mode 100644 index 0000000..6f79fee --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0061.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0061: wrong number of function arguments + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0061", + title: LocalizedText::new( + "Wrong number of function arguments", + "Неверное количество аргументов функции", + "잘못된 함수 인수 수" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when a function is called with the wrong number of arguments. +The number of arguments must exactly match the function signature. + +Example: + fn f(a: u16, b: &str) {} + f(2); // Error: expected 2 arguments, found 1", + "\ +Эта ошибка возникает при вызове функции с неверным количеством аргументов. +Количество аргументов должно точно соответствовать сигнатуре функции.", + "\ +이 오류는 잘못된 수의 인수로 함수를 호출할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Provide all required arguments", + "Предоставить все необходимые аргументы", + "모든 필수 인수 제공" + ), + code: "fn f(a: u16, b: &str) {}\nf(2, \"test\"); // Correct" + }], + links: &[ + DocLink { + title: "Rust Book: Functions", + url: "https://doc.rust-lang.org/book/ch03-03-how-functions-work.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0061.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0069.rs b/masterror-knowledge/src/errors/types/e0069.rs new file mode 100644 index 0000000..0aae128 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0069.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0069: return with no value in non-unit function + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0069", + title: LocalizedText::new( + "Return with no value in non-unit function", + "Return без значения в функции, возвращающей не ()", + "non-unit 함수에서 값 없이 return" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when a function with a non-unit return type contains a bare +`return;` statement without a value. A bare `return;` is equivalent to +`return ();`, which doesn't match the expected return type. + +Example: + fn foo() -> u8 { + return; // Error: expected u8, returns () + }", + "\ +Эта ошибка возникает, когда функция с не-unit типом возврата содержит +голый `return;` без значения.", + "\ +이 오류는 non-unit 반환 타입을 가진 함수가 값 없이 `return;`을 포함할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Return a value of the correct type", + "Вернуть значение правильного типа", + "올바른 타입의 값 반환" + ), + code: "fn foo() -> u8 {\n return 5;\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Change return type to unit", + "Изменить тип возврата на ()", + "반환 타입을 unit으로 변경" + ), + code: "fn foo() {\n return;\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0069.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0070.rs b/masterror-knowledge/src/errors/types/e0070.rs new file mode 100644 index 0000000..a144a1d --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0070.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0070: invalid left-hand side of assignment + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0070", + title: LocalizedText::new( + "Invalid left-hand side of assignment", + "Недопустимое левое значение в присваивании", + "할당의 잘못된 좌변" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when you try to assign to something that isn't a valid +place expression. Only variables, dereferences, indexing expressions, and +field references can be assigned to. + +Example: + 1 = 3; // Error: can't assign to a literal + some_func() = 4; // Error: can't assign to function result", + "\ +Эта ошибка возникает при попытке присвоить что-то, что не является +допустимым place-выражением.", + "\ +이 오류는 유효한 place 표현식이 아닌 것에 할당하려고 할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Assign to a mutable variable", + "Присвоить изменяемой переменной", + "가변 변수에 할당" + ), + code: "let mut x = 0;\nx = 3; // Correct" + }], + links: &[ + DocLink { + title: "Rust Reference: Place Expressions", + url: "https://doc.rust-lang.org/reference/expressions.html#place-expressions-and-value-expressions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0070.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0071.rs b/masterror-knowledge/src/errors/types/e0071.rs new file mode 100644 index 0000000..b9d0e48 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0071.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0071: struct literal used for non-struct type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0071", + title: LocalizedText::new( + "Struct literal used for non-struct type", + "Синтаксис структуры для не-структурного типа", + "비구조체 타입에 구조체 리터럴 사용" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when struct literal syntax `{ field: value }` is used with +a type that isn't a struct, enum variant, or union. + +Example: + type U32 = u32; + let t = U32 { value: 4 }; // Error: u32 is not a struct", + "\ +Эта ошибка возникает при использовании синтаксиса структурного литерала +с типом, который не является структурой, вариантом enum или union.", + "\ +이 오류는 구조체, 열거형 변형 또는 공용체가 아닌 타입에 구조체 리터럴 구문을 사용할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use correct initialization syntax", + "Использовать правильный синтаксис инициализации", + "올바른 초기화 구문 사용" + ), + code: "type U32 = u32;\nlet t: U32 = 4;" + }, + FixSuggestion { + description: LocalizedText::new( + "Define an actual struct", + "Определить настоящую структуру", + "실제 구조체 정의" + ), + code: "struct U32 { value: u32 }\nlet t = U32 { value: 4 };" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0071.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0072.rs b/masterror-knowledge/src/errors/types/e0072.rs new file mode 100644 index 0000000..b92dc08 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0072.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0072: recursive type has infinite size + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0072", + title: LocalizedText::new( + "Recursive type has infinite size", + "Рекурсивный тип имеет бесконечный размер", + "재귀 타입이 무한 크기를 가짐" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when a struct or enum contains itself directly without +indirection, making it impossible to compute its size. + +Example: + struct Node { + value: i32, + next: Option, // Error: infinite size + } + +Rust needs to know the size of types at compile time.", + "\ +Эта ошибка возникает, когда структура или enum содержит себя напрямую +без косвенности, что делает невозможным вычисление её размера.", + "\ +이 오류는 구조체나 열거형이 간접 참조 없이 자신을 직접 포함하여 크기를 계산할 수 없을 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use Box for indirection", + "Использовать Box для косвенности", + "간접 참조를 위해 Box 사용" + ), + code: "struct Node {\n value: i32,\n next: Option>, // Box has known size\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Using Box for Recursive Types", + url: "https://doc.rust-lang.org/book/ch15-01-box.html#enabling-recursive-types-with-boxes" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0072.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0161.rs b/masterror-knowledge/src/errors/types/e0161.rs new file mode 100644 index 0000000..935618e --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0161.rs @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0161: cannot move a value of type: the size cannot be statically determined + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0161", + title: LocalizedText::new( + "Cannot move a value of type: the size cannot be statically determined", + "Нельзя переместить значение: размер не может быть определён статически", + "값을 이동할 수 없음: 크기를 정적으로 결정할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A value was moved whose size was not known at compile time. In Rust, you can +only move a value when its size is known at compile time. This error occurs +when attempting to move a dynamically-sized type (like dyn Trait).", + "\ +Было перемещено значение, размер которого не известен во время компиляции. +В Rust можно перемещать только значения с известным размером во время +компиляции. Эта ошибка возникает при попытке переместить динамически +размерный тип (например, dyn Trait).", + "\ +컴파일 시간에 크기를 알 수 없는 값이 이동되었습니다. Rust에서는 +컴파일 시간에 크기가 알려진 경우에만 값을 이동할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a reference instead of moving", + "Использовать ссылку вместо перемещения", + "이동 대신 참조 사용" + ), + code: "trait Bar {\n fn f(&self); // use &self instead of self\n}\n\nimpl Bar for i32 {\n fn f(&self) {}\n}\n\nfn main() {\n let b: Box = Box::new(0i32);\n b.f(); // ok!\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Dynamically Sized Types", + url: "https://doc.rust-lang.org/reference/dynamically-sized-types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0161.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0203.rs b/masterror-knowledge/src/errors/types/e0203.rs new file mode 100644 index 0000000..b4d25fb --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0203.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0203: duplicate relaxed bounds + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0203", + title: LocalizedText::new( + "Duplicate relaxed default bounds", + "Дублирующиеся ослабленные ограничения по умолчанию", + "중복된 완화된 기본 바운드" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Having duplicate relaxed default bounds is unsupported. + +The `?Sized` bound is a relaxed bound that removes the default `Sized` +requirement from a type parameter. Using `?Sized` more than once on +the same type parameter is redundant and not allowed.", + "\ +Наличие дублирующихся ослабленных ограничений по умолчанию не поддерживается. + +Ограничение `?Sized` убирает требование `Sized` по умолчанию. +Использование `?Sized` более одного раза для одного параметра типа +избыточно и не допускается.", + "\ +중복된 완화된 기본 바운드는 지원되지 않습니다. +`?Sized` 바운드는 한 번만 사용해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove duplicate ?Sized bound", + "Удалите дублирующееся ограничение ?Sized", + "중복 ?Sized 바운드 제거" + ), + code: "struct Good {\n inner: T,\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Sized Trait", + url: "https://doc.rust-lang.org/std/marker/trait.Sized.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0203.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0208.rs b/masterror-knowledge/src/errors/types/e0208.rs new file mode 100644 index 0000000..b505e7e --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0208.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0208: variance display (internal) + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0208", + title: LocalizedText::new( + "Type variance display (internal)", + "Отображение вариантности типа (внутреннее)", + "타입 변성 표시 (내부용)" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This is an internal compiler error that is no longer emitted in normal +Rust code. It was used to display the variance of a type's generic +parameters via the unstable `#[rustc_variance]` attribute. + +Variance notation: +- `-` indicates contravariance +- `o` indicates invariance +- `+` indicates covariance + +This attribute is only used internally for compiler testing.", + "\ +Это внутренняя ошибка компилятора, которая больше не выдаётся в +обычном коде Rust. Она использовалась для отображения вариантности +параметров типа через нестабильный атрибут `#[rustc_variance]`.", + "\ +이것은 더 이상 일반 Rust 코드에서 발생하지 않는 내부 컴파일러 오류입니다. +`#[rustc_variance]` 속성을 통해 타입의 변성을 표시하는 데 사용되었습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove #[rustc_variance] attribute", + "Удалите атрибут #[rustc_variance]", + "#[rustc_variance] 속성 제거" + ), + code: "struct Foo<'a, T> {\n t: &'a mut T,\n}" + }], + links: &[ + DocLink { + title: "Rustonomicon: Variance", + url: "https://doc.rust-lang.org/nomicon/subtyping.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0208.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0211.rs b/masterror-knowledge/src/errors/types/e0211.rs new file mode 100644 index 0000000..2be8037 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0211.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0211: type mismatch in function/type usage + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0211", + title: LocalizedText::new( + "Type mismatch in function or type usage", + "Несоответствие типов в использовании функции или типа", + "함수 또는 타입 사용에서 타입 불일치" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A function or type doesn't fit the requirements for where it was used. +This is a type mismatch error with several common scenarios. + +Note: This error code is no longer emitted by the compiler. + +Common cases: +- Intrinsic function with wrong signature +- Main function with wrong return type +- Range pattern type mismatch in match +- Invalid self type in methods", + "\ +Функция или тип не соответствует требованиям для места использования. +Это ошибка несоответствия типов. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +함수나 타입이 사용된 위치의 요구사항과 맞지 않습니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Ensure types match the expected signature", + "Убедитесь, что типы соответствуют ожидаемой сигнатуре", + "타입이 예상 시그니처와 일치하는지 확인" + ), + code: "fn main() {} // correct main signature" + }, + FixSuggestion { + description: LocalizedText::new( + "Use matching types in range patterns", + "Используйте совпадающие типы в диапазонных паттернах", + "범위 패턴에서 일치하는 타입 사용" + ), + code: "let x = 1u8;\nmatch x {\n 0u8..=3u8 => (),\n _ => ()\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Type System", + url: "https://doc.rust-lang.org/reference/types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0211.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0212.rs b/masterror-knowledge/src/errors/types/e0212.rs new file mode 100644 index 0000000..5a459fd --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0212.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0212: cannot use associated type with uninferred generics + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0212", + title: LocalizedText::new( + "Cannot use associated type with uninferred generics", + "Нельзя использовать ассоциированный тип с невыведенными дженериками", + "추론되지 않은 제네릭과 연관 타입 사용 불가" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Cannot use the associated type of a trait with uninferred generic parameters. +The compiler cannot determine what concrete type should be used for +the generic parameter, making it impossible to resolve the associated type. + +This commonly occurs with higher-ranked trait bounds (HRTB) where the +lifetime is quantified with `for<'x>`, and the compiler doesn't know +which specific lifetime to substitute when accessing the associated type.", + "\ +Нельзя использовать ассоциированный тип трейта с невыведенными параметрами +дженериков. Компилятор не может определить, какой конкретный тип +использовать для параметра. + +Часто встречается с высокоранговыми ограничениями трейтов (HRTB).", + "\ +추론되지 않은 제네릭 매개변수를 가진 트레이트의 연관 타입을 사용할 수 없습니다. +컴파일러가 어떤 구체적인 타입을 사용해야 할지 결정할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Explicitly specify generic parameters", + "Явно укажите параметры дженериков", + "제네릭 매개변수를 명시적으로 지정" + ), + code: "fn foo3 Foo<&'x isize>>(\n x: >::A) {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a named lifetime parameter", + "Используйте именованный параметр времени жизни", + "명명된 수명 매개변수 사용" + ), + code: "fn foo4<'a, I: for<'x> Foo<&'x isize>>(\n x: >::A) {}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Higher-ranked Trait Bounds", + url: "https://doc.rust-lang.org/reference/trait-bounds.html#higher-ranked-trait-bounds" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0212.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0214.rs b/masterror-knowledge/src/errors/types/e0214.rs new file mode 100644 index 0000000..820a2e3 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0214.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0214: incorrect generic type syntax + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0214", + title: LocalizedText::new( + "Generic type described with parentheses instead of angle brackets", + "Обобщённый тип описан круглыми скобками вместо угловых", + "제네릭 타입이 꺾쇠괄호 대신 괄호로 기술됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Generic type parameter specified using parentheses rather than angle brackets. + +Incorrect syntax: Vec(&str) +Correct syntax: Vec<&str> + +Parentheses are ONLY used with generic types when defining parameters +for `Fn`-family traits (like `Fn()`, `FnMut()`, `FnOnce()`). For all +other generic types, angle brackets must be used.", + "\ +Параметр обобщённого типа указан с использованием круглых скобок +вместо угловых. + +Неправильно: Vec(&str) +Правильно: Vec<&str> + +Круглые скобки используются ТОЛЬКО для трейтов семейства Fn.", + "\ +제네릭 타입 매개변수가 꺾쇠괄호 대신 괄호로 지정되었습니다. +괄호는 Fn 계열 트레이트에만 사용됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use angle brackets for generic types", + "Используйте угловые скобки для обобщённых типов", + "제네릭 타입에 꺾쇠괄호 사용" + ), + code: "let v: Vec<&str> = vec![\"foo\"];" + }], + links: &[ + DocLink { + title: "Rust Book: Generic Types", + url: "https://doc.rust-lang.org/book/ch10-01-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0214.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0243.rs b/masterror-knowledge/src/errors/types/e0243.rs new file mode 100644 index 0000000..4e0e68c --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0243.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0243: not enough type parameters + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0243", + title: LocalizedText::new( + "Not enough type parameters provided", + "Предоставлено недостаточно параметров типа", + "제공된 타입 매개변수가 충분하지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Not enough type parameters were found in a type or trait usage. + +When a struct, trait, or other type is defined as generic (with type +parameters), all those type parameters must be specified when using +that type. If you fail to provide the required type parameters, you +get this error. + +Note: This error code is no longer emitted by the compiler.", + "\ +В использовании типа или трейта найдено недостаточно параметров типа. + +Когда struct, trait или другой тип определён как обобщённый, +все параметры типа должны быть указаны при использовании. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +타입 또는 트레이트 사용에서 충분한 타입 매개변수가 제공되지 않았습니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Provide all required type parameters", + "Укажите все требуемые параметры типа", + "필요한 모든 타입 매개변수 제공" + ), + code: "struct Foo { x: T }\n\nstruct Bar { x: Foo } // provide T" + }], + links: &[ + DocLink { + title: "Rust Book: Generic Types", + url: "https://doc.rust-lang.org/book/ch10-01-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0243.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0244.rs b/masterror-knowledge/src/errors/types/e0244.rs new file mode 100644 index 0000000..11afb63 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0244.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0244: too many type parameters + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0244", + title: LocalizedText::new( + "Too many type parameters provided", + "Предоставлено слишком много параметров типа", + "제공된 타입 매개변수가 너무 많음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Too many type parameters were found in a type or trait usage. + +You attempted to provide more type parameters than the type or trait +actually accepts. The number of type arguments must match the number +of type parameters in the definition. + +Note: This error code is no longer emitted by the compiler.", + "\ +В использовании типа или трейта найдено слишком много параметров типа. + +Вы попытались предоставить больше параметров типа, чем тип или трейт +фактически принимает. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +타입 또는 트레이트 사용에서 너무 많은 타입 매개변수가 제공되었습니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Provide only the required type parameters", + "Укажите только требуемые параметры типа", + "필요한 타입 매개변수만 제공" + ), + code: "struct Foo { x: T }\n\nstruct Bar { x: Foo } // only one parameter" + }], + links: &[ + DocLink { + title: "Rust Book: Generic Types", + url: "https://doc.rust-lang.org/book/ch10-01-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0244.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0277.rs b/masterror-knowledge/src/errors/types/e0277.rs new file mode 100644 index 0000000..e054ab2 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0277.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0277", + title: LocalizedText::new( + "Trait bound not satisfied", + "Ограничение трейта не выполнено", + "트레이트 바운드가 충족되지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "A generic function or type requires a trait bound that your type doesn't satisfy.", + "Обобщённая функция или тип требует ограничение трейта, которому ваш тип не удовлетворяет.", + "제네릭 함수나 타입이 당신의 타입이 충족하지 않는 트레이트 바운드를 요구합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Derive the trait", + "Получить через derive", + "트레이트 derive" + ), + code: "#[derive(Hash, Eq, PartialEq)]" + }, + FixSuggestion { + description: LocalizedText::new( + "Implement manually", + "Реализовать вручную", + "수동 구현" + ), + code: "impl MyTrait for MyType { ... }" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0277.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0281.rs b/masterror-knowledge/src/errors/types/e0281.rs new file mode 100644 index 0000000..f83522a --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0281.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0281: type mismatch in Fn trait requirement + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0281", + title: LocalizedText::new( + "Type mismatch in Fn trait requirement", + "Несоответствие типов в требовании трейта Fn", + "Fn 트레이트 요구사항에서 타입 불일치" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +You attempted to supply a type that doesn't implement a required trait +in a location that expects that trait. This typically occurs when +working with `Fn`-based types. + +The closure or function parameter types must match the trait requirement +exactly. If a function expects `Fn(usize)` but you provide a closure +that takes `String`, you get a type mismatch. + +Note: This error code is no longer emitted by the compiler.", + "\ +Вы попытались предоставить тип, который не реализует требуемый трейт. +Это обычно происходит при работе с типами на основе `Fn`. + +Типы параметров замыкания должны точно соответствовать требованию трейта. + +Примечание: Этот код ошибки больше не выдаётся компилятором.", + "\ +요구된 트레이트를 구현하지 않는 타입을 제공하려고 했습니다. +참고: 이 오류 코드는 더 이상 컴파일러에서 발생하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match closure parameter types to trait requirement", + "Сопоставьте типы параметров замыкания с требованием трейта", + "클로저 매개변수 타입을 트레이트 요구사항과 일치시킴" + ), + code: "fn foo(x: F) { }\n\nfn main() {\n foo(|y: usize| { }); // match usize\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Closures", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0281.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0283.rs b/masterror-knowledge/src/errors/types/e0283.rs new file mode 100644 index 0000000..d0a0713 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0283.rs @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0283: type annotation needed due to ambiguity + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0283", + title: LocalizedText::new( + "Type annotation needed due to ambiguity", + "Требуется аннотация типа из-за неоднозначности", + "모호성으로 인해 타입 어노테이션 필요" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The compiler could not infer a type due to ambiguity - multiple types +could satisfy the requirements. + +This typically happens with generic methods like `collect()` on iterators, +which have multiple valid implementations. The compiler cannot decide +between valid options without explicit type information.", + "\ +Компилятор не смог вывести тип из-за неоднозначности - несколько +типов могут удовлетворять требованиям. + +Это часто происходит с методами вроде `collect()` на итераторах, +которые имеют несколько допустимых реализаций.", + "\ +컴파일러가 모호성으로 인해 타입을 추론할 수 없습니다. +여러 타입이 요구사항을 충족할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add a type annotation", + "Добавьте аннотацию типа", + "타입 어노테이션 추가" + ), + code: "let x: Vec = \"hello\".chars().rev().collect();" + }, + FixSuggestion { + description: LocalizedText::new( + "Use turbofish syntax", + "Используйте синтаксис turbofish", + "터보피시 구문 사용" + ), + code: "let x = \"hello\".chars().rev().collect::>();" + }, + FixSuggestion { + description: LocalizedText::new( + "Use partial type annotation with placeholder", + "Используйте частичную аннотацию с заполнителем", + "플레이스홀더와 부분 타입 어노테이션 사용" + ), + code: "let x: Vec<_> = \"hello\".chars().rev().collect();" + } + ], + links: &[ + DocLink { + title: "Rust Book: Type Annotations", + url: "https://doc.rust-lang.org/book/ch03-02-data-types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0283.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0284.rs b/masterror-knowledge/src/errors/types/e0284.rs new file mode 100644 index 0000000..4652bf3 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0284.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0284: ambiguous return type inference + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0284", + title: LocalizedText::new( + "Ambiguous return type cannot be inferred", + "Неоднозначный возвращаемый тип не может быть выведен", + "모호한 반환 타입을 추론할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The compiler cannot unambiguously infer the return type of a generic +function or method. + +This commonly happens with methods like `into()` for type conversions, +where the return type is not explicitly specified and the compiler +cannot determine it from context due to multiple valid possibilities.", + "\ +Компилятор не может однозначно вывести возвращаемый тип обобщённой +функции или метода. + +Это часто происходит с методами вроде `into()` для преобразования типов, +где возвращаемый тип явно не указан и компилятор не может определить +его из контекста.", + "\ +컴파일러가 제네릭 함수나 메서드의 반환 타입을 명확하게 추론할 수 없습니다. +`into()` 같은 타입 변환 메서드에서 자주 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Explicitly type the intermediate expression", + "Явно укажите тип промежуточного выражения", + "중간 표현식의 타입을 명시적으로 지정" + ), + code: "let n: u32 = 1;\nlet mut d: u64 = 2;\nlet m: u64 = n.into(); // explicitly typed\nd = d + m;" + }, + FixSuggestion { + description: LocalizedText::new( + "Use turbofish syntax on the method", + "Используйте синтаксис turbofish для метода", + "메서드에 터보피시 구문 사용" + ), + code: "let n: u32 = 1;\nlet d: u64 = n.into::();" + } + ], + links: &[ + DocLink { + title: "Rust Book: Type Annotations", + url: "https://doc.rust-lang.org/book/ch03-02-data-types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0284.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0307.rs b/masterror-knowledge/src/errors/types/e0307.rs new file mode 100644 index 0000000..a3605a6 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0307.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0307: invalid receiver type for self parameter + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0307", + title: LocalizedText::new( + "Invalid receiver type for self parameter", + "Недопустимый тип получателя для параметра self", + "self 매개변수에 대한 잘못된 수신자 타입" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Methods in Rust take a special first parameter called the receiver. +Valid receiver types are: +- self (syntactic sugar for self: Self) +- &self (syntactic sugar for self: &Self) +- &mut self (syntactic sugar for self: &mut Self) +- self: Box, self: Rc, self: Arc +- self: Pin

where P is one of the above types + +The error occurs when using an invalid receiver type that doesn't match +these patterns.", + "\ +Методы в Rust принимают специальный первый параметр - получатель (receiver). +Допустимые типы получателя: +- self (сахар для self: Self) +- &self (сахар для self: &Self) +- &mut self (сахар для self: &mut Self) +- self: Box, self: Rc, self: Arc + +Ошибка возникает при использовании недопустимого типа получателя.", + "\ +Rust의 메서드는 수신자라는 특별한 첫 번째 매개변수를 받습니다. +유효한 수신자 타입: +- self (self: Self의 문법적 설탕) +- &self (self: &Self의 문법적 설탕) +- &mut self (self: &mut Self의 문법적 설탕) +- self: Box, self: Rc, self: Arc" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a valid receiver type", + "Использовать допустимый тип получателя", + "유효한 수신자 타입 사용" + ), + code: "impl Trait for Foo {\n fn foo(&self) {} // or &mut self, self, etc.\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Method Receivers", + url: "https://doc.rust-lang.org/reference/items/associated-items.html#methods" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0307.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0308.rs b/masterror-knowledge/src/errors/types/e0308.rs new file mode 100644 index 0000000..a01246f --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0308.rs @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0308", + title: LocalizedText::new("Mismatched types", "Несовпадение типов", "타입 불일치"), + category: Category::Types, + explanation: LocalizedText::new( + "Rust is statically typed and does NOT perform implicit type conversions.", + "Rust статически типизирован и НЕ выполняет неявные преобразования типов.", + "Rust는 정적 타입 언어이며 암시적 타입 변환을 수행하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new("Use parse()", "Использовать parse()", "parse() 사용"), + code: "let n: i32 = s.parse().unwrap();" + }, + FixSuggestion { + description: LocalizedText::new("Use 'as'", "Использовать 'as'", "'as' 사용"), + code: "let n = x as i32;" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0308.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0317.rs b/masterror-knowledge/src/errors/types/e0317.rs new file mode 100644 index 0000000..92b9366 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0317.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0317: if expression is missing an else block + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0317", + title: LocalizedText::new( + "If expression is missing an else block", + "Выражение if не имеет блока else", + "if 표현식에 else 블록이 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An if expression without an else block is used in a context where a type +other than () is expected. An if expression without else has type (), +which causes a type mismatch when the surrounding code expects a different +type value. + +Example: let a = if x == 5 { 1 }; fails because without else, the if +returns () when the condition is false, not an integer.", + "\ +Выражение if без блока else используется в контексте, где ожидается тип +отличный от (). Выражение if без else имеет тип (), что вызывает +несоответствие типов, когда окружающий код ожидает другое значение.", + "\ +else 블록이 없는 if 표현식이 () 이외의 타입이 예상되는 컨텍스트에서 사용되었습니다. +else가 없는 if 표현식은 () 타입을 가지며, 주변 코드가 다른 타입 값을 기대할 때 +타입 불일치가 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add else block with same return type", + "Добавить блок else с тем же типом возврата", + "동일한 반환 타입의 else 블록 추가" + ), + code: "let a = if x == 5 {\n 1\n} else {\n 2\n};" + } + ], + links: &[ + DocLink { + title: "Rust Book: if Expressions", + url: "https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0317.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0320.rs b/masterror-knowledge/src/errors/types/e0320.rs new file mode 100644 index 0000000..2f2430f --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0320.rs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0320: recursion limit reached while creating drop-check rules + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0320", + title: LocalizedText::new( + "Recursion limit reached while creating drop-check rules", + "Достигнут лимит рекурсии при создании правил drop-check", + "drop-check 규칙 생성 중 재귀 제한 도달" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The compiler must be able to reason about how a type is Dropped and the types +of its fields to generate proper cleanup code. This error occurs when the +compiler encounters a type with recursive drop-check rules that prevent it +from completing this analysis. + +This is not the same as infinite type size - the type has finite size, but +attempting to Drop it would recurse infinitely. The compiler cannot infer +the drop behavior for recursively-defined types.", + "\ +Компилятор должен иметь возможность рассуждать о том, как тип освобождается +(Drop) и о типах его полей для генерации кода очистки. Эта ошибка возникает, +когда компилятор встречает тип с рекурсивными правилами drop-check. + +Это не то же самое, что бесконечный размер типа - тип имеет конечный размер, +но попытка вызвать Drop приведёт к бесконечной рекурсии.", + "\ +컴파일러는 적절한 정리 코드를 생성하기 위해 타입이 어떻게 Drop되는지와 +필드 타입에 대해 추론할 수 있어야 합니다. 컴파일러가 재귀적 drop-check 규칙을 +가진 타입을 만나면 이 오류가 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove recursive structure in type definition", + "Удалить рекурсивную структуру в определении типа", + "타입 정의에서 재귀 구조 제거" + ), + code: "// Redesign type hierarchy to avoid infinite\n// recursion in drop-check analysis" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Drop Trait", + url: "https://doc.rust-lang.org/std/ops/trait.Drop.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0320.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0366.rs b/masterror-knowledge/src/errors/types/e0366.rs new file mode 100644 index 0000000..ed383f0 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0366.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0366: Drop implemented on concrete specialization of generic type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0366", + title: LocalizedText::new( + "Drop on concrete specialization of generic type", + "Drop на конкретной специализации обобщённого типа", + "제네릭 타입의 구체적 특수화에 대한 Drop" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Rust does not allow implementing Drop for a specific concrete type that is a +specialization of a generic struct. This would violate coherence rules - you +cannot specialize Drop to only work for a subset of implementations of a +generic type. + +Example: impl Drop for Foo {} is not allowed when Foo is generic.", + "\ +Rust не позволяет реализовывать Drop для конкретного типа, который является +специализацией обобщённой структуры. Это нарушило бы правила когерентности - +нельзя специализировать Drop только для подмножества реализаций обобщённого типа. + +Пример: impl Drop for Foo {} не разрешён, когда Foo обобщённый.", + "\ +Rust는 제네릭 구조체의 특수화인 특정 구체적 타입에 대해 Drop을 구현하는 것을 +허용하지 않습니다. 이는 일관성 규칙을 위반합니다 - 제네릭 타입 구현의 하위 집합에 +대해서만 Drop을 특수화할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Wrap in non-generic struct and implement Drop on wrapper", + "Обернуть в необобщённую структуру и реализовать Drop", + "비제네릭 구조체로 감싸고 래퍼에 Drop 구현" + ), + code: "struct Bar {\n t: Foo\n}\n\nimpl Drop for Bar {\n fn drop(&mut self) {}\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Drop Trait", + url: "https://doc.rust-lang.org/std/ops/trait.Drop.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0366.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0367.rs b/masterror-knowledge/src/errors/types/e0367.rs new file mode 100644 index 0000000..8993129 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0367.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0367: Drop implemented on specialized generic type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0367", + title: LocalizedText::new( + "Drop implemented on specialized generic type", + "Drop реализован на специализированном обобщённом типе", + "특수화된 제네릭 타입에 Drop이 구현됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Rust does not allow implementing Drop for a specialized version of a generic +type. Drop cannot be specialized to only apply to a subset of implementations +of a generic type. + +Example: impl Drop for MyStruct {} is not allowed because it +specializes Drop only for T that implements Foo.", + "\ +Rust не позволяет реализовывать Drop для специализированной версии обобщённого +типа. Drop нельзя специализировать только для подмножества реализаций. + +Пример: impl Drop for MyStruct {} не разрешён, потому что +специализирует Drop только для T, реализующих Foo.", + "\ +Rust는 제네릭 타입의 특수화된 버전에 대해 Drop을 구현하는 것을 허용하지 않습니다. +Drop은 제네릭 타입 구현의 하위 집합에만 적용되도록 특수화될 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add trait bound to struct definition", + "Добавить ограничение трейта в определение структуры", + "구조체 정의에 트레이트 바운드 추가" + ), + code: "struct MyStruct {\n t: T\n}\n\nimpl Drop for MyStruct {\n fn drop(&mut self) {}\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use wrapper struct with trait bounds", + "Использовать обёртку с ограничениями трейтов", + "트레이트 바운드가 있는 래퍼 구조체 사용" + ), + code: "struct MyStructWrapper {\n t: MyStruct\n}\n\nimpl Drop for MyStructWrapper {\n fn drop(&mut self) {}\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Drop Trait", + url: "https://doc.rust-lang.org/std/ops/trait.Drop.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0367.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0368.rs b/masterror-knowledge/src/errors/types/e0368.rs new file mode 100644 index 0000000..cdba217 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0368.rs @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0368: binary assignment operator applied to unsupported type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0368", + title: LocalizedText::new( + "Binary assignment operator cannot be applied to type", + "Бинарный оператор присваивания не применим к типу", + "이항 대입 연산자를 타입에 적용할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A binary assignment operator (like +=, -=, <<=, ^=, etc.) is applied to a +type that doesn't implement the corresponding assignment trait. + +Common causes: +1. The type doesn't support the operation (e.g., <<= on f32) +2. You implemented the operator trait (e.g., Add) but not the assignment + variant (e.g., AddAssign)", + "\ +Бинарный оператор присваивания (например +=, -=, <<=, ^=) применён к типу, +который не реализует соответствующий трейт присваивания. + +Частые причины: +1. Тип не поддерживает операцию (например <<= для f32) +2. Реализован трейт оператора (Add), но не трейт присваивания (AddAssign)", + "\ +이항 대입 연산자(+=, -=, <<=, ^= 등)가 해당 대입 트레이트를 구현하지 않는 +타입에 적용되었습니다. + +일반적인 원인: +1. 타입이 연산을 지원하지 않음 (예: f32에 <<=) +2. 연산자 트레이트(Add)는 구현했지만 대입 변형(AddAssign)은 구현하지 않음" + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Implement the assignment trait", + "Реализовать трейт присваивания", + "대입 트레이트 구현" + ), + code: "use std::ops::AddAssign;\n\nimpl AddAssign for Foo {\n fn add_assign(&mut self, rhs: Foo) {\n self.0 += rhs.0;\n }\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use a type that supports the operation", + "Использовать тип, поддерживающий операцию", + "연산을 지원하는 타입 사용" + ), + code: "let mut x = 12u32; // u32 supports <<=\nx <<= 2;" + } + ], + links: &[ + DocLink { + title: "Rust std::ops Module", + url: "https://doc.rust-lang.org/std/ops/index.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0368.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0369.rs b/masterror-knowledge/src/errors/types/e0369.rs new file mode 100644 index 0000000..d5cf0f1 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0369.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0369: binary operation cannot be applied to type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0369", + title: LocalizedText::new( + "Binary operation cannot be applied to type", + "Бинарная операция не применима к типу", + "이항 연산을 타입에 적용할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A binary operation was attempted on a type which doesn't support it. +This error occurs when trying to use an operator (like <<, +, -, etc.) +with a type that hasn't implemented the corresponding trait from std::ops. + +Example: f32 doesn't implement left shift (<<), so 12f32 << 2 fails.", + "\ +Бинарная операция была применена к типу, который её не поддерживает. +Эта ошибка возникает при попытке использовать оператор (<<, +, - и т.д.) +с типом, который не реализовал соответствующий трейт из std::ops. + +Пример: f32 не реализует сдвиг влево (<<), поэтому 12f32 << 2 не работает.", + "\ +지원하지 않는 타입에 이항 연산이 시도되었습니다. +std::ops의 해당 트레이트를 구현하지 않은 타입에 연산자(<<, +, - 등)를 +사용하려고 할 때 이 오류가 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a compatible type", + "Использовать совместимый тип", + "호환되는 타입 사용" + ), + code: "let x = 12u32; // u32 supports <<\nx << 2;" + }, + FixSuggestion { + description: LocalizedText::new( + "Implement the operator trait for custom types", + "Реализовать трейт оператора для своего типа", + "사용자 정의 타입에 연산자 트레이트 구현" + ), + code: "use std::ops::Add;\n\nimpl Add for MyType {\n type Output = MyType;\n fn add(self, rhs: Self) -> Self::Output {\n // ...\n }\n}" + } + ], + links: &[ + DocLink { + title: "Rust std::ops Module", + url: "https://doc.rust-lang.org/std/ops/index.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0369.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0370.rs b/masterror-knowledge/src/errors/types/e0370.rs new file mode 100644 index 0000000..bbcbf94 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0370.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0370: enum discriminant overflow + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0370", + title: LocalizedText::new( + "Enum discriminant overflow", + "Переполнение дискриминанта перечисления", + "열거형 판별자 오버플로우" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The maximum value of an enum was reached, so it cannot be automatically set +in the next enum value. When an enum variant's discriminant reaches the maximum +value for its representation type, the compiler cannot automatically assign +the next sequential value to the following variant. + +Example: #[repr(i64)] enum with X = 0x7fffffffffffffff cannot have Y after it +without explicit value.", + "\ +Достигнуто максимальное значение enum, поэтому следующее значение не может +быть установлено автоматически. Когда дискриминант варианта достигает +максимального значения для типа представления, компилятор не может +автоматически назначить следующее последовательное значение.", + "\ +열거형의 최대값에 도달하여 다음 열거형 값을 자동으로 설정할 수 없습니다. +열거형 변형의 판별자가 표현 타입의 최대값에 도달하면, 컴파일러는 +다음 변형에 순차적 값을 자동으로 할당할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Explicitly set the next enum value", + "Явно установить следующее значение enum", + "다음 열거형 값을 명시적으로 설정" + ), + code: "#[repr(i64)]\nenum Foo {\n X = 0x7fffffffffffffff,\n Y = 0, // explicit value\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Place maximum value variant at the end", + "Поместить вариант с максимальным значением в конец", + "최대값 변형을 끝에 배치" + ), + code: "#[repr(i64)]\nenum Foo {\n Y = 0,\n X = 0x7fffffffffffffff, // last variant\n}" + } + ], + links: &[ + DocLink { + title: "Rust Reference: Enumerations", + url: "https://doc.rust-lang.org/reference/items/enumerations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0370.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0391.rs b/masterror-knowledge/src/errors/types/e0391.rs new file mode 100644 index 0000000..dac44d0 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0391.rs @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0391: type dependency cycle detected + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0391", + title: LocalizedText::new( + "Type dependency cycle detected", + "Обнаружен цикл зависимости типов", + "타입 의존성 순환이 감지됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type dependency cycle has been encountered. This occurs when there is a +circular dependency between types, typically involving trait definitions. + +This creates an impossible situation where a type depends on itself (directly +or indirectly) through trait bounds. + +Example of cyclic dependency: +- FirstTrait has a supertrait bound on SecondTrait +- SecondTrait has a supertrait bound on FirstTrait +- This creates a circular dependency that cannot be resolved", + "\ +Обнаружен цикл зависимости типов. Это происходит при наличии круговой +зависимости между типами, обычно связанной с определениями трейтов. + +Это создаёт невозможную ситуацию, когда тип зависит от себя (прямо или +косвенно) через ограничения трейтов. + +Пример циклической зависимости: +- FirstTrait имеет супертрейт SecondTrait +- SecondTrait имеет супертрейт FirstTrait +- Это создаёт круговую зависимость, которую невозможно разрешить", + "\ +타입 의존성 순환이 발견되었습니다. 이는 일반적으로 트레이트 정의를 포함하여 +타입 간에 순환 의존성이 있을 때 발생합니다. + +이는 타입이 트레이트 바운드를 통해 (직접 또는 간접적으로) 자기 자신에게 +의존하는 불가능한 상황을 만듭니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove one of the trait bounds to break the cycle", + "Удалить одно из ограничений трейта для разрыва цикла", + "순환을 끊기 위해 트레이트 바운드 중 하나 제거" + ), + code: "trait FirstTrait {\n // No supertrait bound\n}\n\ntrait SecondTrait : FirstTrait {\n // Only one direction of dependency\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Restructure trait hierarchy to avoid cycles", + "Реструктурировать иерархию трейтов для избежания циклов", + "순환을 피하기 위해 트레이트 계층 구조 재구성" + ), + code: "trait Base {}\ntrait FirstTrait : Base {}\ntrait SecondTrait : Base {}" + } + ], + links: &[ + DocLink { + title: "Rustc Dev Guide: Queries", + url: "https://rustc-dev-guide.rust-lang.org/query.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0391.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0392.rs b/masterror-knowledge/src/errors/types/e0392.rs new file mode 100644 index 0000000..76c7f7e --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0392.rs @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0392: unused type or lifetime parameter + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0392", + title: LocalizedText::new( + "Unused type or lifetime parameter", + "Неиспользуемый параметр типа или времени жизни", + "사용되지 않는 타입 또는 라이프타임 매개변수" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type or lifetime parameter has been declared but is not actually used. +The compiler requires that all declared generic parameters be utilized in +the definition. + +If you need to specify a lifetime constraint with raw pointers without +storing actual data, use PhantomData to tell the compiler about the +relationship.", + "\ +Параметр типа или времени жизни объявлен, но фактически не используется. +Компилятор требует, чтобы все объявленные параметры были использованы. + +Если нужно указать ограничение времени жизни с сырыми указателями без +хранения данных, используйте PhantomData.", + "\ +타입 또는 라이프타임 매개변수가 선언되었지만 실제로 사용되지 않습니다. +컴파일러는 선언된 모든 제네릭 매개변수가 정의에서 사용되어야 합니다. + +원시 포인터와 함께 라이프타임 제약을 지정해야 하지만 실제 데이터를 +저장하지 않는 경우 PhantomData를 사용하세요." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove unused parameter", + "Удалить неиспользуемый параметр", + "사용되지 않는 매개변수 제거" + ), + code: "enum Foo {\n Bar,\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use the parameter in the type", + "Использовать параметр в типе", + "타입에서 매개변수 사용" + ), + code: "enum Foo {\n Bar(T),\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Use PhantomData for lifetime constraints", + "Использовать PhantomData для ограничений времени жизни", + "라이프타임 제약에 PhantomData 사용" + ), + code: "use std::marker::PhantomData;\n\nstruct Foo<'a, T: 'a> {\n x: *const T,\n phantom: PhantomData<&'a T>\n}" + } + ], + links: &[ + DocLink { + title: "Rust std::marker::PhantomData", + url: "https://doc.rust-lang.org/std/marker/struct.PhantomData.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0392.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0472.rs b/masterror-knowledge/src/errors/types/e0472.rs new file mode 100644 index 0000000..6de9789 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0472.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0472: inline assembly not supported on target + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0472", + title: LocalizedText::new( + "Inline assembly not supported on this target", + "Встроенный ассемблер не поддерживается для этой цели", + "이 타겟에서 인라인 어셈블리가 지원되지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An attempt was made to use the asm! macro for inline assembly on a target +architecture that does not support it. While all Tier 1 targets support +inline assembly, support among Tier 2 and 3 targets is not guaranteed. + +This error indicates that support for your target is not planned or in +progress (as opposed to E0658 which indicates an unstable feature).", + "\ +Попытка использовать макрос asm! для встроенного ассемблера на целевой +архитектуре, которая его не поддерживает. Хотя все цели Tier 1 +поддерживают встроенный ассемблер, поддержка для Tier 2 и 3 не гарантирована. + +Эта ошибка указывает, что поддержка для вашей цели не планируется.", + "\ +인라인 어셈블리를 지원하지 않는 타겟 아키텍처에서 asm! 매크로를 +사용하려고 시도했습니다. 모든 Tier 1 타겟은 인라인 어셈블리를 +지원하지만, Tier 2 및 3 타겟 간의 지원은 보장되지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Write assembly externally and link it", + "Написать ассемблер отдельно и связать", + "외부에 어셈블리 작성 후 링크" + ), + code: "// Compile .s file separately and link\n// Or contribute support to Rust" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0472.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0476.rs b/masterror-knowledge/src/errors/types/e0476.rs new file mode 100644 index 0000000..d4e417e --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0476.rs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0476: coerced type doesn't outlive the value being coerced to + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0476", + title: LocalizedText::new( + "Coerced type doesn't outlive the value being coerced to", + "Приводимый тип не переживает значение, к которому приводится", + "강제 변환된 타입이 변환 대상 값보다 오래 살지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs during type coercion when the source pointer's lifetime +does not outlive the lifetime bound of the target type. In the coercion, +'b (source lifetime) is not a subtype of 'a (target lifetime requirement). + +This error can currently only be encountered with the unstable CoerceUnsized +trait.", + "\ +Эта ошибка возникает при приведении типов, когда время жизни исходного +указателя не переживает ограничение времени жизни целевого типа. +При приведении 'b (исходное время жизни) не является подтипом 'a +(требование целевого времени жизни). + +Эта ошибка может возникнуть только с нестабильным трейтом CoerceUnsized.", + "\ +이 오류는 타입 강제 변환 중 소스 포인터의 라이프타임이 대상 타입의 +라이프타임 바운드보다 오래 살지 않을 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Ensure source lifetime outlives target", + "Обеспечить, чтобы исходное время жизни пережило целевое", + "소스 라이프타임이 대상보다 오래 살도록 보장" + ), + code: "// Ensure 'b: 'a (source outlives target)" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0476.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0511.rs b/masterror-knowledge/src/errors/types/e0511.rs new file mode 100644 index 0000000..bd0b464 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0511.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0511: invalid monomorphization of intrinsic function + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0511", + title: LocalizedText::new( + "Invalid monomorphization of intrinsic function", + "Неверная мономорфизация внутренней функции", + "내장 함수의 잘못된 단형화" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +This error occurs when an intrinsic function is used with an invalid type +during monomorphization. For SIMD intrinsics like `simd_add`, the generic type +parameter must be a SIMD type, not a scalar type like `i32`. + +Intrinsic functions have specific type requirements that must be satisfied.", + "\ +Эта ошибка возникает, когда внутренняя функция используется с неверным +типом при мономорфизации. Для SIMD-функций, таких как `simd_add`, +параметр типа должен быть SIMD-типом, а не скаляром вроде `i32`.", + "\ +이 오류는 단형화 중 내장 함수가 잘못된 타입으로 사용될 때 발생합니다. +`simd_add`와 같은 SIMD 내장 함수의 경우 제네릭 타입 매개변수는 +`i32`와 같은 스칼라 타입이 아닌 SIMD 타입이어야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use a SIMD type instead of scalar", + "Использовать SIMD-тип вместо скаляра", + "스칼라 대신 SIMD 타입 사용" + ), + code: "#[repr(simd)]\n#[derive(Copy, Clone)]\nstruct i32x2([i32; 2]);\n\nunsafe { simd_add(i32x2([0, 0]), i32x2([1, 2])); }" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0511.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0512.rs b/masterror-knowledge/src/errors/types/e0512.rs new file mode 100644 index 0000000..035fc3c --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0512.rs @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0512: transmute with differently sized types + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0512", + title: LocalizedText::new( + "Cannot transmute between types of different sizes", + "Нельзя преобразовать типы разных размеров", + "크기가 다른 타입 간에 변환할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A transmute with two differently sized types was attempted. The `transmute` +function requires both the source and destination types to be the same size +in bytes, as it performs a bitwise reinterpretation of the data. + +This is a fundamental requirement of transmute - you cannot change the size +of data during transmutation.", + "\ +Попытка преобразования между типами разного размера. Функция `transmute` +требует, чтобы исходный и целевой типы имели одинаковый размер в байтах, +так как она выполняет побитовую реинтерпретацию данных.", + "\ +크기가 다른 두 타입 간의 transmute가 시도되었습니다. `transmute` 함수는 +소스와 대상 타입이 바이트 단위로 같은 크기여야 합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use types with the same size", + "Использовать типы одинакового размера", + "같은 크기의 타입 사용" + ), + code: "unsafe { takes_u8(std::mem::transmute(0i8)); } // i8 and u8 same size" + }, + FixSuggestion { + description: LocalizedText::new( + "Use direct type conversion instead", + "Использовать прямое преобразование типа", + "대신 직접 타입 변환 사용" + ), + code: "takes_u8(0u8); // direct conversion" + } + ], + links: &[ + DocLink { + title: "std::mem::transmute", + url: "https://doc.rust-lang.org/std/mem/fn.transmute.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0512.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0516.rs b/masterror-knowledge/src/errors/types/e0516.rs new file mode 100644 index 0000000..80abc4c --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0516.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0516: typeof keyword is reserved but unimplemented + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0516", + title: LocalizedText::new( + "The `typeof` keyword is reserved but unimplemented", + "Ключевое слово `typeof` зарезервировано, но не реализовано", + "`typeof` 키워드는 예약되었지만 구현되지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `typeof` keyword was used in code, but this keyword is currently reserved +for future use and not implemented in the Rust compiler. + +Note: This error code is no longer emitted by the compiler.", + "\ +Ключевое слово `typeof` было использовано в коде, но оно зарезервировано +для будущего использования и не реализовано в компиляторе Rust. + +Примечание: этот код ошибки больше не выдаётся компилятором.", + "\ +`typeof` 키워드가 코드에서 사용되었지만, 이 키워드는 현재 향후 사용을 위해 +예약되어 있으며 Rust 컴파일러에서 구현되지 않았습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use type inference instead", + "Использовать вывод типов", + "타입 추론 사용" + ), + code: "let x = 92; // compiler infers i32" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0516.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0527.rs b/masterror-knowledge/src/errors/types/e0527.rs new file mode 100644 index 0000000..b9b6aa0 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0527.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0527: pattern requires N elements but array has M + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0527", + title: LocalizedText::new( + "Pattern requires different number of elements than array", + "Образец требует другое количество элементов, чем в массиве", + "패턴이 배열과 다른 수의 요소를 요구함" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The number of elements in an array or slice pattern differs from the number +of elements in the array being matched. When matching against arrays, the +pattern must account for the correct number of elements. + +Use the `..` pattern to capture remaining elements when you don't need to +match all elements explicitly.", + "\ +Количество элементов в образце массива или среза отличается от количества +элементов в сопоставляемом массиве. При сопоставлении с массивами образец +должен учитывать правильное количество элементов. + +Используйте `..` для захвата оставшихся элементов.", + "\ +배열 또는 슬라이스 패턴의 요소 수가 매칭되는 배열의 요소 수와 다릅니다. +배열과 매칭할 때 패턴은 올바른 수의 요소를 설명해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use `..` to match remaining elements", + "Использовать `..` для сопоставления остальных элементов", + "`..`를 사용하여 나머지 요소 매칭" + ), + code: "match r {\n &[a, b, ..] => println!(\"a={}, b={}\", a, b),\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0527.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0528.rs b/masterror-knowledge/src/errors/types/e0528.rs new file mode 100644 index 0000000..71ef50c --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0528.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0528: pattern requires at least N elements but array has M + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0528", + title: LocalizedText::new( + "Pattern requires at least N elements but array has fewer", + "Образец требует минимум N элементов, но массив содержит меньше", + "패턴이 최소 N개의 요소를 요구하지만 배열이 더 적음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An array or slice pattern requires more elements than are present in the +matched array. Even with the `..` operator for remaining elements, the +pattern specifies a minimum number of required elements. + +The matched array must have at least as many elements as explicitly required +by the pattern.", + "\ +Образец массива или среза требует больше элементов, чем присутствует +в сопоставляемом массиве. Даже с оператором `..` для оставшихся элементов +образец указывает минимальное количество требуемых элементов.", + "\ +배열 또는 슬라이스 패턴이 매칭된 배열에 있는 것보다 더 많은 요소를 요구합니다. +나머지 요소를 위한 `..` 연산자를 사용해도 패턴은 최소 요소 수를 지정합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Ensure array has enough elements", + "Убедиться, что массив содержит достаточно элементов", + "배열에 충분한 요소가 있는지 확인" + ), + code: "let r = &[1, 2, 3, 4, 5];\nmatch r {\n &[a, b, c, rest @ ..] => { /* ok */ }\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0528.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0529.rs b/masterror-knowledge/src/errors/types/e0529.rs new file mode 100644 index 0000000..a815759 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0529.rs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0529: expected array or slice, found different type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0529", + title: LocalizedText::new( + "Expected an array or slice, found different type", + "Ожидался массив или срез, найден другой тип", + "배열 또는 슬라이스가 예상되었지만 다른 타입 발견" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An array or slice pattern was matched against a value that is not an array +or slice type. The pattern syntax `[a, b]` expects the matched expression +to be an array or slice, but a different type was provided. + +Ensure the pattern and the expression being matched are of consistent types.", + "\ +Образец массива или среза был сопоставлен со значением, которое не является +массивом или срезом. Синтаксис образца `[a, b]` ожидает, что сопоставляемое +выражение будет массивом или срезом.", + "\ +배열 또는 슬라이스 패턴이 배열이나 슬라이스 타입이 아닌 값과 매칭되었습니다. +패턴 구문 `[a, b]`는 매칭되는 표현식이 배열 또는 슬라이스일 것으로 예상합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use an array or slice as the matched value", + "Использовать массив или срез как сопоставляемое значение", + "매칭되는 값으로 배열 또는 슬라이스 사용" + ), + code: "let r = [1.0, 2.0];\nmatch r {\n [a, b] => println!(\"a={}, b={}\", a, b),\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0529.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0559.rs b/masterror-knowledge/src/errors/types/e0559.rs new file mode 100644 index 0000000..f5a164b --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0559.rs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0559: unknown field in enum struct variant + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0559", + title: LocalizedText::new( + "Unknown field in enum struct variant", + "Неизвестное поле в структурном варианте перечисления", + "열거형 구조체 변형에 알 수 없는 필드" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unknown field was specified in an enum's struct variant. This error occurs +when you try to initialize a struct variant of an enum with a field name that +doesn't exist in that variant's definition. + +Verify that you're using the correct field name as defined in the enum variant.", + "\ +Неизвестное поле было указано в структурном варианте перечисления. +Эта ошибка возникает при попытке инициализировать структурный вариант +перечисления с именем поля, которое не существует в определении варианта.", + "\ +열거형의 구조체 변형에 알 수 없는 필드가 지정되었습니다. 이 오류는 +해당 변형의 정의에 존재하지 않는 필드 이름으로 열거형의 구조체 변형을 +초기화하려고 할 때 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use the correct field name", + "Использовать правильное имя поля", + "올바른 필드 이름 사용" + ), + code: "enum Field { Fool { x: u32 } }\nlet s = Field::Fool { x: 0 }; // use 'x' not 'joke'" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0559.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0560.rs b/masterror-knowledge/src/errors/types/e0560.rs new file mode 100644 index 0000000..69780d6 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0560.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0560: unknown field in struct + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0560", + title: LocalizedText::new( + "Unknown field specified in struct", + "Неизвестное поле указано в структуре", + "구조체에 알 수 없는 필드 지정" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unknown field was specified in a structure. This error occurs when you try +to initialize a struct with a field name that doesn't exist in the struct +definition. The compiler cannot find the specified field. + +Verify that the field name is spelled correctly and actually exists in the +struct definition.", + "\ +Неизвестное поле было указано в структуре. Эта ошибка возникает при попытке +инициализировать структуру с именем поля, которое не существует в определении +структуры. Компилятор не может найти указанное поле.", + "\ +구조체에 알 수 없는 필드가 지정되었습니다. 이 오류는 구조체 정의에 +존재하지 않는 필드 이름으로 구조체를 초기화하려고 할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Add the missing field to struct definition", + "Добавить отсутствующее поле в определение структуры", + "구조체 정의에 누락된 필드 추가" + ), + code: "struct Simba {\n mother: u32,\n father: u32, // add missing field\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Remove the erroneous field from initialization", + "Удалить ошибочное поле из инициализации", + "초기화에서 잘못된 필드 제거" + ), + code: "let s = Simba { mother: 1 }; // remove non-existent field" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0560.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0561.rs b/masterror-knowledge/src/errors/types/e0561.rs new file mode 100644 index 0000000..5aca99a --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0561.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0561: non-ident pattern in function pointer type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0561", + title: LocalizedText::new( + "Non-ident pattern in function pointer type parameter", + "Не-идентификаторный образец в параметре типа указателя на функцию", + "함수 포인터 타입 매개변수에 비식별자 패턴" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A non-ident or non-wildcard pattern is used as a parameter in a function +pointer type. When defining a type alias for a function pointer, you cannot +use patterns like `mut` or reference patterns (`&`) on parameters. + +Only simple identifiers or wildcards (`_`) are allowed in function pointer +type definitions.", + "\ +Не-идентификаторный или не-подстановочный образец используется в качестве +параметра в типе указателя на функцию. При определении псевдонима типа +для указателя на функцию нельзя использовать образцы вроде `mut` или `&`.", + "\ +함수 포인터 타입의 매개변수로 비식별자 또는 비와일드카드 패턴이 사용되었습니다. +함수 포인터에 대한 타입 별칭을 정의할 때 `mut`이나 참조 패턴(`&`)을 +매개변수에 사용할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove patterns from parameter", + "Удалить образцы из параметра", + "매개변수에서 패턴 제거" + ), + code: "type A1 = fn(param: u8); // ok\ntype A2 = fn(_: u32); // wildcard ok" + }, + FixSuggestion { + description: LocalizedText::new( + "Omit parameter name entirely", + "Полностью опустить имя параметра", + "매개변수 이름 완전히 생략" + ), + code: "type A3 = fn(i16); // ok" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0561.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0562.rs b/masterror-knowledge/src/errors/types/e0562.rs new file mode 100644 index 0000000..00b5032 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0562.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0562: impl Trait only allowed in function signatures + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0562", + title: LocalizedText::new( + "`impl Trait` only allowed in function signatures", + "`impl Trait` разрешён только в сигнатурах функций", + "`impl Trait`는 함수 시그니처에서만 허용됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `impl Trait` syntax can only be used in specific contexts: +- As a function return type +- As a function argument type + +It cannot be used in variable type annotations or other contexts like +struct fields or const declarations.", + "\ +Синтаксис `impl Trait` можно использовать только в определённых контекстах: +- Как возвращаемый тип функции +- Как тип аргумента функции + +Его нельзя использовать в аннотациях типов переменных или других контекстах.", + "\ +`impl Trait` 구문은 특정 컨텍스트에서만 사용할 수 있습니다: +- 함수 반환 타입으로 +- 함수 인수 타입으로 + +변수 타입 어노테이션이나 다른 컨텍스트에서는 사용할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Move `impl Trait` to function return type", + "Переместить `impl Trait` в возвращаемый тип функции", + "`impl Trait`를 함수 반환 타입으로 이동" + ), + code: "fn count_to_n(n: usize) -> impl Iterator {\n 0..n\n}" + }], + links: &[ + DocLink { + title: "impl Trait Reference", + url: "https://doc.rust-lang.org/stable/reference/types/impl-trait.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0562.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0573.rs b/masterror-knowledge/src/errors/types/e0573.rs new file mode 100644 index 0000000..f518bbe --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0573.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0573: expected type, found something else + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0573", + title: LocalizedText::new( + "Expected a type, found something else", + "Ожидался тип, найдено что-то другое", + "타입이 예상되었지만 다른 것이 발견됨" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Something other than a type has been used when one was expected. This commonly +happens when using an enum variant, constant, or other value in a context that +requires a type, such as: +- Return type annotations +- `impl` blocks +- Function parameter type annotations +- Trait method signatures + +Always use actual types (structs, enums, traits) in type positions, not their +variants or values.", + "\ +Вместо типа было использовано что-то другое. Это часто происходит при +использовании варианта перечисления, константы или другого значения +в контексте, требующем тип, например: +- Аннотации возвращаемого типа +- Блоки `impl` +- Аннотации типов параметров функций", + "\ +타입이 예상되는 곳에 타입이 아닌 것이 사용되었습니다. 이는 열거형 변형, +상수 또는 다른 값이 다음과 같은 타입이 필요한 컨텍스트에서 사용될 때 +자주 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use the enum type, not the variant", + "Использовать тип перечисления, а не вариант", + "변형이 아닌 열거형 타입 사용" + ), + code: "fn oblivion() -> Dragon { // not Dragon::Born\n Dragon::Born\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Create a newtype struct for impl blocks", + "Создать новый тип структуры для блоков impl", + "impl 블록을 위한 뉴타입 구조체 생성" + ), + code: "struct Hobbit(u32);\nconst HOBBIT: Hobbit = Hobbit(2);\nimpl Hobbit {} // ok" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0573.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0574.rs b/masterror-knowledge/src/errors/types/e0574.rs new file mode 100644 index 0000000..0c1551e --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0574.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0574: expected struct/variant/union, found something else + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0574", + title: LocalizedText::new( + "Expected struct, variant or union, found something else", + "Ожидалась структура, вариант или объединение", + "구조체, 변형 또는 유니온이 예상되었지만 다른 것 발견" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Something other than a struct, variant or union has been used when one was +expected. This error occurs when you attempt to instantiate or pattern match +against something that isn't a struct, variant, or union. + +The compiler expects a concrete type that can be instantiated with field +initialization syntax `{ }`, but received something else (like a module or +an enum instead of its variant).", + "\ +Вместо структуры, варианта или объединения было использовано что-то другое. +Эта ошибка возникает при попытке создать экземпляр или сопоставить с образцом +что-то, что не является структурой, вариантом или объединением.", + "\ +구조체, 변형 또는 유니온이 예상되는 곳에 다른 것이 사용되었습니다. +이 오류는 구조체, 변형 또는 유니온이 아닌 것을 인스턴스화하거나 +패턴 매칭하려고 할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use full path to struct in module", + "Использовать полный путь к структуре в модуле", + "모듈 내 구조체의 전체 경로 사용" + ), + code: "mod mordor { pub struct TheRing { pub x: usize } }\nlet sauron = mordor::TheRing { x: 1 };" + }, + FixSuggestion { + description: LocalizedText::new( + "Match enum variant, not the enum itself", + "Сопоставлять вариант перечисления, а не само перечисление", + "열거형 자체가 아닌 열거형 변형과 매칭" + ), + code: "match eco {\n Jak::Daxter { i } => {} // not just Jak { i }\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0574.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0575.rs b/masterror-knowledge/src/errors/types/e0575.rs new file mode 100644 index 0000000..7327119 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0575.rs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0575: expected type or associated type, found something else + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0575", + title: LocalizedText::new( + "Expected type or associated type, found something else", + "Ожидался тип или ассоциированный тип", + "타입 또는 연관 타입이 예상되었지만 다른 것 발견" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Something other than a type or an associated type was given where one was +expected. This error occurs when you attempt to use a non-type construct +(such as an enum variant or trait method) in a context that requires a type +annotation. + +Use the enum itself as the type, not the variant. For traits, use the +associated type, not methods.", + "\ +Вместо типа или ассоциированного типа было указано что-то другое. +Эта ошибка возникает при попытке использовать не-типовую конструкцию +(например, вариант перечисления или метод трейта) в контексте, +требующем аннотации типа.", + "\ +타입 또는 연관 타입이 예상되는 곳에 다른 것이 주어졌습니다. +이 오류는 열거형 변형이나 트레이트 메서드와 같은 비타입 구성을 +타입 어노테이션이 필요한 컨텍스트에서 사용하려고 할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use the enum type, not its variant", + "Использовать тип перечисления, а не вариант", + "변형이 아닌 열거형 타입 사용" + ), + code: "enum Rick { Morty }\nlet _: Rick; // not ::Morty" + }, + FixSuggestion { + description: LocalizedText::new( + "Use associated type, not method", + "Использовать ассоциированный тип, а не метод", + "메서드가 아닌 연관 타입 사용" + ), + code: "let _: ::Empire; // not ::Mythology" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0575.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0591.rs b/masterror-knowledge/src/errors/types/e0591.rs new file mode 100644 index 0000000..67b00fb --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0591.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0591: transmuting function items vs function pointers + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0591", + title: LocalizedText::new( + "Cannot transmute between function items and pointers", + "Нельзя преобразовать между элементами функций и указателями", + "함수 항목과 포인터 간에 변환할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Per RFC 401, function items have a unique, zero-sized marker type that is +distinct from function pointers. While the language typically coerces function +items to function pointers automatically, this distinction becomes problematic +when using `transmute`. + +The key issue is: +- Function items (e.g., `typeof(foo)`) are zero-sized types +- Function pointers (e.g., `fn(S)`) are not zero-sized + +Transmuting directly between these types is incorrect because their sizes +don't match.", + "\ +Согласно RFC 401, элементы функций имеют уникальный тип-маркер нулевого +размера, отличный от указателей на функции. Хотя язык обычно автоматически +приводит элементы функций к указателям, это различие становится проблемой +при использовании `transmute`.", + "\ +RFC 401에 따르면 함수 항목은 함수 포인터와 구별되는 고유한 크기가 0인 +마커 타입을 갖습니다. 언어는 일반적으로 함수 항목을 함수 포인터로 +자동 변환하지만, `transmute` 사용 시 이 구분이 문제가 됩니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Cast to function pointer before transmute", + "Привести к указателю на функцию перед transmute", + "transmute 전에 함수 포인터로 캐스트" + ), + code: "let f: extern \"C\" fn(*mut i32) = transmute(foo as extern \"C\" fn(_));" + }, + FixSuggestion { + description: LocalizedText::new( + "Cast to usize before transmute", + "Привести к usize перед transmute", + "transmute 전에 usize로 캐스트" + ), + code: "let f: extern \"C\" fn(*mut i32) = transmute(foo as usize);" + } + ], + links: &[ + DocLink { + title: "RFC 401: Coercions", + url: "https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0591.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0599.rs b/masterror-knowledge/src/errors/types/e0599.rs new file mode 100644 index 0000000..84a2802 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0599.rs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0599", + title: LocalizedText::new( + "No method named X found for type", + "Метод не найден для типа", + "타입에서 메서드를 찾을 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "You're calling a method that doesn't exist on this type. Check trait imports.", + "Вы вызываете метод, который не существует для этого типа. Проверьте импорт трейтов.", + "이 타입에 존재하지 않는 메서드를 호출하고 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Import the trait", + "Импортировать трейт", + "트레이트 import" + ), + code: "use std::io::Read;" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0599.html" + }] +}; diff --git a/masterror-knowledge/src/errors/types/e0600.rs b/masterror-knowledge/src/errors/types/e0600.rs new file mode 100644 index 0000000..11fb156 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0600.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0600: cannot apply unary operator to type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0600", + title: LocalizedText::new( + "Cannot apply unary operator to type", + "Нельзя применить унарный оператор к типу", + "타입에 단항 연산자를 적용할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An unary operator was used on a type which doesn't implement it. Unary +operators like `!`, `-`, `*`, `&` require the type to implement the +corresponding trait from `std::ops`. + +Different unary operators require different trait implementations: +- `!` requires `std::ops::Not` +- `-` requires `std::ops::Neg` +- `*` requires `std::ops::Deref`", + "\ +Унарный оператор был использован для типа, который его не реализует. +Унарные операторы вроде `!`, `-`, `*`, `&` требуют, чтобы тип реализовывал +соответствующий трейт из `std::ops`.", + "\ +타입이 구현하지 않은 단항 연산자가 사용되었습니다. `!`, `-`, `*`, `&`와 같은 +단항 연산자는 해당 타입이 `std::ops`의 해당 트레이트를 구현해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Implement the appropriate operator trait", + "Реализовать соответствующий трейт оператора", + "적절한 연산자 트레이트 구현" + ), + code: "use std::ops::Not;\n\nimpl Not for Question {\n type Output = bool;\n fn not(self) -> bool { matches!(self, Question::No) }\n}" + }], + links: &[ + DocLink { + title: "std::ops module", + url: "https://doc.rust-lang.org/std/ops/index.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0600.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0604.rs b/masterror-knowledge/src/errors/types/e0604.rs new file mode 100644 index 0000000..630fd3f --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0604.rs @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0604: only `u8` can be cast as `char` + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0604", + title: LocalizedText::new( + "Only u8 can be cast as char", + "Только u8 можно привести к char", + "u8만 char로 캐스팅 가능" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type other than `u8` was cast to `char`. Only `u8` can be directly cast +to `char` in Rust. + +`char` represents a Unicode Scalar Value, which is an integer value in +ranges 0 to 0xD7FF and 0xE000 to 0x10FFFF. Since only `u8` (0-255) always +fits within valid Unicode ranges, it's the only integer type that can be +directly cast to `char`.", + "\ +Тип, отличный от `u8`, был приведён к `char`. Только `u8` может быть +напрямую приведён к `char` в Rust. + +`char` представляет скалярное значение Unicode. Поскольку только `u8` (0-255) +всегда попадает в допустимые диапазоны Unicode, это единственный целочисленный +тип, который можно напрямую привести к `char`.", + "\ +`u8`가 아닌 타입이 `char`로 캐스팅되었습니다. Rust에서는 `u8`만 +직접 `char`로 캐스팅할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use char::from_u32() for safe conversion", + "Использовать char::from_u32() для безопасного преобразования", + "안전한 변환을 위해 char::from_u32() 사용" + ), + code: "let c = char::from_u32(0x3B1); // Some('α')" + }, + FixSuggestion { + description: LocalizedText::new( + "Cast u8 directly", + "Привести u8 напрямую", + "u8 직접 캐스팅" + ), + code: "let c = 86u8 as char; // 'V'" + } + ], + links: &[ + DocLink { + title: "Type Cast Expressions", + url: "https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0604.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0605.rs b/masterror-knowledge/src/errors/types/e0605.rs new file mode 100644 index 0000000..e3d3bf5 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0605.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0605: non-primitive cast + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0605", + title: LocalizedText::new( + "Non-primitive cast attempted", + "Попытка непримитивного приведения типа", + "비원시 타입 캐스팅 시도" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An invalid cast was attempted. Only primitive types can be directly cast +into each other using the `as` operator. + +For complex type conversions, use the `Into`/`From` traits, constructor +methods, or type-specific conversion functions.", + "\ +Была предпринята попытка недопустимого приведения типа. Только примитивные +типы могут быть напрямую приведены друг к другу с помощью оператора `as`. + +Для сложных преобразований типов используйте трейты `Into`/`From`, +методы-конструкторы или функции преобразования типов.", + "\ +잘못된 캐스팅이 시도되었습니다. `as` 연산자를 사용하여 직접 캐스팅할 수 +있는 것은 원시 타입뿐입니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use From/Into traits for complex conversions", + "Использовать трейты From/Into для сложных преобразований", + "복잡한 변환에는 From/Into 트레이트 사용" + ), + code: "let v: Vec = x.into();" + }, + FixSuggestion { + description: LocalizedText::new( + "Cast only between primitive types", + "Приводить только между примитивными типами", + "원시 타입 간에만 캐스팅" + ), + code: "let x = 0u8 as u32; // ok" + } + ], + links: &[ + DocLink { + title: "Type Cast Expressions", + url: "https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0605.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0606.rs b/masterror-knowledge/src/errors/types/e0606.rs new file mode 100644 index 0000000..217e052 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0606.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0606: incompatible cast + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0606", + title: LocalizedText::new( + "Incompatible cast attempted", + "Попытка несовместимого приведения типа", + "호환되지 않는 캐스팅 시도" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +An incompatible cast was attempted. Only primitive types can be cast into +each other. Attempting to cast non-primitive types (like references) +directly will result in this error. + +For example, casting `&u8` directly to `u32` is invalid. You must +dereference first.", + "\ +Была предпринята попытка несовместимого приведения типа. Только примитивные +типы могут быть приведены друг к другу. Попытка привести непримитивные типы +(например, ссылки) напрямую приведёт к этой ошибке. + +Например, приведение `&u8` напрямую к `u32` недопустимо. Сначала нужно +разыменовать.", + "\ +호환되지 않는 캐스팅이 시도되었습니다. 원시 타입만 서로 캐스팅할 수 있습니다. +참조와 같은 비원시 타입을 직접 캐스팅하면 이 오류가 발생합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Dereference before casting", + "Разыменовать перед приведением", + "캐스팅 전에 역참조" + ), + code: "let x = &0u8;\nlet y: u32 = *x as u32; // dereference first" + }], + links: &[ + DocLink { + title: "Type Cast Expressions", + url: "https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0606.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0607.rs b/masterror-knowledge/src/errors/types/e0607.rs new file mode 100644 index 0000000..a7edd73 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0607.rs @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0607: cast between thin and wide pointer + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0607", + title: LocalizedText::new( + "Cannot cast between thin and wide pointer", + "Невозможно привести между тонким и широким указателем", + "얇은 포인터와 넓은 포인터 간 캐스팅 불가" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A cast between a thin and a wide pointer was attempted. + +Thin pointers contain only a memory address. Wide pointers reference +Dynamically Sized Types (DSTs) and carry additional metadata: +- Slices: address + length +- Trait objects: address + vtable pointer + +You cannot directly cast between these pointer types.", + "\ +Была предпринята попытка приведения между тонким и широким указателем. + +Тонкие указатели содержат только адрес памяти. Широкие указатели ссылаются +на типы с динамическим размером (DST) и несут дополнительные метаданные: +- Срезы: адрес + длина +- Трейт-объекты: адрес + указатель на vtable + +Вы не можете напрямую приводить между этими типами указателей.", + "\ +얇은 포인터와 넓은 포인터 간 캐스팅이 시도되었습니다. + +얇은 포인터는 메모리 주소만 포함합니다. 넓은 포인터는 동적 크기 타입(DST)을 +참조하며 추가 메타데이터를 포함합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use proper Rust constructs instead of casting", + "Использовать правильные конструкции Rust вместо приведения", + "캐스팅 대신 적절한 Rust 구조 사용" + ), + code: "// Create slice from array properly\nlet arr = [1, 2, 3];\nlet slice: &[i32] = &arr;" + }], + links: &[ + DocLink { + title: "Type Cast Expressions", + url: "https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0607.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0608.rs b/masterror-knowledge/src/errors/types/e0608.rs new file mode 100644 index 0000000..28f682e --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0608.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0608: cannot index into a value + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0608", + title: LocalizedText::new( + "Cannot index into a value of this type", + "Невозможно индексировать значение этого типа", + "이 타입의 값을 인덱싱할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to index a value whose type doesn't implement the `std::ops::Index` +trait. + +Only types that implement `Index` can be indexed with square brackets. +Common indexable types include `Vec`, arrays, and slices. + +Note: Tuples and structs use dot notation (`.0`, `.field`), not brackets.", + "\ +Попытка индексировать значение, тип которого не реализует трейт +`std::ops::Index`. + +Только типы, реализующие `Index`, могут индексироваться квадратными скобками. +Общие индексируемые типы включают `Vec`, массивы и срезы. + +Примечание: Кортежи и структуры используют точечную нотацию (`.0`, `.field`).", + "\ +`std::ops::Index` 트레이트를 구현하지 않는 타입의 값을 인덱싱하려고 시도했습니다. + +`Index`를 구현하는 타입만 대괄호로 인덱싱할 수 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use indexable types like Vec or arrays", + "Использовать индексируемые типы, такие как Vec или массивы", + "Vec나 배열 같은 인덱싱 가능한 타입 사용" + ), + code: "let v: Vec = vec![0, 1, 2];\nprintln!(\"{}\", v[1]);" + }, + FixSuggestion { + description: LocalizedText::new( + "Use dot notation for tuples", + "Использовать точечную нотацию для кортежей", + "튜플에는 점 표기법 사용" + ), + code: "let tuple = (1, 2, 3);\nprintln!(\"{}\", tuple.0);" + } + ], + links: &[ + DocLink { + title: "std::ops::Index", + url: "https://doc.rust-lang.org/std/ops/trait.Index.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0608.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0609.rs b/masterror-knowledge/src/errors/types/e0609.rs new file mode 100644 index 0000000..5e2a787 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0609.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0609: no field on type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0609", + title: LocalizedText::new("No field on type", "Нет поля у типа", "타입에 필드가 없음"), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to access a nonexistent field in a struct. This is typically +caused by: +- Misspelling the field name +- Referencing a field that was never defined in the struct", + "\ +Попытка доступа к несуществующему полю структуры. Обычно это вызвано: +- Опечаткой в имени поля +- Обращением к полю, которое никогда не было определено в структуре", + "\ +구조체에 존재하지 않는 필드에 접근하려고 시도했습니다. 일반적으로: +- 필드 이름 오타 +- 구조체에 정의되지 않은 필드 참조" + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Check the field name spelling", + "Проверить правописание имени поля", + "필드 이름 철자 확인" + ), + code: "struct Foo { x: u32 }\nlet f = Foo { x: 0 };\nprintln!(\"{}\", f.x); // correct field name" + }], + links: &[ + DocLink { + title: "Structs", + url: "https://doc.rust-lang.org/book/ch05-01-defining-structs.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0609.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0610.rs b/masterror-knowledge/src/errors/types/e0610.rs new file mode 100644 index 0000000..b7b064a --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0610.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0610: primitive type has no fields + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0610", + title: LocalizedText::new( + "Primitive type has no fields", + "Примитивный тип не имеет полей", + "원시 타입에는 필드가 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to access a field on a primitive type. Primitive types in Rust +(like `u32`, `i32`, `bool`, etc.) do not have fields and cannot be accessed +using dot notation for fields. + +Only struct types support named field access.", + "\ +Попытка доступа к полю примитивного типа. Примитивные типы в Rust +(такие как `u32`, `i32`, `bool` и т.д.) не имеют полей и не могут быть +доступны с помощью точечной нотации для полей. + +Только структуры поддерживают доступ к именованным полям.", + "\ +원시 타입에서 필드에 접근하려고 시도했습니다. Rust의 원시 타입에는 +필드가 없으며 점 표기법으로 접근할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use struct types for named data", + "Использовать структуры для именованных данных", + "명명된 데이터에는 구조체 타입 사용" + ), + code: "struct Point { x: u32, y: i64 }\nlet p = Point { x: 0, y: -12 };\nprintln!(\"{}\", p.x);" + }], + links: &[ + DocLink { + title: "Primitive Types", + url: "https://doc.rust-lang.org/book/ch03-02-data-types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0610.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0614.rs b/masterror-knowledge/src/errors/types/e0614.rs new file mode 100644 index 0000000..e8f70e9 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0614.rs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0614: type cannot be dereferenced + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0614", + title: LocalizedText::new( + "Type cannot be dereferenced", + "Тип не может быть разыменован", + "타입을 역참조할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to dereference a variable which cannot be dereferenced. + +Only types that implement `std::ops::Deref` can be dereferenced. +Common dereferenceable types include: +- References (`&T`) +- Smart pointers (`Box`, `Rc`) +- Custom types implementing `Deref`", + "\ +Попытка разыменовать переменную, которую нельзя разыменовать. + +Только типы, реализующие `std::ops::Deref`, могут быть разыменованы. +Общие разыменовываемые типы включают: +- Ссылки (`&T`) +- Умные указатели (`Box`, `Rc`) +- Пользовательские типы, реализующие `Deref`", + "\ +역참조할 수 없는 변수를 역참조하려고 시도했습니다. + +`std::ops::Deref`를 구현하는 타입만 역참조할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Dereference a reference instead", + "Разыменовать ссылку вместо этого", + "대신 참조를 역참조" + ), + code: "let y = 0u32;\nlet x = &y;\n*x; // ok - x is &u32" + }], + links: &[ + DocLink { + title: "std::ops::Deref", + url: "https://doc.rust-lang.org/std/ops/trait.Deref.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0614.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0617.rs b/masterror-knowledge/src/errors/types/e0617.rs new file mode 100644 index 0000000..7ffd448 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0617.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0617: invalid type for variadic function + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0617", + title: LocalizedText::new( + "Invalid type for variadic function", + "Недопустимый тип для функции с переменным числом аргументов", + "가변 인수 함수에 대한 잘못된 타입" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to pass an invalid type of variable into a variadic function. + +When calling C variadic functions (with `...` parameters), the C ABI has +specific rules about which types can be passed. Some Rust types (like `f32`) +must be cast to their corresponding C types (like `c_double`).", + "\ +Попытка передать недопустимый тип переменной в функцию с переменным +числом аргументов. + +При вызове C-функций с переменным числом аргументов (с `...` параметрами), +ABI C имеет особые правила о том, какие типы можно передавать. Некоторые +типы Rust (например, `f32`) должны быть приведены к соответствующим +типам C (например, `c_double`).", + "\ +가변 인수 함수에 잘못된 타입의 변수를 전달하려고 시도했습니다. + +C 가변 인수 함수를 호출할 때 C ABI에는 전달할 수 있는 타입에 대한 +특정 규칙이 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Cast to appropriate C type", + "Привести к соответствующему типу C", + "적절한 C 타입으로 캐스팅" + ), + code: "unsafe { printf(\"%f\\n\\0\".as_ptr() as _, 0f64); } // use f64 instead of f32" + }], + links: &[ + DocLink { + title: "std::os::raw", + url: "https://doc.rust-lang.org/std/os/raw/" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0617.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0618.rs b/masterror-knowledge/src/errors/types/e0618.rs new file mode 100644 index 0000000..d4c27c4 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0618.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0618: expected function, found non-callable + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0618", + title: LocalizedText::new( + "Expected function, found non-callable type", + "Ожидалась функция, найден невызываемый тип", + "함수가 예상되었으나 호출 불가능한 타입 발견" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to call something which isn't a function nor a method. +Only functions and methods can be invoked with parentheses. + +Common mistakes: +- Calling an enum variant as a function +- Using `()` on a non-callable value like an integer", + "\ +Попытка вызвать что-то, что не является функцией или методом. +Только функции и методы могут быть вызваны с помощью скобок. + +Распространённые ошибки: +- Вызов варианта enum как функции +- Использование `()` на невызываемом значении, например целом числе", + "\ +함수나 메서드가 아닌 것을 호출하려고 시도했습니다. +함수와 메서드만 괄호로 호출할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Only call actual functions or methods", + "Вызывать только реальные функции или методы", + "실제 함수나 메서드만 호출" + ), + code: "fn my_function() {}\nmy_function(); // ok" + }], + links: &[ + DocLink { + title: "Functions", + url: "https://doc.rust-lang.org/book/ch03-03-how-functions-work.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0618.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0620.rs b/masterror-knowledge/src/errors/types/e0620.rs new file mode 100644 index 0000000..3f86643 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0620.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0620: cast to unsized type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0620", + title: LocalizedText::new( + "Cast to unsized type not allowed", + "Приведение к нетипизированному размеру не допускается", + "크기가 정해지지 않은 타입으로 캐스팅 불가" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to cast a value directly to an unsized type. Unsized types are +types whose size cannot be determined at compile-time. + +Since the size cannot be computed, unsized types cannot exist as standalone +values - they can only be accessed through pointers or references.", + "\ +Попытка привести значение напрямую к типу с неизвестным размером. +Типы с неизвестным размером - это типы, размер которых не может быть +определён во время компиляции. + +Поскольку размер не может быть вычислен, такие типы не могут существовать +как самостоятельные значения - к ним можно обращаться только через +указатели или ссылки.", + "\ +크기가 정해지지 않은 타입으로 직접 캐스팅하려고 시도했습니다. +이러한 타입은 포인터나 참조를 통해서만 접근할 수 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Cast to a reference of the unsized type", + "Привести к ссылке на тип с неизвестным размером", + "크기가 정해지지 않은 타입의 참조로 캐스팅" + ), + code: "let x = &[1_usize, 2] as &[usize]; // cast to reference" + }], + links: &[ + DocLink { + title: "Dynamically Sized Types", + url: "https://doc.rust-lang.org/reference/dynamically-sized-types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0620.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0631.rs b/masterror-knowledge/src/errors/types/e0631.rs new file mode 100644 index 0000000..88dab12 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0631.rs @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0631: type mismatch in closure arguments + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0631", + title: LocalizedText::new( + "Type mismatch in closure arguments", + "Несоответствие типов в аргументах замыкания", + "클로저 인수의 타입 불일치" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A closure was passed to a function but the closure's argument types don't +match the expected types defined by the function's trait bounds. + +The function expects a closure with specific argument types via a trait +like `Fn(T)`, but you passed a closure with different argument types.", + "\ +Замыкание было передано в функцию, но типы аргументов замыкания не +соответствуют ожидаемым типам, определённым ограничениями трейтов функции. + +Функция ожидает замыкание с определёнными типами аргументов через трейт +типа `Fn(T)`, но вы передали замыкание с другими типами аргументов.", + "\ +클로저가 함수에 전달되었지만 클로저의 인수 타입이 함수의 트레이트 바운드에서 +정의한 예상 타입과 일치하지 않습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Correct the closure's argument type", + "Исправить тип аргумента замыкания", + "클로저의 인수 타입 수정" + ), + code: "fn foo(f: F) {}\nfoo(|x: i32| {}); // correct type" + }, + FixSuggestion { + description: LocalizedText::new( + "Let the type be inferred", + "Позволить типу быть выведенным", + "타입이 추론되도록 함" + ), + code: "fn foo(f: F) {}\nfoo(|x| {}); // type inferred as i32" + } + ], + links: &[ + DocLink { + title: "Closures", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0631.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0641.rs b/masterror-knowledge/src/errors/types/e0641.rs new file mode 100644 index 0000000..028aa45 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0641.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0641: pointer with unknown kind + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0641", + title: LocalizedText::new( + "Cannot cast to/from pointer with unknown kind", + "Невозможно привести к/от указателя с неизвестным типом", + "알 수 없는 종류의 포인터로/부터 캐스팅 불가" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Attempted to cast to or from a pointer type, but the compiler cannot infer +the complete type information needed for the pointer. + +The error is triggered when casting to a pointer type using the wildcard `_` +without providing enough context for the compiler to determine what the +pointed-to type should be.", + "\ +Попытка привести к или от типа указателя, но компилятор не может вывести +полную информацию о типе, необходимую для указателя. + +Ошибка возникает при приведении к типу указателя с использованием `_` +без предоставления достаточного контекста для определения целевого типа.", + "\ +포인터 타입으로/부터 캐스팅하려고 시도했지만 컴파일러가 포인터에 필요한 +완전한 타입 정보를 추론할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Explicitly specify the pointed-to type", + "Явно указать тип, на который указывает указатель", + "가리키는 타입을 명시적으로 지정" + ), + code: "let b = 0 as *const i32; // explicit type" + }, + FixSuggestion { + description: LocalizedText::new( + "Use type annotation on the variable", + "Использовать аннотацию типа для переменной", + "변수에 타입 주석 사용" + ), + code: "let c: *const i32 = 0 as *const _; // type from annotation" + } + ], + links: &[ + DocLink { + title: "Raw Pointers", + url: "https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0641.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0643.rs b/masterror-knowledge/src/errors/types/e0643.rs new file mode 100644 index 0000000..1ad5989 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0643.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0643: impl Trait mismatch in trait implementation + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0643", + title: LocalizedText::new( + "Mismatch between impl Trait and generic parameters", + "Несоответствие между impl Trait и обобщёнными параметрами", + "impl Trait와 제네릭 매개변수 간 불일치" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +There is a mismatch between how generic parameters are declared in a trait +method versus how they are implemented. + +You cannot substitute explicit generic parameters for `impl Trait` parameters +when implementing a trait. The implementation must match the trait signature +exactly.", + "\ +Существует несоответствие между объявлением обобщённых параметров в методе +трейта и их реализацией. + +Вы не можете заменить явные обобщённые параметры на параметры `impl Trait` +при реализации трейта. Реализация должна точно соответствовать сигнатуре +трейта.", + "\ +트레이트 메서드에서 제네릭 매개변수가 선언되는 방식과 구현되는 방식 간에 +불일치가 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Match the trait signature exactly", + "Точно соответствовать сигнатуре трейта", + "트레이트 시그니처와 정확히 일치시킴" + ), + code: "trait Foo {\n fn foo(&self, _: &impl Iterator);\n}\n\nimpl Foo for () {\n fn foo(&self, _: &impl Iterator) {} // match exactly\n}" + }], + links: &[ + DocLink { + title: "impl Trait", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0643.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0644.rs b/masterror-knowledge/src/errors/types/e0644.rs new file mode 100644 index 0000000..9fc769a --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0644.rs @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0644: closure references its own type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0644", + title: LocalizedText::new( + "Closure cannot reference its own type", + "Замыкание не может ссылаться на свой собственный тип", + "클로저는 자신의 타입을 참조할 수 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A closure or generator was constructed that references its own type. +This typically happens when a closure accepts a parameter of its own +closure type. + +Rust prohibits closures from directly referencing their own type to keep +closure type inference tractable and prevent circular type dependencies.", + "\ +Было создано замыкание или генератор, который ссылается на свой +собственный тип. Это обычно происходит, когда замыкание принимает +параметр своего собственного типа замыкания. + +Rust запрещает замыканиям напрямую ссылаться на свой собственный тип, +чтобы упростить вывод типов замыканий и предотвратить циклические +зависимости типов.", + "\ +자신의 타입을 참조하는 클로저나 제너레이터가 생성되었습니다. +Rust는 클로저 타입 추론을 가능하게 하고 순환 타입 종속성을 방지하기 위해 +클로저가 자신의 타입을 직접 참조하는 것을 금지합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use a top-level function instead", + "Использовать функцию верхнего уровня вместо этого", + "대신 최상위 함수 사용" + ), + code: "fn my_fn() { /* ... */ }" + }, + FixSuggestion { + description: LocalizedText::new( + "Use indirect recursion via function pointers", + "Использовать косвенную рекурсию через указатели на функции", + "함수 포인터를 통한 간접 재귀 사용" + ), + code: "fn foo(f: &dyn Fn()) { f(); }" + } + ], + links: &[ + DocLink { + title: "Closures", + url: "https://doc.rust-lang.org/book/ch13-01-closures.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0644.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0666.rs b/masterror-knowledge/src/errors/types/e0666.rs new file mode 100644 index 0000000..a731d19 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0666.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0666: nested impl Trait not allowed + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0666", + title: LocalizedText::new( + "Nested impl Trait not allowed", + "Вложенный impl Trait не допускается", + "중첩 impl Trait 허용되지 않음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +`impl Trait` types cannot appear nested in the generic arguments of other +`impl Trait` types. + +You cannot use an `impl Trait` type as a generic argument inside another +`impl Trait` syntax.", + "\ +Типы `impl Trait` не могут появляться вложенными в обобщённые аргументы +других типов `impl Trait`. + +Вы не можете использовать тип `impl Trait` как обобщённый аргумент внутри +другого синтаксиса `impl Trait`.", + "\ +`impl Trait` 타입은 다른 `impl Trait` 타입의 제네릭 인수에 중첩되어 +나타날 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use named generic type parameters", + "Использовать именованные обобщённые параметры типа", + "명명된 제네릭 타입 매개변수 사용" + ), + code: "fn foo(\n bar: impl MyGenericTrait,\n) {}" + }], + links: &[ + DocLink { + title: "impl Trait", + url: "https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0666.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0689.rs b/masterror-knowledge/src/errors/types/e0689.rs new file mode 100644 index 0000000..43dc38e --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0689.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0689: method called on ambiguous numeric type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0689", + title: LocalizedText::new( + "Method called on ambiguous numeric type", + "Метод вызван на неоднозначном числовом типе", + "모호한 숫자 타입에서 메서드 호출" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A method was called on an ambiguous numeric type. The Rust compiler cannot +determine the concrete type of the numeric value, creating ambiguity that +prevents resolving which implementation of the method to use. + +This happens with numeric literals or bindings without an identified +concrete type.", + "\ +Метод был вызван на неоднозначном числовом типе. Компилятор Rust не может +определить конкретный тип числового значения, что создаёт неоднозначность +и не позволяет определить, какую реализацию метода использовать. + +Это происходит с числовыми литералами или привязками без определённого +конкретного типа.", + "\ +모호한 숫자 타입에서 메서드가 호출되었습니다. Rust 컴파일러가 숫자 값의 +구체적인 타입을 결정할 수 없어 어떤 메서드 구현을 사용할지 해결할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Use type suffix on literal", + "Использовать суффикс типа для литерала", + "리터럴에 타입 접미사 사용" + ), + code: "let _ = 2.0_f32.neg(); // type suffix" + }, + FixSuggestion { + description: LocalizedText::new( + "Use type annotation on binding", + "Использовать аннотацию типа для привязки", + "바인딩에 타입 주석 사용" + ), + code: "let x: f32 = 2.0;\nlet _ = x.neg();" + } + ], + links: &[ + DocLink { + title: "Numeric Types", + url: "https://doc.rust-lang.org/book/ch03-02-data-types.html#numeric-types" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0689.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0690.rs b/masterror-knowledge/src/errors/types/e0690.rs new file mode 100644 index 0000000..b13022b --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0690.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0690: transparent struct with multiple non-zero-sized fields + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0690", + title: LocalizedText::new( + "Transparent struct with multiple non-zero-sized fields", + "Прозрачная структура с несколькими ненулевыми полями", + "여러 개의 비영 크기 필드가 있는 투명 구조체" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A struct with `repr(transparent)` had two or more fields that were not +guaranteed to be zero-sized. + +The `repr(transparent)` attribute requires that the struct be represented +exactly like one of its fields at runtime, so there can only be one +non-zero-sized field.", + "\ +Структура с `repr(transparent)` имела два или более полей, которые +не гарантированно имеют нулевой размер. + +Атрибут `repr(transparent)` требует, чтобы структура была представлена +точно так же, как одно из её полей во время выполнения, поэтому может +быть только одно поле с ненулевым размером.", + "\ +`repr(transparent)` 구조체에 크기가 0이 아닌 것으로 보장되지 않는 +필드가 두 개 이상 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use PhantomData for type parameters", + "Использовать PhantomData для параметров типа", + "타입 매개변수에 PhantomData 사용" + ), + code: "use std::marker::PhantomData;\n\n#[repr(transparent)]\nstruct Wrapper {\n value: f32,\n unit: PhantomData, // zero-sized\n}" + }], + links: &[ + DocLink { + title: "repr(transparent)", + url: "https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0690.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0691.rs b/masterror-knowledge/src/errors/types/e0691.rs new file mode 100644 index 0000000..774353c --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0691.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0691: zero-sized field with non-trivial alignment in transparent struct + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0691", + title: LocalizedText::new( + "Zero-sized field in transparent struct has non-trivial alignment", + "Поле нулевого размера в прозрачной структуре имеет нетривиальное выравнивание", + "투명 구조체의 크기가 0인 필드가 비정상적인 정렬을 가짐" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A struct, enum, or union with `repr(transparent)` contains a zero-sized +field that requires non-trivial alignment (alignment greater than 1). + +The `repr(transparent)` representation guarantees that a type is represented +exactly like the single piece of data it wraps. Zero-sized fields with +larger alignment requirements would force the struct to have greater +alignment than its data field, violating the transparency guarantee.", + "\ +Структура, enum или union с `repr(transparent)` содержит поле нулевого +размера, которое требует нетривиального выравнивания (больше 1). + +Представление `repr(transparent)` гарантирует, что тип представлен +точно так же, как единственный элемент данных, который он оборачивает. +Поля нулевого размера с большими требованиями к выравниванию заставят +структуру иметь большее выравнивание, чем её поле данных.", + "\ +`repr(transparent)` 구조체, enum 또는 union에 크기가 0이지만 +정렬이 1보다 큰 필드가 포함되어 있습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use PhantomData instead of aligned zero-sized type", + "Использовать PhantomData вместо выровненного типа нулевого размера", + "정렬된 크기 0 타입 대신 PhantomData 사용" + ), + code: "use std::marker::PhantomData;\n\n#[repr(transparent)]\nstruct Wrapper(f32, PhantomData);" + }], + links: &[ + DocLink { + title: "repr(transparent)", + url: "https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0691.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0692.rs b/masterror-knowledge/src/errors/types/e0692.rs new file mode 100644 index 0000000..e1fbffe --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0692.rs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0692: incompatible representation hints + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0692", + title: LocalizedText::new( + "Incompatible representation hints", + "Несовместимые подсказки представления", + "호환되지 않는 표현 힌트" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type is annotated with `repr(transparent)` along with other conflicting +representation hints. + +This is contradictory because `repr(transparent)` delegates all representation +concerns to another type, so adding additional hints like `repr(C)` conflicts +with this purpose.", + "\ +Тип аннотирован `repr(transparent)` вместе с другими конфликтующими +подсказками представления. + +Это противоречиво, поскольку `repr(transparent)` делегирует все вопросы +представления другому типу, поэтому добавление дополнительных подсказок +вроде `repr(C)` конфликтует с этой целью.", + "\ +타입이 `repr(transparent)`와 함께 다른 충돌하는 표현 힌트로 +주석이 달려 있습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Remove conflicting hints", + "Удалить конфликтующие подсказки", + "충돌하는 힌트 제거" + ), + code: "#[repr(transparent)]\nstruct Grams(f32);" + }, + FixSuggestion { + description: LocalizedText::new( + "Move other attributes to contained type", + "Переместить другие атрибуты на содержащийся тип", + "다른 속성을 포함된 타입으로 이동" + ), + code: "#[repr(C)]\nstruct Foo { x: i32 }\n\n#[repr(transparent)]\nstruct FooWrapper(Foo);" + } + ], + links: &[ + DocLink { + title: "repr(transparent)", + url: "https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0692.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0693.rs b/masterror-knowledge/src/errors/types/e0693.rs new file mode 100644 index 0000000..088a8eb --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0693.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0693: incorrect repr(align) syntax + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0693", + title: LocalizedText::new( + "Incorrect repr(align) syntax", + "Неправильный синтаксис repr(align)", + "잘못된 repr(align) 구문" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `align` representation hint was declared using incorrect syntax. + +Common mistakes include: +- Using `=` instead of parentheses: `#[repr(align=8)]` +- Using string quotes: `#[repr(align=\"8\")]`", + "\ +Подсказка представления `align` была объявлена с использованием +неправильного синтаксиса. + +Распространённые ошибки: +- Использование `=` вместо скобок: `#[repr(align=8)]` +- Использование строковых кавычек: `#[repr(align=\"8\")]`", + "\ +`align` 표현 힌트가 잘못된 구문으로 선언되었습니다. + +일반적인 실수: +- 괄호 대신 `=` 사용 +- 문자열 따옴표 사용" + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use correct syntax with parentheses", + "Использовать правильный синтаксис со скобками", + "괄호가 있는 올바른 구문 사용" + ), + code: "#[repr(align(8))]\nstruct Align8(i8);" + }], + links: &[ + DocLink { + title: "Type Layout", + url: "https://doc.rust-lang.org/reference/type-layout.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0693.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0800.rs b/masterror-knowledge/src/errors/types/e0800.rs new file mode 100644 index 0000000..88bba51 --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0800.rs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0800: type or const parameter not in scope + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0800", + title: LocalizedText::new( + "Type or const parameter not in scope", + "Типовой или const параметр не в области видимости", + "타입 또는 const 매개변수가 스코프에 없음" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +A type or const parameter of the given name is not in scope. + +This error occurs when you reference a type or const parameter that hasn't +been declared or is not available in the current scope. + +Common causes: +- Misspelled type parameter name +- Missing generic declaration in function or type +- Using `use` clause without declaring T", + "\ +Типовой или const параметр с данным именем не находится в области видимости. + +Эта ошибка возникает, когда вы ссылаетесь на параметр типа или const, +который не был объявлен или недоступен в текущей области видимости. + +Частые причины: +- Опечатка в имени параметра типа +- Отсутствует объявление дженерика в функции или типе +- Использование `use` без объявления T", + "\ +주어진 이름의 타입 또는 const 매개변수가 스코프에 없습니다. +선언되지 않았거나 현재 스코프에서 사용할 수 없는 매개변수를 참조할 때 발생합니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Declare the type parameter", + "Объявить параметр типа", + "타입 매개변수 선언" + ), + code: "fn missing() -> impl Sized + use {}" + }, + FixSuggestion { + description: LocalizedText::new( + "Check spelling of parameter name", + "Проверить написание имени параметра", + "매개변수 이름 철자 확인" + ), + code: "fn example(x: Item) -> Item { x }" + } + ], + links: &[ + DocLink { + title: "Rust Book: Generic Types", + url: "https://doc.rust-lang.org/book/ch10-01-syntax.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0800.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/types/e0801.rs b/masterror-knowledge/src/errors/types/e0801.rs new file mode 100644 index 0000000..c1374ef --- /dev/null +++ b/masterror-knowledge/src/errors/types/e0801.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0801: invalid generic receiver type + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0801", + title: LocalizedText::new( + "Invalid generic receiver type", + "Недопустимый обобщённый тип получателя", + "잘못된 제네릭 수신자 타입" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +The `self` parameter in a method has an invalid generic receiver type. + +Methods take a special first parameter called `self`. With arbitrary self types, +you can use types that implement `Deref` like `Rc` or `Box`. + +However, the `self` type must be CONCRETE. Generic `self` types are not permitted. +A `self` type will be rejected if it is a type parameter defined on the method. + +Invalid: `fn foo>(self: R)` +Invalid: `fn foo(self: impl Deref)` +Valid: `fn foo(self: Rc)`", + "\ +Параметр `self` в методе имеет недопустимый обобщённый тип получателя. + +Методы принимают специальный первый параметр `self`. С произвольными типами self +можно использовать типы, реализующие `Deref`, такие как `Rc`. + +Однако тип `self` должен быть КОНКРЕТНЫМ. Обобщённые типы `self` не разрешены. +Тип `self` будет отклонён, если он является параметром типа, определённым в методе. + +Неверно: `fn foo>(self: R)` +Верно: `fn foo(self: Rc)`", + "\ +메서드의 `self` 매개변수가 잘못된 제네릭 수신자 타입을 가지고 있습니다. +`self` 타입은 반드시 구체적이어야 합니다. 제네릭 `self` 타입은 허용되지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Use concrete self type", + "Использовать конкретный тип self", + "구체적인 self 타입 사용" + ), + code: "\ +use std::rc::Rc; + +impl Foo { + fn foo(self: Rc) {} +}" + }], + links: &[ + DocLink { + title: "Arbitrary Self Types", + url: "https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0801.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/unsafe_code.rs b/masterror-knowledge/src/errors/unsafe_code.rs new file mode 100644 index 0000000..6d1f158 --- /dev/null +++ b/masterror-knowledge/src/errors/unsafe_code.rs @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Unsafe code related errors. + +mod e0133; +mod e0197; +mod e0198; +mod e0199; +mod e0200; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0133::ENTRY, + &e0197::ENTRY, + &e0198::ENTRY, + &e0199::ENTRY, + &e0200::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/unsafe_code/e0133.rs b/masterror-knowledge/src/errors/unsafe_code/e0133.rs new file mode 100644 index 0000000..a394e78 --- /dev/null +++ b/masterror-knowledge/src/errors/unsafe_code/e0133.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0133: call to unsafe function requires unsafe function or block + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0133", + title: LocalizedText::new( + "Call to unsafe function requires unsafe function or block", + "Вызов unsafe функции требует unsafe функции или блока", + "unsafe 함수 호출에는 unsafe 함수 또는 블록이 필요" + ), + category: Category::Types, + explanation: LocalizedText::new( + "\ +Unsafe code was used outside of an unsafe block. Unsafe operations in Rust +are potentially dangerous and require explicit safe boundaries. + +Examples of unsafe code that require unsafe blocks: +- Dereferencing raw pointers +- Calling functions via FFI +- Calling functions marked unsafe", + "\ +Небезопасный код использован вне блока unsafe. Небезопасные операции в Rust +потенциально опасны и требуют явных границ безопасности. + +Примеры небезопасного кода, требующего блока unsafe: +- Разыменование сырых указателей +- Вызов функций через FFI +- Вызов функций, помеченных как unsafe", + "\ +unsafe 블록 외부에서 unsafe 코드가 사용되었습니다. Rust에서 unsafe 작업은 +잠재적으로 위험하며 명시적인 안전 경계가 필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Wrap unsafe code in an unsafe block", + "Обернуть небезопасный код в блок unsafe", + "unsafe 코드를 unsafe 블록으로 감싸기" + ), + code: "unsafe fn f() { }\n\nfn main() {\n unsafe { f(); } // ok!\n}" + }], + links: &[ + DocLink { + title: "Rust Book: Unsafe Rust", + url: "https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0133.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/unsafe_code/e0197.rs b/masterror-knowledge/src/errors/unsafe_code/e0197.rs new file mode 100644 index 0000000..735550c --- /dev/null +++ b/masterror-knowledge/src/errors/unsafe_code/e0197.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0197: inherent implementation was marked unsafe + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0197", + title: LocalizedText::new( + "Inherent implementation was marked unsafe", + "Собственная реализация помечена как unsafe", + "고유 구현이 unsafe로 표시됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An inherent implementation was marked unsafe. Inherent implementations +(implementations that do not implement a trait but provide methods +associated with a type) are always safe because they are not implementing +an unsafe trait. + +Remove the unsafe keyword from the inherent implementation.", + "\ +Собственная реализация помечена как unsafe. Собственные реализации +(реализации, которые не реализуют трейт, но предоставляют методы, +связанные с типом) всегда безопасны, потому что они не реализуют +небезопасный трейт. + +Удалите ключевое слово unsafe из собственной реализации.", + "\ +고유 구현이 unsafe로 표시되었습니다. 고유 구현(트레이트를 구현하지 +않지만 타입과 연관된 메서드를 제공하는 구현)은 unsafe 트레이트를 +구현하지 않기 때문에 항상 안전합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove the unsafe keyword", + "Удалить ключевое слово unsafe", + "unsafe 키워드 제거" + ), + code: "struct Foo;\n\nimpl Foo { } // ok! no unsafe" + }], + links: &[ + DocLink { + title: "Rust Reference: Implementations", + url: "https://doc.rust-lang.org/reference/items/implementations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0197.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/unsafe_code/e0198.rs b/masterror-knowledge/src/errors/unsafe_code/e0198.rs new file mode 100644 index 0000000..f5da627 --- /dev/null +++ b/masterror-knowledge/src/errors/unsafe_code/e0198.rs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0198: negative implementation was marked as unsafe + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0198", + title: LocalizedText::new( + "Negative implementation was marked as unsafe", + "Негативная реализация помечена как unsafe", + "부정 구현이 unsafe로 표시됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A negative trait implementation is incorrectly marked as unsafe. Negative +implementations exclude a type from implementing a particular trait. Since +not being able to use a trait is always a safe operation, negative +implementations are inherently safe and should never be marked as unsafe. + +Negative implementations are only allowed for auto traits.", + "\ +Негативная реализация трейта неправильно помечена как unsafe. Негативные +реализации исключают тип из реализации конкретного трейта. Поскольку +невозможность использовать трейт - это всегда безопасная операция, +негативные реализации по своей сути безопасны и не должны быть помечены как unsafe. + +Негативные реализации разрешены только для auto трейтов.", + "\ +부정 트레이트 구현이 잘못 unsafe로 표시되었습니다. 부정 구현은 특정 +트레이트를 구현하지 못하도록 타입을 제외합니다. 트레이트를 사용할 수 +없다는 것은 항상 안전한 작업이므로 부정 구현은 본질적으로 안전하며 +unsafe로 표시하면 안 됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove the unsafe keyword from negative impl", + "Удалить unsafe из негативной реализации", + "부정 impl에서 unsafe 키워드 제거" + ), + code: "#![feature(auto_traits)]\n\nstruct Foo;\n\nauto trait Enterprise {}\n\nimpl !Enterprise for Foo { } // ok! no unsafe" + }], + links: &[ + DocLink { + title: "Rust Reference: Auto Traits", + url: "https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0198.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/unsafe_code/e0199.rs b/masterror-knowledge/src/errors/unsafe_code/e0199.rs new file mode 100644 index 0000000..14527d8 --- /dev/null +++ b/masterror-knowledge/src/errors/unsafe_code/e0199.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0199: implementing trait was marked as unsafe while the trait is safe + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0199", + title: LocalizedText::new( + "Implementing trait was marked as unsafe while the trait is safe", + "Реализация трейта помечена как unsafe, хотя трейт безопасен", + "트레이트가 안전한데 구현이 unsafe로 표시됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +A trait implementation was marked as unsafe while the trait is safe. +Safe traits should not have unsafe implementations. The unsafe keyword +should only be used when implementing unsafe traits. + +Only unsafe traits can have unsafe implementations.", + "\ +Реализация трейта помечена как unsafe, хотя трейт безопасен. +Безопасные трейты не должны иметь unsafe реализации. Ключевое слово +unsafe должно использоваться только при реализации unsafe трейтов. + +Только unsafe трейты могут иметь unsafe реализации.", + "\ +트레이트가 안전한데 트레이트 구현이 unsafe로 표시되었습니다. +안전한 트레이트는 unsafe 구현을 가지면 안 됩니다. unsafe 키워드는 +unsafe 트레이트를 구현할 때만 사용해야 합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove the unsafe keyword from trait impl", + "Удалить unsafe из реализации трейта", + "트레이트 impl에서 unsafe 키워드 제거" + ), + code: "struct Foo;\n\ntrait Bar { }\n\nimpl Bar for Foo { } // ok! no unsafe" + }], + links: &[ + DocLink { + title: "Rust Book: Unsafe Traits", + url: "https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#implementing-an-unsafe-trait" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0199.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/unsafe_code/e0200.rs b/masterror-knowledge/src/errors/unsafe_code/e0200.rs new file mode 100644 index 0000000..bd76f7f --- /dev/null +++ b/masterror-knowledge/src/errors/unsafe_code/e0200.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0200: unsafe trait was implemented without an unsafe impl + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0200", + title: LocalizedText::new( + "Unsafe trait was implemented without an unsafe impl", + "Unsafe трейт реализован без unsafe impl", + "unsafe 트레이트가 unsafe impl 없이 구현됨" + ), + category: Category::Traits, + explanation: LocalizedText::new( + "\ +An unsafe trait was implemented without an unsafe implementation. Unsafe +traits must have unsafe implementations. The unsafe keyword is required +to indicate that the implementation upholds the safety contract of the +unsafe trait.", + "\ +Unsafe трейт реализован без unsafe реализации. Unsafe трейты должны +иметь unsafe реализации. Ключевое слово unsafe требуется, чтобы +указать, что реализация соблюдает контракт безопасности unsafe трейта.", + "\ +unsafe 트레이트가 unsafe 구현 없이 구현되었습니다. unsafe 트레이트는 +unsafe 구현을 가져야 합니다. unsafe 키워드는 구현이 unsafe 트레이트의 +안전성 계약을 준수함을 나타내기 위해 필요합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Add unsafe keyword to trait impl", + "Добавить unsafe к реализации трейта", + "트레이트 impl에 unsafe 키워드 추가" + ), + code: "struct Foo;\n\nunsafe trait Bar { }\n\nunsafe impl Bar for Foo { } // ok! unsafe impl" + }], + links: &[ + DocLink { + title: "Rust Book: Unsafe Traits", + url: "https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#implementing-an-unsafe-trait" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0200.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/visibility.rs b/masterror-knowledge/src/errors/visibility.rs new file mode 100644 index 0000000..ff7b96a --- /dev/null +++ b/masterror-knowledge/src/errors/visibility.rs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Visibility related errors. + +mod e0364; +mod e0365; +mod e0445; +mod e0446; +mod e0447; +mod e0448; +mod e0449; +mod e0451; + +use super::ErrorEntry; + +static ENTRIES: &[&ErrorEntry] = &[ + &e0364::ENTRY, + &e0365::ENTRY, + &e0445::ENTRY, + &e0446::ENTRY, + &e0447::ENTRY, + &e0448::ENTRY, + &e0449::ENTRY, + &e0451::ENTRY +]; + +pub fn entries() -> &'static [&'static ErrorEntry] { + ENTRIES +} diff --git a/masterror-knowledge/src/errors/visibility/e0364.rs b/masterror-knowledge/src/errors/visibility/e0364.rs new file mode 100644 index 0000000..61a8940 --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0364.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0364: private items cannot be publicly re-exported + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0364", + title: LocalizedText::new( + "Private items cannot be publicly re-exported", + "Приватные элементы нельзя публично реэкспортировать", + "비공개 항목은 공개적으로 재내보내기할 수 없음" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +You attempted to use `pub use` to re-export an item that is not itself marked +as `pub`. You cannot publicly expose private items through re-exports. + +Re-exports cannot elevate the visibility of private items to public scope.", + "\ +Вы попытались использовать `pub use` для реэкспорта элемента, который сам +не помечен как `pub`. Нельзя публично раскрывать приватные элементы через +реэкспорт. + +Реэкспорт не может повысить видимость приватных элементов до публичной области.", + "\ +`pub use`를 사용하여 `pub`로 표시되지 않은 항목을 재내보내기하려고 했습니다. +재내보내기를 통해 비공개 항목을 공개적으로 노출할 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Mark the item as pub before re-exporting", + "Пометить элемент как pub перед реэкспортом", + "재내보내기 전에 항목을 pub로 표시" + ), + code: "mod a {\n pub fn foo() {} // now public\n \n mod a {\n pub use super::foo; // ok!\n }\n}" + }], + links: &[ + DocLink { + title: "Rust Reference: Use Declarations", + url: "https://doc.rust-lang.org/reference/items/use-declarations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0364.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/visibility/e0365.rs b/masterror-knowledge/src/errors/visibility/e0365.rs new file mode 100644 index 0000000..bf63b1f --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0365.rs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0365: private modules cannot be publicly re-exported + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0365", + title: LocalizedText::new( + "Private modules cannot be publicly re-exported", + "Приватные модули нельзя публично реэкспортировать", + "비공개 모듈은 공개적으로 재내보내기할 수 없음" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +You attempted to use `pub use` to re-export a module that is not itself marked +as `pub`. In Rust, you cannot make a private module publicly accessible through +re-exporting. + +When using `pub use` to re-export a module, the module being re-exported must +first be declared with the `pub` visibility modifier.", + "\ +Вы попытались использовать `pub use` для реэкспорта модуля, который сам +не помечен как `pub`. В Rust нельзя сделать приватный модуль публично +доступным через реэкспорт. + +При использовании `pub use` для реэкспорта модуля, реэкспортируемый модуль +должен быть объявлен с модификатором видимости `pub`.", + "\ +`pub use`를 사용하여 `pub`로 표시되지 않은 모듈을 재내보내기하려고 했습니다. +Rust에서는 재내보내기를 통해 비공개 모듈을 공개적으로 접근 가능하게 만들 수 없습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Mark the module as pub before re-exporting", + "Пометить модуль как pub перед реэкспортом", + "재내보내기 전에 모듈을 pub로 표시" + ), + code: "pub mod foo {\n pub const X: u32 = 1;\n}\n\npub use foo as foo2; // ok!" + }], + links: &[ + DocLink { + title: "Rust Reference: Use Declarations", + url: "https://doc.rust-lang.org/reference/items/use-declarations.html" + }, + DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0365.html" + } + ] +}; diff --git a/masterror-knowledge/src/errors/visibility/e0445.rs b/masterror-knowledge/src/errors/visibility/e0445.rs new file mode 100644 index 0000000..cf64531 --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0445.rs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0445: private trait in public interface + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0445", + title: LocalizedText::new( + "Private trait in public interface", + "Приватный трейт в публичном интерфейсе", + "공개 인터페이스의 비공개 트레이트" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +A private trait was used as a constraint on a public type parameter in a +public interface. This violates visibility rules because public APIs should +not expose private types. + +Note: This error is no longer emitted by modern compiler versions.", + "\ +Приватный трейт использован как ограничение публичного параметра типа +в публичном интерфейсе. Это нарушает правила видимости, так как +публичные API не должны раскрывать приватные типы. + +Примечание: эта ошибка больше не выдаётся современными версиями компилятора.", + "\ +비공개 트레이트가 공개 인터페이스에서 공개 타입 매개변수의 제약으로 +사용되었습니다. 이는 공개 API가 비공개 타입을 노출해서는 안 되기 +때문에 가시성 규칙을 위반합니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Make the trait public", + "Сделать трейт публичным", + "트레이트를 공개로 만들기" + ), + code: "pub trait Foo { }\npub fn foo(t: T) {} // ok!" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0445.html" + }] +}; diff --git a/masterror-knowledge/src/errors/visibility/e0446.rs b/masterror-knowledge/src/errors/visibility/e0446.rs new file mode 100644 index 0000000..ec134e7 --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0446.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0446: private type in public interface + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0446", + title: LocalizedText::new( + "Private type in public interface", + "Приватный тип в публичном интерфейсе", + "공개 인터페이스의 비공개 타입" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +A private type or trait was exposed through a public associated type in a +trait implementation. Since the trait or associated type is public, external +code can see and access it, but the underlying type is private.", + "\ +Приватный тип или трейт раскрыт через публичный ассоциированный тип в +реализации трейта. Поскольку трейт или ассоциированный тип публичен, +внешний код может его видеть, но базовый тип приватен.", + "\ +비공개 타입 또는 트레이트가 트레이트 구현의 공개 연관 타입을 통해 +노출되었습니다. 트레이트 또는 연관 타입이 공개이므로 외부 코드가 +볼 수 있지만 기본 타입은 비공개입니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Restrict the trait's visibility", + "Ограничить видимость трейта", + "트레이트의 가시성 제한" + ), + code: "struct Bar;\n\npub(crate) trait PubTr {\n type Alias;\n}\n\nimpl PubTr for u8 {\n type Alias = Bar;\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Make the private type public", + "Сделать приватный тип публичным", + "비공개 타입을 공개로 만들기" + ), + code: "pub struct Bar;\n\npub trait PubTr {\n type Alias;\n}\n\nimpl PubTr for u8 {\n type Alias = Bar;\n}" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0446.html" + }] +}; diff --git a/masterror-knowledge/src/errors/visibility/e0447.rs b/masterror-knowledge/src/errors/visibility/e0447.rs new file mode 100644 index 0000000..4fa5f80 --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0447.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0447: pub used inside a function + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0447", + title: LocalizedText::new( + "pub keyword used inside a function", + "Ключевое слово pub использовано внутри функции", + "함수 내에서 pub 키워드 사용됨" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +The pub (public) keyword was used to mark an item as public inside a +function body. This is invalid because visibility modifiers have no +effect for items defined inside functions. + +Items defined inside a function are not accessible from outside that +function's scope regardless of visibility modifiers. + +Note: This error is no longer emitted by modern compiler versions.", + "\ +Ключевое слово pub использовано для пометки элемента как публичного +внутри тела функции. Это недопустимо, так как модификаторы видимости +не имеют эффекта для элементов внутри функций. + +Примечание: эта ошибка больше не выдаётся современными версиями компилятора.", + "\ +pub(공개) 키워드가 함수 본문 내에서 항목을 공개로 표시하는 데 +사용되었습니다. 함수 내에서 정의된 항목에는 가시성 수정자가 +효과가 없으므로 유효하지 않습니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove the pub keyword", + "Удалить ключевое слово pub", + "pub 키워드 제거" + ), + code: "fn foo() {\n struct Bar; // Remove pub\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0447.html" + }] +}; diff --git a/masterror-knowledge/src/errors/visibility/e0448.rs b/masterror-knowledge/src/errors/visibility/e0448.rs new file mode 100644 index 0000000..8314d15 --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0448.rs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0448: unnecessary pub on enum variant + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0448", + title: LocalizedText::new( + "Unnecessary pub visibility on enum variant", + "Лишняя публичная видимость варианта перечисления", + "열거형 변형에 불필요한 pub 가시성" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +The pub keyword was used on enum variants inside a public enum, which is +redundant. Since the enum is already public, all of its variants are +automatically public. + +Note: This error is no longer emitted by modern compiler versions.", + "\ +Ключевое слово pub использовано для вариантов перечисления внутри +публичного перечисления, что избыточно. Поскольку перечисление уже +публично, все его варианты автоматически публичны. + +Примечание: эта ошибка больше не выдаётся современными версиями компилятора.", + "\ +공개 열거형 내의 열거형 변형에 pub 키워드가 사용되었으며, 이는 +중복입니다. 열거형이 이미 공개이므로 모든 변형은 자동으로 공개됩니다." + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove pub from enum variants", + "Удалить pub из вариантов перечисления", + "열거형 변형에서 pub 제거" + ), + code: "pub enum Foo {\n Bar, // Variants inherit enum's visibility\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0448.html" + }] +}; diff --git a/masterror-knowledge/src/errors/visibility/e0449.rs b/masterror-knowledge/src/errors/visibility/e0449.rs new file mode 100644 index 0000000..4bcc2b4 --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0449.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0449: visibility qualifiers not permitted + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0449", + title: LocalizedText::new( + "Visibility qualifiers not permitted here", + "Модификаторы видимости здесь не разрешены", + "여기서 가시성 수식어가 허용되지 않음" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +Visibility qualifiers (like pub) were used in a context where they are +not allowed. Visibility qualifiers cannot be applied to: +- Enum variants (they inherit the enum's visibility) +- Trait items (they inherit the trait's visibility) +- Impl blocks (they inherit the type's visibility) +- Extern blocks", + "\ +Модификаторы видимости (например, pub) использованы там, где они +не разрешены. Модификаторы видимости нельзя применять к: +- Вариантам перечислений (они наследуют видимость перечисления) +- Элементам трейтов (они наследуют видимость трейта) +- Блокам impl (они наследуют видимость типа) +- Блокам extern", + "\ +가시성 수식어(pub 등)가 허용되지 않는 컨텍스트에서 사용되었습니다. +가시성 수식어는 다음에 적용할 수 없습니다: +- 열거형 변형 (열거형의 가시성 상속) +- 트레이트 항목 (트레이트의 가시성 상속) +- impl 블록 (타입의 가시성 상속) +- extern 블록" + ), + fixes: &[FixSuggestion { + description: LocalizedText::new( + "Remove visibility qualifiers", + "Удалить модификаторы видимости", + "가시성 수식어 제거" + ), + code: "impl Foo for Bar {\n fn foo() {} // Remove pub\n}" + }], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0449.html" + }] +}; diff --git a/masterror-knowledge/src/errors/visibility/e0451.rs b/masterror-knowledge/src/errors/visibility/e0451.rs new file mode 100644 index 0000000..36726b9 --- /dev/null +++ b/masterror-knowledge/src/errors/visibility/e0451.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! E0451: private field in struct constructor + +use crate::errors::{Category, DocLink, ErrorEntry, FixSuggestion, LocalizedText}; + +pub static ENTRY: ErrorEntry = ErrorEntry { + code: "E0451", + title: LocalizedText::new( + "Struct constructor with private fields invoked", + "Вызов конструктора структуры с приватными полями", + "비공개 필드가 있는 구조체 생성자 호출됨" + ), + category: Category::Visibility, + explanation: LocalizedText::new( + "\ +An attempt was made to directly instantiate a struct that has private fields +using struct literal syntax. Since the fields are not publicly accessible, +you cannot initialize them directly from outside the module.", + "\ +Попытка напрямую создать экземпляр структуры с приватными полями +с использованием синтаксиса литерала структуры. Поскольку поля +недоступны публично, их нельзя инициализировать извне модуля.", + "\ +구조체 리터럴 구문을 사용하여 비공개 필드가 있는 구조체를 직접 +인스턴스화하려고 시도했습니다. 필드가 공개적으로 접근할 수 없으므로 +모듈 외부에서 직접 초기화할 수 없습니다." + ), + fixes: &[ + FixSuggestion { + description: LocalizedText::new( + "Make all fields public", + "Сделать все поля публичными", + "모든 필드를 공개로 만들기" + ), + code: "pub struct Foo {\n pub a: isize,\n pub b: isize,\n}" + }, + FixSuggestion { + description: LocalizedText::new( + "Implement a constructor method", + "Реализовать метод-конструктор", + "생성자 메서드 구현" + ), + code: "impl Foo {\n pub fn new() -> Foo {\n Foo { a: 0, b: 0 }\n }\n}\n\nlet f = Foo::new();" + } + ], + links: &[DocLink { + title: "Error Code Reference", + url: "https://doc.rust-lang.org/error_codes/E0451.html" + }] +}; diff --git a/masterror-knowledge/src/i18n.rs b/masterror-knowledge/src/i18n.rs new file mode 100644 index 0000000..a7c6afc --- /dev/null +++ b/masterror-knowledge/src/i18n.rs @@ -0,0 +1,152 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Internationalization system for masterror-cli. +//! +//! Provides compile-time localization with zero runtime allocation. + +pub mod messages; +pub mod phrases; + +/// Supported languages. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +#[repr(u8)] +pub enum Lang { + /// English (default). + #[default] + En = 0, + /// Russian. + #[cfg(feature = "lang-ru")] + Ru = 1, + /// Korean. + #[cfg(feature = "lang-ko")] + Ko = 2 +} + +impl Lang { + /// Parse language from string, fallback to English. + /// + /// # Examples + /// + /// ``` + /// use masterror_knowledge::Lang; + /// + /// assert_eq!(Lang::from_code("ru"), Lang::Ru); + /// assert_eq!(Lang::from_code("unknown"), Lang::En); + /// ``` + pub fn from_code(s: &str) -> Self { + match s { + #[cfg(feature = "lang-ru")] + "ru" | "RU" | "Ru" => Self::Ru, + #[cfg(feature = "lang-ko")] + "ko" | "KO" | "Ko" => Self::Ko, + _ => Self::En + } + } + + /// Get language code as string. + pub const fn code(self) -> &'static str { + match self { + Self::En => "en", + #[cfg(feature = "lang-ru")] + Self::Ru => "ru", + #[cfg(feature = "lang-ko")] + Self::Ko => "ko" + } + } + + /// Get language display name. + pub const fn name(self) -> &'static str { + match self { + Self::En => "English", + #[cfg(feature = "lang-ru")] + Self::Ru => "Русский", + #[cfg(feature = "lang-ko")] + Self::Ko => "한국어" + } + } +} + +/// Define localized messages with compile-time validation. +/// +/// Creates an enum with localized strings accessible via `.get(lang)` method. +/// All strings are `&'static str` with zero runtime allocation. +/// +/// # Example +/// +/// ```ignore +/// define_messages! { +/// pub enum UiMsg { +/// LabelWhy { +/// en: "Why:", +/// ru: "Почему:", +/// ko: "왜:", +/// } +/// } +/// } +/// +/// let msg = UiMsg::LabelWhy.get(Lang::Ru); +/// assert_eq!(msg, "Почему:"); +/// ``` +#[macro_export] +macro_rules! define_messages { + ( + $vis:vis enum $name:ident { + $( + $key:ident { + en: $en:literal + $(, ru: $ru:literal)? + $(, ko: $ko:literal)? + $(,)? + } + )* + } + ) => { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[repr(u16)] + $vis enum $name { + $($key,)* + } + + impl $name { + /// Total number of messages. + pub const COUNT: usize = { + let mut count = 0usize; + $(let _ = stringify!($key); count += 1;)* + count + }; + + /// Get localized string for this message key. + #[inline] + pub const fn get(self, lang: $crate::i18n::Lang) -> &'static str { + match self { + $( + Self::$key => { + match lang { + $crate::i18n::Lang::En => $en, + $( + #[cfg(feature = "lang-ru")] + $crate::i18n::Lang::Ru => $ru, + )? + $( + #[cfg(feature = "lang-ko")] + $crate::i18n::Lang::Ko => $ko, + )? + #[allow(unreachable_patterns)] + _ => $en, + } + } + )* + } + } + + /// Get all message keys as static slice. + pub const fn all() -> &'static [Self] { + &[$(Self::$key,)*] + } + } + }; +} + +pub use define_messages; diff --git a/masterror-knowledge/src/i18n/messages.rs b/masterror-knowledge/src/i18n/messages.rs new file mode 100644 index 0000000..99ebba6 --- /dev/null +++ b/masterror-knowledge/src/i18n/messages.rs @@ -0,0 +1,206 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! UI messages for masterror-cli. + +use crate::define_messages; + +define_messages! { + pub enum UiMsg { + LabelTranslation { + en: "Translation:", + ru: "Перевод:", + ko: "번역:", + } + LabelWhy { + en: "Why this happens:", + ru: "Почему это происходит:", + ko: "왜 이런 일이 발생하나요:", + } + LabelFix { + en: "How to fix:", + ru: "Как исправить:", + ko: "해결 방법:", + } + LabelLink { + en: "Learn more:", + ru: "Подробнее:", + ko: "더 알아보기:", + } + LabelWhyMatters { + en: "Why this matters:", + ru: "Почему это важно:", + ko: "왜 중요한가:", + } + LabelHowToApply { + en: "How to apply:", + ru: "Как применять:", + ko: "적용 방법:", + } + LabelAvoid { + en: "Avoid", + ru: "Избегайте", + ko: "피하세요", + } + LabelPrefer { + en: "Prefer", + ru: "Предпочитайте", + ko: "선호하세요", + } + + CategoryOwnership { + en: "Ownership", + ru: "Владение", + ko: "소유권", + } + CategoryBorrowing { + en: "Borrowing", + ru: "Заимствование", + ko: "빌림", + } + CategoryLifetimes { + en: "Lifetimes", + ru: "Времена жизни", + ko: "라이프타임", + } + CategoryTypes { + en: "Types", + ru: "Типы", + ko: "타입", + } + CategoryTraits { + en: "Traits", + ru: "Трейты", + ko: "트레이트", + } + CategoryResolution { + en: "Name Resolution", + ru: "Разрешение имён", + ko: "이름 확인", + } + + CategoryErrorHandling { + en: "Error Handling", + ru: "Обработка ошибок", + ko: "에러 처리", + } + CategoryPerformance { + en: "Performance", + ru: "Производительность", + ko: "성능", + } + CategoryNaming { + en: "Naming", + ru: "Именование", + ko: "명명", + } + CategoryDocumentation { + en: "Documentation", + ru: "Документация", + ko: "문서화", + } + CategoryDesign { + en: "Design", + ru: "Дизайн", + ko: "설계", + } + CategoryTesting { + en: "Testing", + ru: "Тестирование", + ko: "테스트", + } + CategorySecurity { + en: "Security", + ru: "Безопасность", + ko: "보안", + } + + UnknownCode { + en: "Unknown code", + ru: "Неизвестный код", + ko: "알 수 없는 코드", + } + Category { + en: "Category", + ru: "Категория", + ko: "카테고리", + } + + InitTitle { + en: "masterror configuration", + ru: "Настройка masterror", + ko: "masterror 설정", + } + InitSuccess { + en: "Configuration saved to", + ru: "Конфигурация сохранена в", + ko: "설정이 저장됨:", + } + InitLangPrompt { + en: "Language", + ru: "Язык", + ko: "언어", + } + InitColorPrompt { + en: "Colored output", + ru: "Цветной вывод", + ko: "색상 출력", + } + InitDisplayPrompt { + en: "Display sections:", + ru: "Секции для отображения:", + ko: "표시 섹션:", + } + InitShowTranslation { + en: "Show translation", + ru: "Показывать перевод", + ko: "번역 표시", + } + InitShowWhy { + en: "Show explanation", + ru: "Показывать объяснение", + ko: "설명 표시", + } + InitShowFix { + en: "Show fix suggestions", + ru: "Показывать исправления", + ko: "수정 제안 표시", + } + InitShowLinks { + en: "Show documentation links", + ru: "Показывать ссылки", + ko: "문서 링크 표시", + } + InitShowOriginal { + en: "Show original compiler output", + ru: "Показывать оригинальный вывод", + ko: "원본 컴파일러 출력 표시", + } + InitSavePrompt { + en: "Where to save configuration?", + ru: "Где сохранить настройки?", + ko: "설정을 어디에 저장할까요?", + } + InitSaveGlobal { + en: "Global (~/.config/masterror/) - applies to all projects", + ru: "Глобально (~/.config/masterror/) - для всех проектов", + ko: "전역 (~/.config/masterror/) - 모든 프로젝트에 적용", + } + InitSaveLocal { + en: "Local (.masterror.toml) - only this project", + ru: "Локально (.masterror.toml) - только этот проект", + ko: "로컬 (.masterror.toml) - 이 프로젝트만", + } + InitTip { + en: "You can change settings anytime by editing:", + ru: "Вы можете изменить настройки в любой момент, отредактировав:", + ko: "언제든지 다음 파일을 편집하여 설정을 변경할 수 있습니다:", + } + InitUsage { + en: "Start using masterror:", + ru: "Начните использовать masterror:", + ko: "masterror 사용 시작:", + } + } +} diff --git a/masterror-knowledge/src/i18n/phrases.rs b/masterror-knowledge/src/i18n/phrases.rs new file mode 100644 index 0000000..f0db428 --- /dev/null +++ b/masterror-knowledge/src/i18n/phrases.rs @@ -0,0 +1,241 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Phrase translations for cargo compiler output. +//! +//! Uses Aho-Corasick algorithm for O(n+m) multi-pattern replacement. + +use std::sync::LazyLock; + +use aho_corasick::AhoCorasick; + +use super::Lang; + +/// Russian phrase translations (sorted alphabetically by English key). +#[cfg(feature = "lang-ru")] +static PHRASES_RU: &[(&str, &str)] = &[ + ("aborting due to", "прерывание из-за"), + ( + "as mutable because it is also borrowed as immutable", + "как изменяемое, т.к. уже заимствовано как неизменяемое" + ), + ( + "as mutable more than once at a time", + "как изменяемое больше одного раза одновременно" + ), + ( + "borrow of moved value", + "заимствование перемещённого значения" + ), + ( + "borrowed value does not live long enough", + "заимствованное значение живёт недостаточно долго" + ), + ("cannot borrow", "нельзя заимствовать"), + ("consider", "рассмотрите"), + ( + "consider cloning the value if the performance cost is acceptable", + "рассмотрите клонирование значения, если допустима потеря производительности" + ), + ("could not compile", "не удалось скомпилировать"), + ("does not live long enough", "живёт недостаточно долго"), + ( + "dropped here while still borrowed", + "удалено здесь, пока ещё заимствовано" + ), + ("due to", "из-за"), + ("error", "ошибка"), + ("expected", "ожидается"), + ( + "expected named lifetime parameter", + "ожидается именованный параметр времени жизни" + ), + ("expected type", "ожидаемый тип"), + ( + "first borrow later used here", + "первое заимствование используется здесь" + ), + ( + "first mutable borrow occurs here", + "первое изменяемое заимствование здесь" + ), + ( + "for more info about this issue", + "для информации об этой ошибке" + ), + ("found", "найдено"), + ("found type", "найденный тип"), + ("has type", "имеет тип"), + ("help", "подсказка"), + ( + "immutable borrow later used here", + "неизменяемое заимствование используется здесь" + ), + ( + "immutable borrow occurs here", + "неизменяемое заимствование здесь" + ), + ("mismatched types", "несовпадение типов"), + ( + "missing lifetime specifier", + "отсутствует спецификатор времени жизни" + ), + ("move occurs because", "перемещение происходит потому что"), + ( + "mutable borrow occurs here", + "изменяемое заимствование здесь" + ), + ("note", "примечание"), + ("previous error", "предыдущей ошибки"), + ("previous errors", "предыдущих ошибок"), + ("run with", "запустите с"), + ( + "second mutable borrow occurs here", + "второе изменяемое заимствование здесь" + ), + ( + "this error originates in the macro", + "эта ошибка возникла в макросе" + ), + ("this expression has type", "это выражение имеет тип"), + ( + "value borrowed here after move", + "значение заимствовано здесь после перемещения" + ), + ("value moved here", "значение перемещено здесь"), + ("warning", "предупреждение"), + ( + "which does not implement the `Copy` trait", + "который не реализует трейт `Copy`" + ) +]; + +/// Korean phrase translations (sorted alphabetically by English key). +#[cfg(feature = "lang-ko")] +static PHRASES_KO: &[(&str, &str)] = &[ + ("borrow of moved value", "이동된 값의 빌림"), + ("cannot borrow", "빌릴 수 없습니다"), + ("error", "에러"), + ("help", "도움말"), + ("mismatched types", "타입 불일치"), + ("note", "참고"), + ("warning", "경고") +]; + +/// Pre-built Aho-Corasick automaton for Russian translations. +/// +/// Patterns are sorted by length (longest first) to ensure correct replacement +/// when shorter patterns are substrings of longer ones. +#[cfg(feature = "lang-ru")] +static AC_RU: LazyLock<(AhoCorasick, Vec<&'static str>)> = LazyLock::new(|| { + let mut sorted: Vec<_> = PHRASES_RU.iter().collect(); + sorted.sort_by(|a, b| b.0.len().cmp(&a.0.len())); + + let patterns: Vec<_> = sorted.iter().map(|(k, _)| *k).collect(); + let replacements: Vec<_> = sorted.iter().map(|(_, v)| *v).collect(); + + let ac = AhoCorasick::new(&patterns).expect("valid patterns"); + (ac, replacements) +}); + +/// Pre-built Aho-Corasick automaton for Korean translations. +#[cfg(feature = "lang-ko")] +static AC_KO: LazyLock<(AhoCorasick, Vec<&'static str>)> = LazyLock::new(|| { + let mut sorted: Vec<_> = PHRASES_KO.iter().collect(); + sorted.sort_by(|a, b| b.0.len().cmp(&a.0.len())); + + let patterns: Vec<_> = sorted.iter().map(|(k, _)| *k).collect(); + let replacements: Vec<_> = sorted.iter().map(|(_, v)| *v).collect(); + + let ac = AhoCorasick::new(&patterns).expect("valid patterns"); + (ac, replacements) +}); + +/// Translate a phrase to the target language. +/// +/// Returns `None` if no translation exists or language is English. +pub fn translate_phrase(phrase: &str, lang: Lang) -> Option<&'static str> { + let phrases: &[(&str, &str)] = match lang { + Lang::En => return None, + #[cfg(feature = "lang-ru")] + Lang::Ru => PHRASES_RU, + #[cfg(feature = "lang-ko")] + Lang::Ko => PHRASES_KO, + #[allow(unreachable_patterns)] + _ => return None + }; + + phrases + .binary_search_by_key(&phrase, |(k, _)| *k) + .ok() + .map(|i| phrases[i].1) +} + +/// Translate full rendered compiler output. +/// +/// Uses pre-built Aho-Corasick automaton for O(n+m) replacement +/// instead of O(n*m) naive string replacement. +pub fn translate_rendered(rendered: &str, lang: Lang) -> String { + match lang { + Lang::En => rendered.to_string(), + #[cfg(feature = "lang-ru")] + Lang::Ru => { + let (ac, replacements) = &*AC_RU; + ac.replace_all(rendered, replacements) + } + #[cfg(feature = "lang-ko")] + Lang::Ko => { + let (ac, replacements) = &*AC_KO; + ac.replace_all(rendered, replacements) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(feature = "lang-ru")] + fn test_translate_phrase_ru() { + assert_eq!( + translate_phrase("borrow of moved value", Lang::Ru), + Some("заимствование перемещённого значения") + ); + assert_eq!(translate_phrase("unknown phrase", Lang::Ru), None); + } + + #[test] + fn test_translate_phrase_en() { + assert_eq!(translate_phrase("borrow of moved value", Lang::En), None); + } + + #[test] + #[cfg(feature = "lang-ru")] + fn test_phrases_sorted() { + for window in PHRASES_RU.windows(2) { + assert!( + window[0].0 < window[1].0, + "Phrases not sorted: {:?} should come before {:?}", + window[1].0, + window[0].0 + ); + } + } + + #[test] + #[cfg(feature = "lang-ru")] + fn test_translate_rendered_ru() { + let input = "error: borrow of moved value"; + let output = translate_rendered(input, Lang::Ru); + assert_eq!(output, "ошибка: заимствование перемещённого значения"); + } + + #[test] + fn test_translate_rendered_en_passthrough() { + let input = "error: borrow of moved value"; + let output = translate_rendered(input, Lang::En); + assert_eq!(output, input); + } +} diff --git a/masterror-knowledge/src/lib.rs b/masterror-knowledge/src/lib.rs new file mode 100644 index 0000000..3ac7174 --- /dev/null +++ b/masterror-knowledge/src/lib.rs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Knowledge base for Rust compiler errors and best practices. +//! +//! This crate provides structured explanations for Rust compiler errors +//! with translations (en/ru/ko) and actionable fix suggestions. +//! +//! # Example +//! +//! ```rust,ignore +//! use masterror_knowledge::{ErrorRegistry, PracticeRegistry}; +//! +//! let registry = ErrorRegistry::new(); +//! if let Some(entry) = registry.find("E0502") { +//! println!("Error: {}", entry.title.en); +//! println!("Explanation: {}", entry.explanation.en); +//! } +//! +//! let practices = PracticeRegistry::new(); +//! if let Some(practice) = practices.find("RA001") { +//! println!("Practice: {}", practice.title.en); +//! } +//! ``` + +pub mod errors; +pub mod i18n; + +pub use errors::{ + Category, DocLink, ErrorEntry, ErrorRegistry, FixSuggestion, LocalizedText, + raprogramm::{BestPractice, PracticeCategory, PracticeRegistry} +}; +pub use i18n::{Lang, messages::UiMsg, phrases}; diff --git a/masterror-rustc/Cargo.toml b/masterror-rustc/Cargo.toml new file mode 100644 index 0000000..2d2665f --- /dev/null +++ b/masterror-rustc/Cargo.toml @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2025-2026 RAprogramm +# +# SPDX-License-Identifier: MIT + +[package] +name = "masterror-rustc" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +description = "RUSTC_WRAPPER that adds translated explanations to Rust compiler errors" +keywords = ["rust", "compiler", "errors", "translation", "rustc"] +categories = ["command-line-utilities", "development-tools"] + +[[bin]] +name = "masterror-rustc" +path = "src/main.rs" + +[dependencies] +masterror-knowledge = { version = "0.1", path = "../masterror-knowledge", features = ["lang-ru", "lang-ko"] } +owo-colors = { version = "4", features = ["supports-colors"] } + +[target.'cfg(unix)'.dependencies] +libc = "0.2" + +[target.'cfg(windows)'.dependencies] +windows-sys = { version = "0.59", features = ["Win32_System_Console"] } diff --git a/masterror-rustc/src/main.rs b/masterror-rustc/src/main.rs new file mode 100644 index 0000000..ef033d2 --- /dev/null +++ b/masterror-rustc/src/main.rs @@ -0,0 +1,198 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! RUSTC_WRAPPER that adds translated explanations to Rust compiler errors. +//! +//! # Usage +//! +//! Add to `.cargo/config.toml`: +//! ```toml +//! [build] +//! rustc-wrapper = "masterror-rustc" +//! ``` +//! +//! Or set environment variable: +//! ```bash +//! export RUSTC_WRAPPER=masterror-rustc +//! ``` +//! +//! Then use cargo as usual: +//! ```bash +//! cargo build +//! cargo run +//! cargo test +//! ``` + +use std::{ + env, + io::{BufRead, BufReader, Write}, + process::{Command, Stdio, exit} +}; + +use masterror_knowledge::{ErrorRegistry, Lang}; +use owo_colors::OwoColorize; + +fn main() { + let args: Vec = env::args().skip(1).collect(); + + if args.is_empty() { + eprintln!("masterror-rustc: no arguments provided"); + eprintln!("This is a RUSTC_WRAPPER, not meant to be called directly."); + eprintln!(); + eprintln!("Usage: Add to .cargo/config.toml:"); + eprintln!(" [build]"); + eprintln!(" rustc-wrapper = \"masterror-rustc\""); + exit(1); + } + + // Cargo passes: $RUSTC_WRAPPER $RUSTC + // First argument is the path to rustc, rest are rustc arguments + let rustc = &args[0]; + let rustc_args = &args[1..]; + + let lang = detect_lang(); + let colored = supports_color(); + let registry = ErrorRegistry::new(); + + let mut child = Command::new(rustc) + .args(rustc_args) + .stdout(Stdio::inherit()) + .stderr(Stdio::piped()) + .spawn() + .unwrap_or_else(|e| { + eprintln!("masterror-rustc: failed to run rustc: {e}"); + exit(1); + }); + + let stderr = child.stderr.take().expect("failed to capture stderr"); + let reader = BufReader::new(stderr); + + let mut stderr_handle = std::io::stderr().lock(); + + for line in reader.lines() { + let line = match line { + Ok(l) => l, + Err(e) => { + eprintln!("masterror-rustc: read error: {e}"); + continue; + } + }; + + // Output original line + let _ = writeln!(stderr_handle, "{line}"); + + // Check for error code pattern: error[E0308] + if let Some(code) = extract_error_code(&line) + && let Some(explanation) = get_explanation(registry, &code, lang, colored) + { + let _ = writeln!(stderr_handle, "{explanation}"); + } + } + + drop(stderr_handle); + + let status = child.wait().unwrap_or_else(|e| { + eprintln!("masterror-rustc: failed to wait for rustc: {e}"); + exit(1); + }); + + exit(status.code().unwrap_or(1)); +} + +/// Extract error code from line like `error[E0308]: mismatched types` +fn extract_error_code(line: &str) -> Option { + let start = line.find("error[E")?; + let code_start = start + 6; // skip "error[" + let end = line[code_start..].find(']')?; + Some(line[code_start..code_start + end].to_string()) +} + +/// Get translated explanation for error code +fn get_explanation( + registry: &'static ErrorRegistry, + code: &str, + lang: Lang, + colored: bool +) -> Option { + let entry = registry.find(code)?; + let lang_code = lang.code(); + let mut output = String::new(); + + // Header + let title = entry.title.get(lang_code); + if colored { + output.push_str(&format!("\n {} {}\n", "💡".bold(), title.bold().cyan())); + } else { + output.push_str(&format!("\n 💡 {title}\n")); + } + + // Description + let desc = entry.explanation.get(lang_code); + if !desc.is_empty() { + for line in desc.lines() { + output.push_str(&format!(" {line}\n")); + } + } + + // Fix suggestions + if !entry.fixes.is_empty() { + output.push('\n'); + let fix_header = match lang.code() { + "ru" => "Как исправить:", + "ko" => "해결 방법:", + _ => "How to fix:" + }; + if colored { + output.push_str(&format!(" {}\n", fix_header.bold().green())); + } else { + output.push_str(&format!(" {fix_header}\n")); + } + for fix in entry.fixes { + let fix_desc = fix.description.get(lang_code); + output.push_str(&format!(" • {fix_desc}\n")); + } + } + + Some(output) +} + +/// Detect language from environment +fn detect_lang() -> Lang { + if let Ok(lang) = env::var("MASTERROR_LANG") { + return Lang::from_code(&lang); + } + + if let Ok(lang) = env::var("LANG") { + if lang.starts_with("ru") { + return Lang::from_code("ru"); + } + if lang.starts_with("ko") { + return Lang::from_code("ko"); + } + } + + Lang::En +} + +/// Check if terminal supports colors +fn supports_color() -> bool { + if env::var("NO_COLOR").is_ok() { + return false; + } + if env::var("CLICOLOR_FORCE").is_ok() { + return true; + } + is_stderr_tty() +} + +/// Check if stderr is a TTY +#[cfg(unix)] +fn is_stderr_tty() -> bool { + unsafe { libc::isatty(libc::STDERR_FILENO) != 0 } +} + +#[cfg(not(unix))] +fn is_stderr_tty() -> bool { + false +} diff --git a/masterror-template/src/template.rs b/masterror-template/src/template.rs index b37bb9f..8310ef2 100644 --- a/masterror-template/src/template.rs +++ b/masterror-template/src/template.rs @@ -455,78 +455,13 @@ impl TemplateFormatter { Self::Display { spec } => spec.as_deref().map(Cow::Borrowed), - Self::Debug { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#?")) - } else { - Some(Cow::Borrowed("?")) - } - } - Self::LowerHex { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#x")) - } else { - Some(Cow::Borrowed("x")) - } - } - Self::UpperHex { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#X")) - } else { - Some(Cow::Borrowed("X")) - } - } - Self::Pointer { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#p")) + _ => self.kind().specifier().map(|spec| { + if self.is_alternate() { + Cow::Owned(format!("#{}", spec)) } else { - Some(Cow::Borrowed("p")) + Cow::Owned(spec.to_string()) } - } - Self::Binary { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#b")) - } else { - Some(Cow::Borrowed("b")) - } - } - Self::Octal { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#o")) - } else { - Some(Cow::Borrowed("o")) - } - } - Self::LowerExp { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#e")) - } else { - Some(Cow::Borrowed("e")) - } - } - Self::UpperExp { - alternate - } => { - if *alternate { - Some(Cow::Borrowed("#E")) - } else { - Some(Cow::Borrowed("E")) - } - } + }) } } diff --git a/pkg/aur/.SRCINFO b/pkg/aur/.SRCINFO new file mode 100644 index 0000000..fe1f3cd --- /dev/null +++ b/pkg/aur/.SRCINFO @@ -0,0 +1,14 @@ +pkgbase = masterror + pkgdesc = CLI tool for explaining Rust compiler errors in human-friendly language + pkgver = 0.1.0 + pkgrel = 1 + url = https://github.com/RAprogramm/masterror + arch = x86_64 + arch = aarch64 + license = MIT + makedepends = cargo + depends = gcc-libs + source = masterror-0.1.0.tar.gz::https://github.com/RAprogramm/masterror/archive/v0.1.0.tar.gz + sha256sums = SKIP + +pkgname = masterror diff --git a/pkg/aur/PKGBUILD b/pkg/aur/PKGBUILD new file mode 100644 index 0000000..0fbc002 --- /dev/null +++ b/pkg/aur/PKGBUILD @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: 2025-2026 RAprogramm +# +# SPDX-License-Identifier: MIT + +# Maintainer: RAprogramm +pkgname=masterror +pkgver=0.1.0 +pkgrel=1 +pkgdesc="CLI tool for explaining Rust compiler errors in human-friendly language" +arch=('x86_64' 'aarch64') +url="https://github.com/RAprogramm/masterror" +license=('MIT') +depends=('gcc-libs') +makedepends=('cargo') +source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz") +sha256sums=('SKIP') + +prepare() { + cd "$pkgname-$pkgver" + export RUSTUP_TOOLCHAIN=stable + cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')" +} + +build() { + cd "$pkgname-$pkgver/masterror-cli" + export RUSTUP_TOOLCHAIN=stable + export CARGO_TARGET_DIR=target + cargo build --frozen --release --all-features +} + +check() { + cd "$pkgname-$pkgver/masterror-cli" + export RUSTUP_TOOLCHAIN=stable + export CARGO_TARGET_DIR=target + cargo test --frozen --release +} + +package() { + cd "$pkgname-$pkgver" + install -Dm755 "masterror-cli/target/release/masterror" "$pkgdir/usr/bin/masterror" + install -Dm755 "masterror-cli/target/release/cargo-masterror" "$pkgdir/usr/bin/cargo-masterror" + install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE" + install -Dm644 masterror-cli/README.md "$pkgdir/usr/share/doc/$pkgname/README.md" +} diff --git a/src/app_error.rs b/src/app_error.rs index fffd18a..87e20f6 100644 --- a/src/app_error.rs +++ b/src/app_error.rs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-FileCopyrightText: 2025-2026 RAprogramm // // SPDX-License-Identifier: MIT @@ -69,6 +69,7 @@ mod constructors; mod context; mod core; +pub mod diagnostics; mod inline_vec; mod metadata; @@ -77,6 +78,7 @@ pub use core::{AppError, AppResult, DisplayMode, Error, ErrorChain, MessageEditP pub(crate) use core::{reset_backtrace_preference, set_backtrace_preference_override}; pub use context::Context; +pub use diagnostics::{DiagnosticVisibility, Diagnostics, DocLink, Hint, Suggestion}; pub(crate) use metadata::duration_to_string; pub use metadata::{Field, FieldRedaction, FieldValue, Metadata, field}; diff --git a/src/app_error/core/backtrace.rs b/src/app_error/core/backtrace.rs index 10bc4bf..b97e1c4 100644 --- a/src/app_error/core/backtrace.rs +++ b/src/app_error/core/backtrace.rs @@ -21,16 +21,17 @@ const BACKTRACE_STATE_DISABLED: u8 = 2; #[cfg(feature = "backtrace")] static BACKTRACE_STATE: AtomicU8 = AtomicU8::new(BACKTRACE_STATE_UNSET); -/// Captures a backtrace snapshot if enabled by environment configuration. +/// Captures a backtrace snapshot when the feature is enabled. /// -/// Returns `Some(Arc)` if backtrace capture is enabled via -/// `RUST_BACKTRACE`, otherwise returns `None`. +/// Returns `Some(Arc)` if backtrace capture is enabled, +/// otherwise returns `None`. Uses `force_capture()` to always record +/// stack frames regardless of `RUST_BACKTRACE` environment variable. /// /// Internal function used for lazy backtrace capture in errors. #[cfg(feature = "backtrace")] pub(crate) fn capture_backtrace_snapshot() -> Option> { if should_capture_backtrace() { - Some(Arc::new(Backtrace::capture())) + Some(Arc::new(Backtrace::force_capture())) } else { None } @@ -42,6 +43,12 @@ pub(crate) fn capture_backtrace_snapshot() -> Option> { /// The first call reads `RUST_BACKTRACE` and caches the result. #[cfg(feature = "backtrace")] fn should_capture_backtrace() -> bool { + // In tests, always check override first (bypasses cache for test control) + #[cfg(test)] + if let Some(value) = test_backtrace_override::get() { + return value; + } + match BACKTRACE_STATE.load(AtomicOrdering::Acquire) { BACKTRACE_STATE_ENABLED => true, BACKTRACE_STATE_DISABLED => false, @@ -62,11 +69,10 @@ fn should_capture_backtrace() -> bool { /// Detects backtrace preference from environment or test override. /// -/// Checks test override first (in test builds), then reads `RUST_BACKTRACE`. -/// Returns `true` if backtrace capture is enabled. +/// When the `backtrace` feature is enabled, backtraces are captured by default. +/// Set `RUST_BACKTRACE=0` to disable capture. /// -/// Valid values for `RUST_BACKTRACE`: any non-empty value except `0`, `off`, -/// or `false`. +/// Checks test override first (in test builds), then reads `RUST_BACKTRACE`. #[cfg(feature = "backtrace")] fn detect_backtrace_preference() -> bool { #[cfg(all(test, feature = "backtrace"))] @@ -74,15 +80,16 @@ fn detect_backtrace_preference() -> bool { return value; } match env::var_os("RUST_BACKTRACE") { - None => false, + None => true, // Default: capture when feature enabled Some(value) => { let value = value.to_string_lossy(); let trimmed = value.trim(); if trimmed.is_empty() { - return false; + return true; } let lowered = trimmed.to_ascii_lowercase(); - !(matches!(lowered.as_str(), "0" | "off" | "false")) + // Only disable if explicitly set to 0/off/false + !matches!(lowered.as_str(), "0" | "off" | "false") } } } @@ -194,14 +201,15 @@ mod tests { } #[test] - fn should_capture_caches_enabled_state() { + fn override_bypasses_cache_in_tests() { reset_backtrace_preference(); set_backtrace_preference_override(Some(true)); - should_capture_backtrace(); + assert!(should_capture_backtrace()); + // Override should take priority over any cached state set_backtrace_preference_override(Some(false)); assert!( - should_capture_backtrace(), - "should use cached enabled state" + !should_capture_backtrace(), + "override should bypass cache in tests" ); reset_backtrace_preference(); } @@ -217,12 +225,15 @@ mod tests { } #[test] - fn detect_preference_returns_false_by_default() { + fn detect_preference_returns_true_by_default() { reset_backtrace_preference(); set_backtrace_preference_override(None); let result = detect_backtrace_preference(); reset_backtrace_preference(); - let _ = result; + assert!( + result, + "backtrace should be enabled by default when feature is on" + ); } #[test] diff --git a/src/app_error/core/builder.rs b/src/app_error/core/builder.rs index 2af4589..229ee97 100644 --- a/src/app_error/core/builder.rs +++ b/src/app_error/core/builder.rs @@ -1,420 +1,18 @@ -// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-FileCopyrightText: 2025-2026 RAprogramm // // SPDX-License-Identifier: MIT -use alloc::{borrow::Cow, string::String, sync::Arc}; -use core::error::Error as CoreError; -#[cfg(feature = "backtrace")] -use std::backtrace::Backtrace; +//! Builder pattern implementation for `AppError`. +//! +//! This module provides fluent builder methods for constructing errors with +//! various attributes like metadata, source chains, and diagnostics. -#[cfg(feature = "serde_json")] -use serde::Serialize; -#[cfg(feature = "serde_json")] -use serde_json::{Value as JsonValue, to_value}; +mod constructors; +mod context; +mod details; +mod diagnostics; +mod metadata; +mod modifiers; -use super::{ - error::Error, - types::{CapturedBacktrace, ContextAttachment, MessageEditPolicy} -}; -use crate::{ - AppCode, AppErrorKind, RetryAdvice, - app_error::metadata::{Field, FieldRedaction, Metadata} -}; - -impl Error { - /// Create a new [`Error`] with a kind and message. - /// - /// This is equivalent to [`Error::with`], provided for API symmetry and to - /// keep doctests readable. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind}; - /// let err = AppError::new(AppErrorKind::BadRequest, "invalid payload"); - /// assert!(err.message.is_some()); - /// ``` - #[must_use] - pub fn new(kind: AppErrorKind, msg: impl Into>) -> Self { - Self::with(kind, msg) - } - - /// Create an error with the given kind and message. - /// - /// Prefer named helpers (e.g. [`Error::not_found`]) where it clarifies - /// intent. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind}; - /// let err = AppError::with(AppErrorKind::Validation, "bad input"); - /// assert_eq!(err.kind, AppErrorKind::Validation); - /// ``` - #[must_use] - pub fn with(kind: AppErrorKind, msg: impl Into>) -> Self { - let err = Self::new_raw(kind, Some(msg.into())); - err.emit_telemetry(); - err - } - - /// Create a message-less error with the given kind. - /// - /// Useful when the kind alone conveys sufficient information to the client. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind}; - /// let err = AppError::bare(AppErrorKind::NotFound); - /// assert!(err.message.is_none()); - /// ``` - #[must_use] - pub fn bare(kind: AppErrorKind) -> Self { - let err = Self::new_raw(kind, None); - err.emit_telemetry(); - err - } - - /// Override the machine-readable [`AppCode`]. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppCode, AppError, AppErrorKind}; - /// let err = AppError::new(AppErrorKind::BadRequest, "test").with_code(AppCode::NotFound); - /// assert_eq!(err.code, AppCode::NotFound); - /// ``` - #[must_use] - pub fn with_code(mut self, code: AppCode) -> Self { - self.code = code; - self.mark_dirty(); - self - } - - /// Attach retry advice to the error. - /// - /// When mapped to HTTP, this becomes the `Retry-After` header. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind}; - /// let err = AppError::new(AppErrorKind::RateLimited, "slow down").with_retry_after_secs(60); - /// assert_eq!(err.retry.map(|r| r.after_seconds), Some(60)); - /// ``` - #[must_use] - pub fn with_retry_after_secs(mut self, secs: u64) -> Self { - self.retry = Some(RetryAdvice { - after_seconds: secs - }); - self.mark_dirty(); - self - } - - /// Attach a `WWW-Authenticate` challenge string. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind}; - /// let err = AppError::new(AppErrorKind::Unauthorized, "auth required") - /// .with_www_authenticate("Bearer realm=\"api\""); - /// assert!(err.www_authenticate.is_some()); - /// ``` - #[must_use] - pub fn with_www_authenticate(mut self, value: impl Into) -> Self { - self.www_authenticate = Some(value.into()); - self.mark_dirty(); - self - } - - /// Attach additional metadata to the error. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind, field}; - /// let err = AppError::new(AppErrorKind::Validation, "bad field") - /// .with_field(field::str("field_name", "email")); - /// assert!(err.metadata().get("field_name").is_some()); - /// ``` - #[must_use] - pub fn with_field(mut self, field: Field) -> Self { - self.metadata.insert(field); - self.mark_dirty(); - self - } - - /// Extend metadata from an iterator of fields. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind, field}; - /// let fields = vec![field::str("key1", "value1"), field::str("key2", "value2")]; - /// let err = AppError::new(AppErrorKind::BadRequest, "test").with_fields(fields); - /// assert!(err.metadata().get("key1").is_some()); - /// ``` - #[must_use] - pub fn with_fields(mut self, fields: impl IntoIterator) -> Self { - self.metadata.extend(fields); - self.mark_dirty(); - self - } - - /// Override the redaction policy for a stored metadata field. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind, FieldRedaction, field}; - /// - /// let err = AppError::new(AppErrorKind::Internal, "test") - /// .with_field(field::str("password", "secret")) - /// .redact_field("password", FieldRedaction::Redact); - /// ``` - #[must_use] - pub fn redact_field(mut self, name: &'static str, redaction: FieldRedaction) -> Self { - self.metadata.set_redaction(name, redaction); - self.mark_dirty(); - self - } - - /// Replace metadata entirely. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind, Metadata}; - /// - /// let metadata = Metadata::new(); - /// let err = AppError::new(AppErrorKind::Internal, "test").with_metadata(metadata); - /// ``` - #[must_use] - pub fn with_metadata(mut self, metadata: Metadata) -> Self { - self.metadata = metadata; - self.mark_dirty(); - self - } - - /// Mark the message as redactable. - /// - /// # Examples - /// - /// ```rust - /// use masterror::{AppError, AppErrorKind, MessageEditPolicy}; - /// - /// let err = AppError::new(AppErrorKind::Internal, "secret").redactable(); - /// assert_eq!(err.edit_policy, MessageEditPolicy::Redact); - /// ``` - #[must_use] - pub fn redactable(mut self) -> Self { - self.edit_policy = MessageEditPolicy::Redact; - self.mark_dirty(); - self - } - - /// Attach upstream diagnostics using [`with_source`](Self::with_source) or - /// an existing [`Arc`]. - /// - /// This is the preferred alias for capturing upstream errors. It accepts - /// either an owned error implementing [`core::error::Error`] or a - /// shared [`Arc`] produced by other APIs, reusing the allocation when - /// possible. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "std")] { - /// use masterror::AppError; - /// - /// let err = AppError::service("downstream degraded") - /// .with_context(std::io::Error::new(std::io::ErrorKind::Other, "boom")); - /// assert!(err.source_ref().is_some()); - /// # } - /// ``` - #[must_use] - pub fn with_context(self, context: impl Into) -> Self { - match context.into() { - ContextAttachment::Owned(source) => { - match source.downcast::>() { - Ok(shared) => self.with_source_arc(*shared), - Err(source) => self.with_source_arc(Arc::from(source)) - } - } - ContextAttachment::Shared(source) => self.with_source_arc(source) - } - } - - /// Attach a source error for diagnostics. - /// - /// Prefer [`with_context`](Self::with_context) when capturing upstream - /// diagnostics without additional `Arc` allocations. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "std")] { - /// use masterror::{AppError, AppErrorKind}; - /// - /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "boom"); - /// let err = AppError::internal("boom").with_source(io_err); - /// assert!(err.source_ref().is_some()); - /// # } - /// ``` - #[must_use] - pub fn with_source(mut self, source: impl CoreError + Send + Sync + 'static) -> Self { - self.source = Some(Arc::new(source)); - self.mark_dirty(); - self - } - - /// Attach a shared source error without cloning the underlying `Arc`. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "std")] { - /// use std::sync::Arc; - /// - /// use masterror::{AppError, AppErrorKind}; - /// - /// let source = Arc::new(std::io::Error::new(std::io::ErrorKind::Other, "boom")); - /// let err = AppError::internal("boom").with_source_arc(source.clone()); - /// assert!(err.source_ref().is_some()); - /// assert_eq!(Arc::strong_count(&source), 2); - /// # } - /// ``` - #[must_use] - pub fn with_source_arc(mut self, source: Arc) -> Self { - self.source = Some(source); - self.mark_dirty(); - self - } - - /// Attach a captured backtrace. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "backtrace")] - /// # { - /// use std::backtrace::Backtrace; - /// - /// use masterror::AppError; - /// - /// let bt = Backtrace::capture(); - /// let err = AppError::internal("test").with_backtrace(bt); - /// # } - /// ``` - #[must_use] - pub fn with_backtrace(mut self, backtrace: CapturedBacktrace) -> Self { - #[cfg(feature = "backtrace")] - { - self.set_backtrace_slot(Arc::new(backtrace)); - } - #[cfg(not(feature = "backtrace"))] - { - self.set_backtrace_slot(backtrace); - } - self.mark_dirty(); - self - } - - /// Attach a shared backtrace without cloning. - /// - /// Internal method for sharing backtraces between errors. - #[cfg(feature = "backtrace")] - pub(crate) fn with_shared_backtrace(mut self, backtrace: Arc) -> Self { - self.set_backtrace_slot(backtrace); - self.mark_dirty(); - self - } - - /// Attach structured JSON details for the client payload. - /// - /// The details are omitted from responses when the error has been marked as - /// [`redactable`](Self::redactable). - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "serde_json")] - /// # { - /// use masterror::{AppError, AppErrorKind}; - /// use serde_json::json; - /// - /// let err = AppError::new(AppErrorKind::Validation, "invalid input") - /// .with_details_json(json!({"field": "email"})); - /// assert!(err.details.is_some()); - /// # } - /// ``` - #[must_use] - #[cfg(feature = "serde_json")] - pub fn with_details_json(mut self, details: JsonValue) -> Self { - self.details = Some(details); - self.mark_dirty(); - self - } - - /// Serialize and attach structured details. - /// - /// Returns [`crate::AppError`] with [`crate::AppErrorKind::BadRequest`] if - /// serialization fails. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "serde_json")] - /// # { - /// use masterror::{AppError, AppErrorKind}; - /// use serde::Serialize; - /// - /// #[derive(Serialize)] - /// struct Extra { - /// reason: &'static str - /// } - /// - /// let err = AppError::new(AppErrorKind::BadRequest, "invalid") - /// .with_details(Extra { - /// reason: "missing" - /// }) - /// .expect("details should serialize"); - /// assert!(err.details.is_some()); - /// # } - /// ``` - #[cfg(feature = "serde_json")] - #[allow(clippy::result_large_err)] - pub fn with_details(self, payload: T) -> crate::AppResult - where - T: Serialize - { - let details = to_value(payload).map_err(|err| Self::bad_request(err.to_string()))?; - Ok(self.with_details_json(details)) - } - - /// Attach plain-text details for client payloads. - /// - /// The text is omitted from responses when the error is - /// [`redactable`](Self::redactable). - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(not(feature = "serde_json"))] - /// # { - /// use masterror::{AppError, AppErrorKind}; - /// - /// let err = AppError::new(AppErrorKind::Internal, "boom").with_details_text("retry later"); - /// assert!(err.details.is_some()); - /// # } - /// ``` - #[must_use] - #[cfg(not(feature = "serde_json"))] - pub fn with_details_text(mut self, details: impl Into) -> Self { - self.details = Some(details.into()); - self.mark_dirty(); - self - } -} +#[cfg(test)] +mod tests; diff --git a/src/app_error/core/builder/constructors.rs b/src/app_error/core/builder/constructors.rs new file mode 100644 index 0000000..93328bf --- /dev/null +++ b/src/app_error/core/builder/constructors.rs @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Core constructors for creating `AppError` instances. + +use alloc::borrow::Cow; + +use crate::{AppErrorKind, app_error::core::error::Error}; + +impl Error { + /// Create a new [`Error`] with a kind and message. + /// + /// This is equivalent to [`Error::with`], provided for API symmetry and to + /// keep doctests readable. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind}; + /// let err = AppError::new(AppErrorKind::BadRequest, "invalid payload"); + /// assert!(err.message.is_some()); + /// ``` + #[must_use] + pub fn new(kind: AppErrorKind, msg: impl Into>) -> Self { + Self::with(kind, msg) + } + + /// Create an error with the given kind and message. + /// + /// Prefer named helpers (e.g. [`Error::not_found`]) where it clarifies + /// intent. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind}; + /// let err = AppError::with(AppErrorKind::Validation, "bad input"); + /// assert_eq!(err.kind, AppErrorKind::Validation); + /// ``` + #[must_use] + pub fn with(kind: AppErrorKind, msg: impl Into>) -> Self { + let err = Self::new_raw(kind, Some(msg.into())); + err.emit_telemetry(); + err + } + + /// Create a message-less error with the given kind. + /// + /// Useful when the kind alone conveys sufficient information to the client. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind}; + /// let err = AppError::bare(AppErrorKind::NotFound); + /// assert!(err.message.is_none()); + /// ``` + #[must_use] + pub fn bare(kind: AppErrorKind) -> Self { + let err = Self::new_raw(kind, None); + err.emit_telemetry(); + err + } +} diff --git a/src/app_error/core/builder/context.rs b/src/app_error/core/builder/context.rs new file mode 100644 index 0000000..654fe8d --- /dev/null +++ b/src/app_error/core/builder/context.rs @@ -0,0 +1,134 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Source and context attachment methods for `AppError`. + +use alloc::sync::Arc; +use core::error::Error as CoreError; +#[cfg(feature = "backtrace")] +use std::backtrace::Backtrace; + +use crate::app_error::core::{ + error::Error, + types::{CapturedBacktrace, ContextAttachment} +}; + +impl Error { + /// Attach upstream diagnostics using [`with_source`](Self::with_source) or + /// an existing [`Arc`]. + /// + /// This is the preferred alias for capturing upstream errors. It accepts + /// either an owned error implementing [`core::error::Error`] or a + /// shared [`Arc`] produced by other APIs, reusing the allocation when + /// possible. + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "std")] { + /// use masterror::AppError; + /// + /// let err = AppError::service("downstream degraded") + /// .with_context(std::io::Error::new(std::io::ErrorKind::Other, "boom")); + /// assert!(err.source_ref().is_some()); + /// # } + /// ``` + #[must_use] + pub fn with_context(self, context: impl Into) -> Self { + match context.into() { + ContextAttachment::Owned(source) => { + match source.downcast::>() { + Ok(shared) => self.with_source_arc(*shared), + Err(source) => self.with_source_arc(Arc::from(source)) + } + } + ContextAttachment::Shared(source) => self.with_source_arc(source) + } + } + + /// Attach a source error for diagnostics. + /// + /// Prefer [`with_context`](Self::with_context) when capturing upstream + /// diagnostics without additional `Arc` allocations. + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "std")] { + /// use masterror::{AppError, AppErrorKind}; + /// + /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "boom"); + /// let err = AppError::internal("boom").with_source(io_err); + /// assert!(err.source_ref().is_some()); + /// # } + /// ``` + #[must_use] + pub fn with_source(mut self, source: impl CoreError + Send + Sync + 'static) -> Self { + self.source = Some(Arc::new(source)); + self.mark_dirty(); + self + } + + /// Attach a shared source error without cloning the underlying `Arc`. + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "std")] { + /// use std::sync::Arc; + /// + /// use masterror::{AppError, AppErrorKind}; + /// + /// let source = Arc::new(std::io::Error::new(std::io::ErrorKind::Other, "boom")); + /// let err = AppError::internal("boom").with_source_arc(source.clone()); + /// assert!(err.source_ref().is_some()); + /// assert_eq!(Arc::strong_count(&source), 2); + /// # } + /// ``` + #[must_use] + pub fn with_source_arc(mut self, source: Arc) -> Self { + self.source = Some(source); + self.mark_dirty(); + self + } + + /// Attach a captured backtrace. + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "backtrace")] + /// # { + /// use std::backtrace::Backtrace; + /// + /// use masterror::AppError; + /// + /// let bt = Backtrace::capture(); + /// let err = AppError::internal("test").with_backtrace(bt); + /// # } + /// ``` + #[must_use] + pub fn with_backtrace(mut self, backtrace: CapturedBacktrace) -> Self { + #[cfg(feature = "backtrace")] + { + self.set_backtrace_slot(Arc::new(backtrace)); + } + #[cfg(not(feature = "backtrace"))] + { + self.set_backtrace_slot(backtrace); + } + self.mark_dirty(); + self + } + + /// Attach a shared backtrace without cloning. + /// + /// Internal method for sharing backtraces between errors. + #[cfg(feature = "backtrace")] + pub(crate) fn with_shared_backtrace(mut self, backtrace: Arc) -> Self { + self.set_backtrace_slot(backtrace); + self.mark_dirty(); + self + } +} diff --git a/src/app_error/core/builder/details.rs b/src/app_error/core/builder/details.rs new file mode 100644 index 0000000..34e6f07 --- /dev/null +++ b/src/app_error/core/builder/details.rs @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Details attachment methods for `AppError`. + +#[cfg(not(feature = "serde_json"))] +use alloc::string::String; + +#[cfg(feature = "serde_json")] +use serde::Serialize; +#[cfg(feature = "serde_json")] +use serde_json::{Value as JsonValue, to_value}; + +use crate::app_error::core::error::Error; + +impl Error { + /// Attach structured JSON details for the client payload. + /// + /// The details are omitted from responses when the error has been marked as + /// [`redactable`](Self::redactable). + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "serde_json")] + /// # { + /// use masterror::{AppError, AppErrorKind}; + /// use serde_json::json; + /// + /// let err = AppError::new(AppErrorKind::Validation, "invalid input") + /// .with_details_json(json!({"field": "email"})); + /// assert!(err.details.is_some()); + /// # } + /// ``` + #[must_use] + #[cfg(feature = "serde_json")] + pub fn with_details_json(mut self, details: JsonValue) -> Self { + self.details = Some(details); + self.mark_dirty(); + self + } + + /// Serialize and attach structured details. + /// + /// Returns [`crate::AppError`] with [`crate::AppErrorKind::BadRequest`] if + /// serialization fails. + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "serde_json")] + /// # { + /// use masterror::{AppError, AppErrorKind}; + /// use serde::Serialize; + /// + /// #[derive(Serialize)] + /// struct Extra { + /// reason: &'static str + /// } + /// + /// let err = AppError::new(AppErrorKind::BadRequest, "invalid") + /// .with_details(Extra { + /// reason: "missing" + /// }) + /// .expect("details should serialize"); + /// assert!(err.details.is_some()); + /// # } + /// ``` + #[cfg(feature = "serde_json")] + #[allow(clippy::result_large_err)] + pub fn with_details(self, payload: T) -> crate::AppResult + where + T: Serialize + { + let Ok(details) = to_value(payload) else { + return Err(Self::bad_request("failed to serialize details")); + }; + Ok(self.with_details_json(details)) + } + + /// Attach plain-text details for client payloads. + /// + /// The text is omitted from responses when the error is + /// [`redactable`](Self::redactable). + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(not(feature = "serde_json"))] + /// # { + /// use masterror::{AppError, AppErrorKind}; + /// + /// let err = AppError::new(AppErrorKind::Internal, "boom").with_details_text("retry later"); + /// assert!(err.details.is_some()); + /// # } + /// ``` + #[must_use] + #[cfg(not(feature = "serde_json"))] + pub fn with_details_text(mut self, details: impl Into) -> Self { + self.details = Some(details.into()); + self.mark_dirty(); + self + } +} diff --git a/src/app_error/core/builder/diagnostics.rs b/src/app_error/core/builder/diagnostics.rs new file mode 100644 index 0000000..136388a --- /dev/null +++ b/src/app_error/core/builder/diagnostics.rs @@ -0,0 +1,197 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Diagnostics builder methods for `AppError`. +//! +//! Provides methods to attach hints, suggestions, documentation links, +//! and related error codes to errors. + +use alloc::{borrow::Cow, boxed::Box}; + +use crate::app_error::{ + core::error::Error, + diagnostics::{DiagnosticVisibility, Diagnostics, DocLink, Hint, Suggestion} +}; + +impl Error { + /// Adds a development-only hint to explain the error. + /// + /// Hints provide context about why an error occurred without necessarily + /// offering a solution. They are only shown in Local (development) mode. + /// + /// # Examples + /// + /// ```rust + /// use masterror::AppError; + /// + /// let err = AppError::not_found("User not found") + /// .with_hint("Check if the user ID is correct") + /// .with_hint("User might have been deleted"); + /// ``` + #[must_use] + pub fn with_hint(mut self, message: impl Into>) -> Self { + self.ensure_diagnostics().hints.push(Hint::new(message)); + self.mark_dirty(); + self + } + + /// Adds a hint with custom visibility. + /// + /// Use this when a hint should be visible in Staging or Production. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, DiagnosticVisibility}; + /// + /// let err = AppError::unauthorized("Invalid token").with_hint_visible( + /// "Token may have expired, please login again", + /// DiagnosticVisibility::Public + /// ); + /// ``` + #[must_use] + pub fn with_hint_visible( + mut self, + message: impl Into>, + visibility: DiagnosticVisibility + ) -> Self { + self.ensure_diagnostics() + .hints + .push(Hint::with_visibility(message, visibility)); + self.mark_dirty(); + self + } + + /// Adds an actionable suggestion to fix the error. + /// + /// Suggestions provide concrete steps users can take to resolve an error. + /// They are only shown in Local (development) mode by default. + /// + /// # Examples + /// + /// ```rust + /// use masterror::AppError; + /// + /// let err = AppError::database_with_message("Connection failed") + /// .with_suggestion("Check if the database server is running"); + /// ``` + #[must_use] + pub fn with_suggestion(mut self, message: impl Into>) -> Self { + self.ensure_diagnostics() + .suggestions + .push(Suggestion::new(message)); + self.mark_dirty(); + self + } + + /// Adds a suggestion with an executable command or code snippet. + /// + /// The command is displayed in a distinct style to indicate it can be + /// copied and executed. + /// + /// # Examples + /// + /// ```rust + /// use masterror::AppError; + /// + /// let err = AppError::database_with_message("PostgreSQL connection refused") + /// .with_suggestion_cmd( + /// "Check if PostgreSQL is running", + /// "systemctl status postgresql" + /// ); + /// ``` + #[must_use] + pub fn with_suggestion_cmd( + mut self, + message: impl Into>, + command: impl Into> + ) -> Self { + self.ensure_diagnostics() + .suggestions + .push(Suggestion::with_command(message, command)); + self.mark_dirty(); + self + } + + /// Links to documentation explaining this error. + /// + /// Documentation links are publicly visible by default, helping end users + /// understand and resolve errors. + /// + /// # Examples + /// + /// ```rust + /// use masterror::AppError; + /// + /// let err = AppError::not_found("User not found") + /// .with_docs("https://docs.example.com/errors/USER_NOT_FOUND"); + /// ``` + #[must_use] + pub fn with_docs(mut self, url: impl Into>) -> Self { + self.ensure_diagnostics().doc_link = Some(DocLink::new(url)); + self.mark_dirty(); + self + } + + /// Links to documentation with a human-readable title. + /// + /// # Examples + /// + /// ```rust + /// use masterror::AppError; + /// + /// let err = AppError::unauthorized("Token expired").with_docs_titled( + /// "https://docs.example.com/auth/tokens", + /// "Authentication Guide" + /// ); + /// ``` + #[must_use] + pub fn with_docs_titled( + mut self, + url: impl Into>, + title: impl Into> + ) -> Self { + self.ensure_diagnostics().doc_link = Some(DocLink::with_title(url, title)); + self.mark_dirty(); + self + } + + /// Adds a related error code for cross-reference. + /// + /// Related codes help users discover errors that might provide additional + /// context or alternative explanations. + /// + /// # Examples + /// + /// ```rust + /// use masterror::AppError; + /// + /// let err = AppError::database_with_message("Connection timeout") + /// .with_related_code("DB_POOL_EXHAUSTED") + /// .with_related_code("DB_AUTH_FAILED"); + /// ``` + #[must_use] + pub fn with_related_code(mut self, code: impl Into>) -> Self { + self.ensure_diagnostics().related_codes.push(code.into()); + self.mark_dirty(); + self + } + + /// Returns a mutable reference to diagnostics, initializing if needed. + fn ensure_diagnostics(&mut self) -> &mut Diagnostics { + if self.inner.diagnostics.is_none() { + self.inner.diagnostics = Some(Box::new(Diagnostics::new())); + } + self.inner + .diagnostics + .as_mut() + .expect("diagnostics initialized above") + } + + /// Returns diagnostics if present. + #[must_use] + pub fn diagnostics(&self) -> Option<&Diagnostics> { + self.inner.diagnostics.as_deref() + } +} diff --git a/src/app_error/core/builder/metadata.rs b/src/app_error/core/builder/metadata.rs new file mode 100644 index 0000000..0995500 --- /dev/null +++ b/src/app_error/core/builder/metadata.rs @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Metadata attachment methods for `AppError`. + +use crate::{ + FieldRedaction, + app_error::{ + core::error::Error, + metadata::{Field, Metadata} + } +}; + +impl Error { + /// Attach additional metadata to the error. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind, field}; + /// let err = AppError::new(AppErrorKind::Validation, "bad field") + /// .with_field(field::str("field_name", "email")); + /// assert!(err.metadata().get("field_name").is_some()); + /// ``` + #[must_use] + pub fn with_field(mut self, field: Field) -> Self { + self.metadata.insert(field); + self.mark_dirty(); + self + } + + /// Extend metadata from an iterator of fields. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind, field}; + /// let fields = vec![field::str("key1", "value1"), field::str("key2", "value2")]; + /// let err = AppError::new(AppErrorKind::BadRequest, "test").with_fields(fields); + /// assert!(err.metadata().get("key1").is_some()); + /// ``` + #[must_use] + pub fn with_fields(mut self, fields: impl IntoIterator) -> Self { + self.metadata.extend(fields); + self.mark_dirty(); + self + } + + /// Override the redaction policy for a stored metadata field. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind, FieldRedaction, field}; + /// + /// let err = AppError::new(AppErrorKind::Internal, "test") + /// .with_field(field::str("password", "secret")) + /// .redact_field("password", FieldRedaction::Redact); + /// ``` + #[must_use] + pub fn redact_field(mut self, name: &'static str, redaction: FieldRedaction) -> Self { + self.metadata.set_redaction(name, redaction); + self.mark_dirty(); + self + } + + /// Replace metadata entirely. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind, Metadata}; + /// + /// let metadata = Metadata::new(); + /// let err = AppError::new(AppErrorKind::Internal, "test").with_metadata(metadata); + /// ``` + #[must_use] + pub fn with_metadata(mut self, metadata: Metadata) -> Self { + self.metadata = metadata; + self.mark_dirty(); + self + } +} diff --git a/src/app_error/core/builder/modifiers.rs b/src/app_error/core/builder/modifiers.rs new file mode 100644 index 0000000..aad1eaa --- /dev/null +++ b/src/app_error/core/builder/modifiers.rs @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Modifier methods for `AppError` that change error properties. + +use alloc::string::String; + +use crate::{ + AppCode, RetryAdvice, + app_error::core::{error::Error, types::MessageEditPolicy} +}; + +impl Error { + /// Override the machine-readable [`AppCode`]. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppCode, AppError, AppErrorKind}; + /// let err = AppError::new(AppErrorKind::BadRequest, "test").with_code(AppCode::NotFound); + /// assert_eq!(err.code, AppCode::NotFound); + /// ``` + #[must_use] + pub fn with_code(mut self, code: AppCode) -> Self { + self.code = code; + self.mark_dirty(); + self + } + + /// Attach retry advice to the error. + /// + /// When mapped to HTTP, this becomes the `Retry-After` header. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind}; + /// let err = AppError::new(AppErrorKind::RateLimited, "slow down").with_retry_after_secs(60); + /// assert_eq!(err.retry.map(|r| r.after_seconds), Some(60)); + /// ``` + #[must_use] + pub fn with_retry_after_secs(mut self, secs: u64) -> Self { + self.retry = Some(RetryAdvice { + after_seconds: secs + }); + self.mark_dirty(); + self + } + + /// Attach a `WWW-Authenticate` challenge string. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind}; + /// let err = AppError::new(AppErrorKind::Unauthorized, "auth required") + /// .with_www_authenticate("Bearer realm=\"api\""); + /// assert!(err.www_authenticate.is_some()); + /// ``` + #[must_use] + pub fn with_www_authenticate(mut self, value: impl Into) -> Self { + self.www_authenticate = Some(value.into()); + self.mark_dirty(); + self + } + + /// Mark the message as redactable. + /// + /// # Examples + /// + /// ```rust + /// use masterror::{AppError, AppErrorKind, MessageEditPolicy}; + /// + /// let err = AppError::new(AppErrorKind::Internal, "secret").redactable(); + /// assert_eq!(err.edit_policy, MessageEditPolicy::Redact); + /// ``` + #[must_use] + pub fn redactable(mut self) -> Self { + self.edit_policy = MessageEditPolicy::Redact; + self.mark_dirty(); + self + } +} diff --git a/src/app_error/core/builder/tests.rs b/src/app_error/core/builder/tests.rs new file mode 100644 index 0000000..ee976ed --- /dev/null +++ b/src/app_error/core/builder/tests.rs @@ -0,0 +1,428 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Tests for builder module. + +use crate::{AppCode, AppError, AppErrorKind, FieldRedaction, MessageEditPolicy, Metadata, field}; + +// ───────────────────────────────────────────────────────────────────────────── +// Constructors tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn new_creates_error_with_message() { + let err = AppError::new(AppErrorKind::BadRequest, "test message"); + assert_eq!(err.kind, AppErrorKind::BadRequest); + assert_eq!(err.message.as_deref(), Some("test message")); +} + +#[test] +fn new_with_owned_string() { + let msg = String::from("owned message"); + let err = AppError::new(AppErrorKind::Internal, msg); + assert_eq!(err.message.as_deref(), Some("owned message")); +} + +#[test] +fn with_creates_error_with_message() { + let err = AppError::with(AppErrorKind::Validation, "validation failed"); + assert_eq!(err.kind, AppErrorKind::Validation); + assert_eq!(err.message.as_deref(), Some("validation failed")); +} + +#[test] +fn bare_creates_error_without_message() { + let err = AppError::bare(AppErrorKind::NotFound); + assert_eq!(err.kind, AppErrorKind::NotFound); + assert!(err.message.is_none()); +} + +#[test] +fn bare_sets_correct_code() { + let err = AppError::bare(AppErrorKind::Unauthorized); + assert_eq!(err.code, AppCode::Unauthorized); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Modifiers tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn with_code_overrides_default_code() { + let err = AppError::new(AppErrorKind::BadRequest, "test").with_code(AppCode::NotFound); + assert_eq!(err.code, AppCode::NotFound); +} + +#[test] +fn with_retry_after_secs_sets_retry_advice() { + let err = AppError::new(AppErrorKind::RateLimited, "slow down").with_retry_after_secs(60); + assert!(err.retry.is_some()); + assert_eq!(err.retry.unwrap().after_seconds, 60); +} + +#[test] +fn with_retry_after_secs_zero() { + let err = AppError::new(AppErrorKind::RateLimited, "test").with_retry_after_secs(0); + assert_eq!(err.retry.unwrap().after_seconds, 0); +} + +#[test] +fn with_www_authenticate_sets_header() { + let err = AppError::new(AppErrorKind::Unauthorized, "auth required") + .with_www_authenticate("Bearer realm=\"api\""); + assert_eq!( + err.www_authenticate.as_deref(), + Some("Bearer realm=\"api\"") + ); +} + +#[test] +fn with_www_authenticate_owned_string() { + let challenge = String::from("Basic realm=\"test\""); + let err = AppError::unauthorized("test").with_www_authenticate(challenge); + assert_eq!( + err.www_authenticate.as_deref(), + Some("Basic realm=\"test\"") + ); +} + +#[test] +fn redactable_sets_edit_policy() { + let err = AppError::new(AppErrorKind::Internal, "secret").redactable(); + assert_eq!(err.edit_policy, MessageEditPolicy::Redact); +} + +#[test] +fn redactable_can_be_chained() { + let err = AppError::internal("secret") + .redactable() + .with_code(AppCode::Internal); + assert_eq!(err.edit_policy, MessageEditPolicy::Redact); + assert_eq!(err.code, AppCode::Internal); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Metadata tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn with_field_adds_metadata() { + let err = AppError::new(AppErrorKind::Validation, "bad field") + .with_field(field::str("name", "email")); + assert!(err.metadata().get("name").is_some()); +} + +#[test] +fn with_field_multiple_fields() { + let err = AppError::internal("test") + .with_field(field::str("key1", "value1")) + .with_field(field::u64("key2", 42)); + assert!(err.metadata().get("key1").is_some()); + assert!(err.metadata().get("key2").is_some()); +} + +#[test] +fn with_fields_adds_multiple() { + let fields = vec![ + field::str("a", "1"), + field::str("b", "2"), + field::str("c", "3"), + ]; + let err = AppError::new(AppErrorKind::BadRequest, "test").with_fields(fields); + assert!(err.metadata().get("a").is_some()); + assert!(err.metadata().get("b").is_some()); + assert!(err.metadata().get("c").is_some()); +} + +#[test] +fn with_fields_empty_iterator() { + let err = AppError::internal("test").with_fields(Vec::new()); + assert!(err.metadata().is_empty()); +} + +#[test] +fn redact_field_sets_redaction() { + let err = AppError::new(AppErrorKind::Internal, "test") + .with_field(field::str("password", "secret")) + .redact_field("password", FieldRedaction::Redact); + // Field exists but is marked for redaction + assert!(err.metadata().get("password").is_some()); +} + +#[test] +fn redact_field_nonexistent_field() { + let err = AppError::internal("test").redact_field("nonexistent", FieldRedaction::Redact); + // Should not panic, just no-op + assert!(err.metadata().get("nonexistent").is_none()); +} + +#[test] +fn with_metadata_replaces_all() { + let mut metadata = Metadata::new(); + metadata.insert(field::str("new_key", "new_value")); + let err = AppError::internal("test") + .with_field(field::str("old_key", "old_value")) + .with_metadata(metadata); + assert!(err.metadata().get("old_key").is_none()); + assert!(err.metadata().get("new_key").is_some()); +} + +#[test] +fn with_metadata_empty() { + let err = AppError::internal("test") + .with_field(field::str("key", "value")) + .with_metadata(Metadata::new()); + assert!(err.metadata().is_empty()); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Context tests +// ───────────────────────────────────────────────────────────────────────────── + +#[cfg(feature = "std")] +#[test] +fn with_source_attaches_error() { + use std::io::{Error as IoError, ErrorKind}; + let io_err = IoError::new(ErrorKind::NotFound, "file not found"); + let err = AppError::internal("failed").with_source(io_err); + assert!(err.source_ref().is_some()); +} + +#[cfg(feature = "std")] +#[test] +fn with_source_arc_shares_error() { + use std::{io::Error as IoError, sync::Arc}; + let source = Arc::new(IoError::other("shared error")); + let err = AppError::internal("test").with_source_arc(source.clone()); + assert!(err.source_ref().is_some()); + assert_eq!(Arc::strong_count(&source), 2); +} + +#[cfg(feature = "std")] +#[test] +fn with_context_accepts_owned_error() { + use std::io::Error as IoError; + let io_err = IoError::other("context error"); + let err = AppError::service("degraded").with_context(io_err); + assert!(err.source_ref().is_some()); +} + +#[cfg(feature = "std")] +#[test] +fn with_context_accepts_arc() { + use std::{io::Error as IoError, sync::Arc}; + let source: Arc = Arc::new(IoError::other("arc error")); + let err = AppError::internal("test").with_context(source); + assert!(err.source_ref().is_some()); +} + +#[cfg(feature = "backtrace")] +#[test] +fn with_backtrace_attaches_backtrace() { + use std::backtrace::Backtrace; + let bt = Backtrace::capture(); + let err = AppError::internal("test").with_backtrace(bt); + // Just ensure it doesn't panic + let _ = err; +} + +// ───────────────────────────────────────────────────────────────────────────── +// Details tests +// ───────────────────────────────────────────────────────────────────────────── + +#[cfg(feature = "serde_json")] +#[test] +fn with_details_json_attaches_value() { + use serde_json::json; + let err = AppError::new(AppErrorKind::Validation, "invalid") + .with_details_json(json!({"field": "email", "reason": "invalid format"})); + assert!(err.details.is_some()); +} + +#[cfg(feature = "serde_json")] +#[test] +fn with_details_json_null() { + use serde_json::Value; + let err = AppError::internal("test").with_details_json(Value::Null); + assert!(err.details.is_some()); +} + +#[cfg(feature = "serde_json")] +#[test] +fn with_details_serializes_struct() { + use serde::Serialize; + + #[derive(Serialize)] + struct Details { + code: u32, + reason: &'static str + } + + let err = AppError::bad_request("invalid") + .with_details(Details { + code: 100, + reason: "missing field" + }) + .expect("serialization should succeed"); + assert!(err.details.is_some()); +} + +#[cfg(feature = "serde_json")] +#[test] +fn with_details_handles_serialization_error() { + use serde::Serialize; + + #[derive(Serialize)] + struct BadStruct { + #[serde(serialize_with = "fail_serialize")] + value: u32 + } + + fn fail_serialize(_: &u32, _: S) -> Result + where + S: serde::Serializer + { + Err(serde::ser::Error::custom("intentional failure")) + } + + let result = AppError::internal("test").with_details(BadStruct { + value: 0 + }); + assert!(result.is_err()); +} + +#[cfg(not(feature = "serde_json"))] +#[test] +fn with_details_text_attaches_string() { + let err = AppError::internal("test").with_details_text("additional info"); + assert!(err.details.is_some()); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Diagnostics tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn with_hint_adds_hint() { + let err = AppError::not_found("User not found").with_hint("Check user ID"); + let diag = err.diagnostics().expect("diagnostics should exist"); + assert_eq!(diag.hints.len(), 1); +} + +#[test] +fn with_hint_multiple() { + let err = AppError::not_found("test") + .with_hint("hint 1") + .with_hint("hint 2") + .with_hint("hint 3"); + let diag = err.diagnostics().unwrap(); + assert_eq!(diag.hints.len(), 3); +} + +#[test] +fn with_hint_visible_sets_visibility() { + use crate::DiagnosticVisibility; + let err = AppError::unauthorized("test") + .with_hint_visible("public hint", DiagnosticVisibility::Public); + let diag = err.diagnostics().unwrap(); + assert_eq!(diag.hints[0].visibility, DiagnosticVisibility::Public); +} + +#[test] +fn with_suggestion_adds_suggestion() { + let err = + AppError::database_with_message("Connection failed").with_suggestion("Check DB server"); + let diag = err.diagnostics().unwrap(); + assert_eq!(diag.suggestions.len(), 1); +} + +#[test] +fn with_suggestion_cmd_includes_command() { + let err = AppError::database_with_message("test") + .with_suggestion_cmd("Check status", "systemctl status postgresql"); + let diag = err.diagnostics().unwrap(); + assert!(diag.suggestions[0].command.is_some()); + assert_eq!( + diag.suggestions[0].command.as_deref(), + Some("systemctl status postgresql") + ); +} + +#[test] +fn with_docs_sets_doc_link() { + let err = AppError::not_found("test").with_docs("https://docs.example.com/errors/NOT_FOUND"); + let diag = err.diagnostics().unwrap(); + assert!(diag.doc_link.is_some()); + assert_eq!( + diag.doc_link.as_ref().unwrap().url.as_ref(), + "https://docs.example.com/errors/NOT_FOUND" + ); +} + +#[test] +fn with_docs_titled_includes_title() { + let err = AppError::unauthorized("test") + .with_docs_titled("https://docs.example.com/auth", "Authentication Guide"); + let diag = err.diagnostics().unwrap(); + let doc = diag.doc_link.as_ref().unwrap(); + assert_eq!(doc.title.as_deref(), Some("Authentication Guide")); +} + +#[test] +fn with_related_code_adds_code() { + let err = AppError::database_with_message("test") + .with_related_code("DB_POOL_EXHAUSTED") + .with_related_code("DB_AUTH_FAILED"); + let diag = err.diagnostics().unwrap(); + assert_eq!(diag.related_codes.len(), 2); +} + +#[test] +fn diagnostics_returns_none_when_empty() { + let err = AppError::internal("no diagnostics"); + assert!(err.diagnostics().is_none()); +} + +#[test] +fn diagnostics_returns_some_when_present() { + let err = AppError::internal("test").with_hint("a hint"); + assert!(err.diagnostics().is_some()); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Chaining tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn all_builders_can_be_chained() { + let err = AppError::new(AppErrorKind::Service, "service error") + .with_code(AppCode::Service) + .with_retry_after_secs(30) + .with_field(field::str("service", "payment")) + .with_hint("Check service health") + .with_suggestion("Retry in 30 seconds") + .with_docs("https://docs.example.com/errors"); + + assert_eq!(err.code, AppCode::Service); + assert!(err.retry.is_some()); + assert!(err.metadata().get("service").is_some()); + assert!(err.diagnostics().is_some()); +} + +#[cfg(feature = "std")] +#[test] +fn chaining_with_source_preserves_all() { + use std::io::Error as IoError; + + let err = AppError::internal("test") + .with_field(field::u64("request_id", 12345)) + .with_source(IoError::other("underlying error")) + .with_hint("debug hint") + .redactable(); + + assert!(err.metadata().get("request_id").is_some()); + assert!(err.source_ref().is_some()); + assert!(err.diagnostics().is_some()); + assert_eq!(err.edit_policy, MessageEditPolicy::Redact); +} diff --git a/src/app_error/core/display.rs b/src/app_error/core/display.rs index cc92573..77c2dc1 100644 --- a/src/app_error/core/display.rs +++ b/src/app_error/core/display.rs @@ -1,799 +1,19 @@ -// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-FileCopyrightText: 2025-2026 RAprogramm // // SPDX-License-Identifier: MIT -use alloc::string::ToString; -use core::{ - error::Error as CoreError, - fmt::{Formatter, Result as FmtResult}, - sync::atomic::{AtomicU8, Ordering} -}; +//! Display formatting for `AppError`. +//! +//! Provides environment-aware display modes: production (compact JSON), +//! local (human-readable), and staging (JSON with context). -use super::error::Error; -use crate::{FieldRedaction, FieldValue, MessageEditPolicy}; - -/// Display mode for error output. -/// -/// Controls the structure and verbosity of error messages based on -/// the deployment environment. The mode is determined by the -/// `MASTERROR_ENV` environment variable or auto-detected based on -/// build configuration and runtime environment. -/// -/// # Examples -/// -/// ``` -/// use masterror::DisplayMode; -/// -/// let mode = DisplayMode::current(); -/// match mode { -/// DisplayMode::Prod => println!("Production mode: JSON output"), -/// DisplayMode::Local => println!("Local mode: Human-readable output"), -/// DisplayMode::Staging => println!("Staging mode: JSON with context") -/// } -/// ``` -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DisplayMode { - /// Production mode: lightweight JSON, minimal fields, no sensitive data. - /// - /// Output includes only: `kind`, `code`, `message` (if not redacted). - /// Metadata is filtered to exclude sensitive fields. - /// Source chain and backtrace are excluded. - /// - /// # Example Output - /// - /// ```json - /// {"kind":"NotFound","code":"NOT_FOUND","message":"User not found"} - /// ``` - Prod = 0, - - /// Development mode: human-readable, full context. - /// - /// Output includes: error details, full source chain, complete metadata, - /// and backtrace (if enabled). Supports colored output when the `colored` - /// feature is enabled and output is a TTY. - /// - /// # Example Output - /// - /// ```text - /// Error: NotFound - /// Code: NOT_FOUND - /// Message: User not found - /// - /// Caused by: database query failed - /// Caused by: connection timeout - /// - /// Context: - /// user_id: 12345 - /// ``` - Local = 1, - - /// Staging mode: JSON with additional context. - /// - /// Output includes: `kind`, `code`, `message`, limited `source_chain`, - /// and filtered metadata. No backtrace. - /// - /// # Example Output - /// - /// ```json - /// {"kind":"NotFound","code":"NOT_FOUND","message":"User not found","source_chain":["database error"],"metadata":{"user_id":12345}} - /// ``` - Staging = 2 -} - -impl DisplayMode { - /// Returns the current display mode based on environment configuration. - /// - /// The mode is determined by checking (in order): - /// 1. `MASTERROR_ENV` environment variable (`prod`, `local`, or `staging`) - /// 2. Kubernetes environment detection (`KUBERNETES_SERVICE_HOST`) - /// 3. Build configuration (`cfg!(debug_assertions)`) - /// - /// The result is cached for performance. - /// - /// # Examples - /// - /// ``` - /// use masterror::DisplayMode; - /// - /// let mode = DisplayMode::current(); - /// assert!(matches!( - /// mode, - /// DisplayMode::Prod | DisplayMode::Local | DisplayMode::Staging - /// )); - /// ``` - #[must_use] - pub fn current() -> Self { - static CACHED_MODE: AtomicU8 = AtomicU8::new(255); - let cached = CACHED_MODE.load(Ordering::Relaxed); - if cached != 255 { - return match cached { - 0 => Self::Prod, - 1 => Self::Local, - 2 => Self::Staging, - _ => unreachable!() - }; - } - let mode = Self::detect(); - CACHED_MODE.store(mode as u8, Ordering::Relaxed); - mode - } - - /// Detects the appropriate display mode from environment. - /// - /// This is an internal helper called by [`current()`](Self::current). - fn detect() -> Self { - #[cfg(feature = "std")] - { - use std::env::var; - if let Ok(env) = var("MASTERROR_ENV") { - return match env.as_str() { - "prod" | "production" => Self::Prod, - "local" | "dev" | "development" => Self::Local, - "staging" | "stage" => Self::Staging, - _ => Self::detect_auto() - }; - } - if var("KUBERNETES_SERVICE_HOST").is_ok() { - return Self::Prod; - } - } - Self::detect_auto() - } - - /// Auto-detects mode based on build configuration. - fn detect_auto() -> Self { - if cfg!(debug_assertions) { - Self::Local - } else { - Self::Prod - } - } -} - -#[allow(dead_code)] -impl Error { - /// Formats error in production mode (compact JSON). - /// - /// # Arguments - /// - /// * `f` - Formatter to write output to - /// - /// # Examples - /// - /// ``` - /// use masterror::AppError; - /// - /// let error = AppError::not_found("User not found"); - /// let output = format!("{}", error); - /// // In prod mode: {"kind":"NotFound","code":"NOT_FOUND","message":"User not found"} - /// ``` - #[cfg(not(test))] - pub(crate) fn fmt_prod(&self, f: &mut Formatter<'_>) -> FmtResult { - self.fmt_prod_impl(f) - } - - #[cfg(test)] - #[allow(missing_docs)] - pub fn fmt_prod(&self, f: &mut Formatter<'_>) -> FmtResult { - self.fmt_prod_impl(f) - } - - fn fmt_prod_impl(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, r#"{{"kind":"{:?}","code":"{}""#, self.kind, self.code)?; - if !matches!(self.edit_policy, MessageEditPolicy::Redact) - && let Some(msg) = &self.message - { - write!(f, ",\"message\":\"")?; - write_json_escaped(f, msg.as_ref())?; - write!(f, "\"")?; - } - if !self.metadata.is_empty() { - let has_public_fields = self - .metadata - .iter_with_redaction() - .any(|(_, _, redaction)| !matches!(redaction, FieldRedaction::Redact)); - if has_public_fields { - write!(f, r#","metadata":{{"#)?; - let mut first = true; - for (name, value, redaction) in self.metadata.iter_with_redaction() { - if matches!(redaction, FieldRedaction::Redact) { - continue; - } - if !first { - write!(f, ",")?; - } - first = false; - write!(f, r#""{}":"#, name)?; - write_metadata_value(f, value)?; - } - write!(f, "}}")?; - } - } - write!(f, "}}") - } - - /// Formats error in local/development mode (human-readable). - /// - /// # Arguments - /// - /// * `f` - Formatter to write output to - /// - /// # Examples - /// - /// ``` - /// use masterror::AppError; - /// - /// let error = AppError::internal("Database error"); - /// let output = format!("{}", error); - /// // In local mode: multi-line human-readable format with full context - /// ``` - #[cfg(not(test))] - pub(crate) fn fmt_local(&self, f: &mut Formatter<'_>) -> FmtResult { - self.fmt_local_impl(f) - } - - #[cfg(test)] - #[allow(missing_docs)] - pub fn fmt_local(&self, f: &mut Formatter<'_>) -> FmtResult { - self.fmt_local_impl(f) - } - - fn fmt_local_impl(&self, f: &mut Formatter<'_>) -> FmtResult { - #[cfg(feature = "colored")] - { - use crate::colored::style; - writeln!(f, "Error: {}", self.kind)?; - writeln!(f, "Code: {}", style::error_code(self.code.to_string()))?; - if let Some(msg) = &self.message { - writeln!(f, "Message: {}", style::error_message(msg))?; - } - if let Some(source) = &self.source { - writeln!(f)?; - let mut current: &dyn CoreError = source.as_ref(); - let mut depth = 0; - while depth < 10 { - writeln!( - f, - " {}: {}", - style::source_context("Caused by"), - style::source_context(current.to_string()) - )?; - if let Some(next) = current.source() { - current = next; - depth += 1; - } else { - break; - } - } - } - if !self.metadata.is_empty() { - writeln!(f)?; - writeln!(f, "Context:")?; - for (key, value) in self.metadata.iter() { - writeln!(f, " {}: {}", style::metadata_key(key), value)?; - } - } - Ok(()) - } - #[cfg(not(feature = "colored"))] - { - writeln!(f, "Error: {}", self.kind)?; - writeln!(f, "Code: {}", self.code)?; - if let Some(msg) = &self.message { - writeln!(f, "Message: {}", msg)?; - } - if let Some(source) = &self.source { - writeln!(f)?; - let mut current: &dyn CoreError = source.as_ref(); - let mut depth = 0; - while depth < 10 { - writeln!(f, " Caused by: {}", current)?; - if let Some(next) = current.source() { - current = next; - depth += 1; - } else { - break; - } - } - } - if !self.metadata.is_empty() { - writeln!(f)?; - writeln!(f, "Context:")?; - for (key, value) in self.metadata.iter() { - writeln!(f, " {}: {}", key, value)?; - } - } - Ok(()) - } - } - - /// Formats error in staging mode (JSON with context). - /// - /// # Arguments - /// - /// * `f` - Formatter to write output to - /// - /// # Examples - /// - /// ``` - /// use masterror::AppError; - /// - /// let error = AppError::service("Service unavailable"); - /// let output = format!("{}", error); - /// // In staging mode: JSON with source_chain and metadata - /// ``` - #[cfg(not(test))] - pub(crate) fn fmt_staging(&self, f: &mut Formatter<'_>) -> FmtResult { - self.fmt_staging_impl(f) - } - - #[cfg(test)] - #[allow(missing_docs)] - pub fn fmt_staging(&self, f: &mut Formatter<'_>) -> FmtResult { - self.fmt_staging_impl(f) - } - - fn fmt_staging_impl(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, r#"{{"kind":"{:?}","code":"{}""#, self.kind, self.code)?; - if !matches!(self.edit_policy, MessageEditPolicy::Redact) - && let Some(msg) = &self.message - { - write!(f, ",\"message\":\"")?; - write_json_escaped(f, msg.as_ref())?; - write!(f, "\"")?; - } - if let Some(source) = &self.source { - write!(f, r#","source_chain":["#)?; - let mut current: &dyn CoreError = source.as_ref(); - let mut depth = 0; - let mut first = true; - while depth < 5 { - if !first { - write!(f, ",")?; - } - first = false; - write!(f, "\"")?; - write_json_escaped(f, ¤t.to_string())?; - write!(f, "\"")?; - if let Some(next) = current.source() { - current = next; - depth += 1; - } else { - break; - } - } - write!(f, "]")?; - } - if !self.metadata.is_empty() { - let has_public_fields = self - .metadata - .iter_with_redaction() - .any(|(_, _, redaction)| !matches!(redaction, FieldRedaction::Redact)); - if has_public_fields { - write!(f, r#","metadata":{{"#)?; - let mut first = true; - for (name, value, redaction) in self.metadata.iter_with_redaction() { - if matches!(redaction, FieldRedaction::Redact) { - continue; - } - if !first { - write!(f, ",")?; - } - first = false; - write!(f, r#""{}":"#, name)?; - write_metadata_value(f, value)?; - } - write!(f, "}}")?; - } - } - write!(f, "}}") - } -} - -/// Writes a string with JSON escaping. -#[allow(dead_code)] -fn write_json_escaped(f: &mut Formatter<'_>, s: &str) -> FmtResult { - for ch in s.chars() { - match ch { - '"' => write!(f, "\\\"")?, - '\\' => write!(f, "\\\\")?, - '\n' => write!(f, "\\n")?, - '\r' => write!(f, "\\r")?, - '\t' => write!(f, "\\t")?, - ch if ch.is_control() => write!(f, "\\u{:04x}", ch as u32)?, - ch => write!(f, "{}", ch)? - } - } - Ok(()) -} - -/// Writes a metadata field value in JSON format. -#[allow(dead_code)] -fn write_metadata_value(f: &mut Formatter<'_>, value: &FieldValue) -> FmtResult { - use crate::app_error::metadata::FieldValue; - match value { - FieldValue::Str(s) => { - write!(f, "\"")?; - write_json_escaped(f, s.as_ref())?; - write!(f, "\"") - } - FieldValue::I64(v) => write!(f, "{}", v), - FieldValue::U64(v) => write!(f, "{}", v), - FieldValue::F64(v) => { - if v.is_finite() { - write!(f, "{}", v) - } else { - write!(f, "null") - } - } - FieldValue::Bool(v) => write!(f, "{}", v), - FieldValue::Uuid(v) => write!(f, "\"{}\"", v), - FieldValue::Duration(v) => { - write!( - f, - r#"{{"secs":{},"nanos":{}}}"#, - v.as_secs(), - v.subsec_nanos() - ) - } - FieldValue::Ip(v) => write!(f, "\"{}\"", v), - #[cfg(feature = "serde_json")] - FieldValue::Json(v) => write!(f, "{}", v) - } -} +mod helpers; +mod local; +mod mode; +mod prod; +mod staging; #[cfg(test)] -mod tests { - use super::*; - use crate::{AppError, field}; - - #[test] - fn display_mode_current_returns_valid_mode() { - let mode = DisplayMode::current(); - assert!(matches!( - mode, - DisplayMode::Prod | DisplayMode::Local | DisplayMode::Staging - )); - } - - #[test] - fn display_mode_detect_auto_returns_local_in_debug() { - if cfg!(debug_assertions) { - assert_eq!(DisplayMode::detect_auto(), DisplayMode::Local); - } else { - assert_eq!(DisplayMode::detect_auto(), DisplayMode::Prod); - } - } - - #[test] - fn fmt_prod_outputs_json() { - let error = AppError::not_found("User not found"); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""kind":"NotFound""#)); - assert!(output.contains(r#""code":"NOT_FOUND""#)); - assert!(output.contains(r#""message":"User not found""#)); - } - - #[test] - fn fmt_prod_excludes_redacted_message() { - let error = AppError::internal("secret").redactable(); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(!output.contains("secret")); - } - - #[test] - fn fmt_prod_includes_metadata() { - let error = AppError::not_found("User not found").with_field(field::u64("user_id", 12345)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""metadata""#)); - assert!(output.contains(r#""user_id":12345"#)); - } - - #[test] - fn fmt_prod_excludes_sensitive_metadata() { - let error = AppError::internal("Error").with_field(field::str("password", "secret")); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(!output.contains("secret")); - } - - #[test] - fn fmt_local_outputs_human_readable() { - let error = AppError::not_found("User not found"); - let output = format!("{}", error.fmt_local_wrapper()); - assert!(output.contains("Error:")); - assert!(output.contains("Code: NOT_FOUND")); - assert!(output.contains("Message: User not found")); - } - - #[cfg(feature = "std")] - #[test] - fn fmt_local_includes_source_chain() { - use std::io::Error as IoError; - let io_err = IoError::other("connection failed"); - let error = AppError::internal("Database error").with_source(io_err); - let output = format!("{}", error.fmt_local_wrapper()); - assert!(output.contains("Caused by")); - assert!(output.contains("connection failed")); - } - - #[test] - fn fmt_staging_outputs_json_with_context() { - let error = AppError::service("Service unavailable"); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(output.contains(r#""kind":"Service""#)); - assert!(output.contains(r#""code":"SERVICE""#)); - } - - #[cfg(feature = "std")] - #[test] - fn fmt_staging_includes_source_chain() { - use std::io::Error as IoError; - let io_err = IoError::other("timeout"); - let error = AppError::network("Network error").with_source(io_err); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(output.contains(r#""source_chain""#)); - assert!(output.contains("timeout")); - } - - #[test] - fn fmt_prod_escapes_special_chars() { - let error = AppError::internal("Line\nwith\"quotes\""); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#"\n"#)); - assert!(output.contains(r#"\""#)); - } - - #[test] - fn fmt_prod_handles_infinity_in_metadata() { - let error = AppError::internal("Error").with_field(field::f64("ratio", f64::INFINITY)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains("null")); - } - - #[test] - fn fmt_prod_formats_duration_metadata() { - use core::time::Duration; - let error = AppError::internal("Error") - .with_field(field::duration("elapsed", Duration::from_millis(1500))); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""secs":1"#)); - assert!(output.contains(r#""nanos":500000000"#)); - } - - #[test] - fn fmt_prod_formats_bool_metadata() { - let error = AppError::internal("Error").with_field(field::bool("active", true)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""active":true"#)); - } - - #[cfg(feature = "std")] - #[test] - fn fmt_prod_formats_ip_metadata() { - use std::net::IpAddr; - let ip: IpAddr = "192.168.1.1".parse().unwrap(); - let error = AppError::internal("Error").with_field(field::ip("client_ip", ip)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""client_ip":"192.168.1.1""#)); - } - - #[test] - fn fmt_prod_formats_uuid_metadata() { - use uuid::Uuid; - let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); - let error = AppError::internal("Error").with_field(field::uuid("request_id", uuid)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""request_id":"550e8400-e29b-41d4-a716-446655440000""#)); - } - - #[cfg(feature = "serde_json")] - #[test] - fn fmt_prod_formats_json_metadata() { - let json = serde_json::json!({"nested": "value"}); - let error = AppError::internal("Error").with_field(field::json("data", json)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""data":"#)); - } - - #[test] - fn fmt_prod_without_message() { - let error = AppError::bare(crate::AppErrorKind::Internal); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""kind":"Internal""#)); - assert!(!output.contains(r#""message""#)); - } - - #[test] - fn fmt_local_without_message() { - let error = AppError::bare(crate::AppErrorKind::BadRequest); - let output = format!("{}", error.fmt_local_wrapper()); - assert!(output.contains("Error:")); - assert!(!output.contains("Message:")); - } - - #[test] - fn fmt_local_with_metadata() { - let error = AppError::internal("Error") - .with_field(field::str("key", "value")) - .with_field(field::i64("count", -42)); - let output = format!("{}", error.fmt_local_wrapper()); - assert!(output.contains("Context:")); - assert!(output.contains("key: value")); - assert!(output.contains("count: -42")); - } - - #[test] - fn fmt_staging_without_message() { - let error = AppError::bare(crate::AppErrorKind::Timeout); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(output.contains(r#""kind":"Timeout""#)); - assert!(!output.contains(r#""message""#)); - } - - #[test] - fn fmt_staging_with_metadata() { - let error = AppError::service("Service error").with_field(field::u64("retry_count", 3)); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(output.contains(r#""metadata""#)); - assert!(output.contains(r#""retry_count":3"#)); - } - - #[test] - fn fmt_staging_with_redacted_message() { - let error = AppError::internal("sensitive data").redactable(); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(!output.contains("sensitive data")); - } - - #[test] - fn fmt_prod_escapes_control_chars() { - let error = AppError::internal("test\x00\x1F"); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#"\u0000"#)); - assert!(output.contains(r#"\u001f"#)); - } - - #[test] - fn fmt_prod_escapes_tab_and_carriage_return() { - let error = AppError::internal("line\ttab\rreturn"); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#"\t"#)); - assert!(output.contains(r#"\r"#)); - } - - #[test] - fn display_mode_current_caches_result() { - let first = DisplayMode::current(); - let second = DisplayMode::current(); - assert_eq!(first, second); - } - - #[test] - fn display_mode_detect_auto_returns_prod_in_release() { - if !cfg!(debug_assertions) { - assert_eq!(DisplayMode::detect_auto(), DisplayMode::Prod); - } - } - - #[test] - fn fmt_prod_with_multiple_metadata_fields() { - let error = AppError::not_found("test") - .with_field(field::str("first", "value1")) - .with_field(field::u64("second", 42)) - .with_field(field::bool("third", true)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""first":"value1""#)); - assert!(output.contains(r#""second":42"#)); - assert!(output.contains(r#""third":true"#)); - } - - #[test] - fn fmt_prod_escapes_backslash() { - let error = AppError::internal("path\\to\\file"); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#"path\\to\\file"#)); - } - - #[test] - fn fmt_prod_with_i64_metadata() { - let error = AppError::internal("test").with_field(field::i64("count", -100)); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""count":-100"#)); - } - - #[test] - fn fmt_prod_with_string_metadata() { - let error = AppError::internal("test").with_field(field::str("name", "value")); - let output = format!("{}", error.fmt_prod_wrapper()); - assert!(output.contains(r#""name":"value""#)); - } - - #[cfg(feature = "colored")] - #[test] - fn fmt_local_with_deep_source_chain() { - use std::io::{Error as IoError, ErrorKind}; - let io1 = IoError::new(ErrorKind::NotFound, "level 1"); - let io2 = IoError::other(io1); - let error = AppError::internal("top").with_source(io2); - let output = format!("{}", error.fmt_local_wrapper()); - assert!(output.contains("Caused by")); - assert!(output.contains("level 1")); - } - - #[test] - fn fmt_staging_with_multiple_metadata_fields() { - let error = AppError::service("error") - .with_field(field::str("key1", "value1")) - .with_field(field::u64("key2", 123)) - .with_field(field::bool("key3", false)); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(output.contains(r#""key1":"value1""#)); - assert!(output.contains(r#""key2":123"#)); - assert!(output.contains(r#""key3":false"#)); - } - - #[test] - fn fmt_staging_with_deep_source_chain() { - use std::io::{Error as IoError, ErrorKind}; - let io1 = IoError::new(ErrorKind::NotFound, "inner error"); - let io2 = IoError::other(io1); - let error = AppError::service("outer").with_source(io2); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(output.contains(r#""source_chain""#)); - assert!(output.contains("inner error")); - } - - #[test] - fn fmt_staging_with_redacted_and_public_metadata() { - let error = AppError::internal("test") - .with_field(field::str("public", "visible")) - .with_field(field::str("password", "secret")); - let output = format!("{}", error.fmt_staging_wrapper()); - assert!(output.contains(r#""public":"visible""#)); - assert!(!output.contains("secret")); - } - - impl Error { - fn fmt_prod_wrapper(&self) -> FormatterWrapper<'_> { - FormatterWrapper { - error: self, - mode: FormatterMode::Prod - } - } - - fn fmt_local_wrapper(&self) -> FormatterWrapper<'_> { - FormatterWrapper { - error: self, - mode: FormatterMode::Local - } - } - - fn fmt_staging_wrapper(&self) -> FormatterWrapper<'_> { - FormatterWrapper { - error: self, - mode: FormatterMode::Staging - } - } - } - - enum FormatterMode { - Prod, - Local, - Staging - } - - struct FormatterWrapper<'a> { - error: &'a Error, - mode: FormatterMode - } +mod tests; - impl core::fmt::Display for FormatterWrapper<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - match self.mode { - FormatterMode::Prod => self.error.fmt_prod(f), - FormatterMode::Local => self.error.fmt_local(f), - FormatterMode::Staging => self.error.fmt_staging(f) - } - } - } -} +pub use mode::DisplayMode; diff --git a/src/app_error/core/display/helpers.rs b/src/app_error/core/display/helpers.rs new file mode 100644 index 0000000..d86295f --- /dev/null +++ b/src/app_error/core/display/helpers.rs @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Helper functions for display formatting. + +use core::fmt::{Formatter, Result as FmtResult}; + +use crate::FieldValue; + +#[allow(dead_code)] +/// Writes a string with JSON escaping. +pub(super) fn write_json_escaped(f: &mut Formatter<'_>, s: &str) -> FmtResult { + for ch in s.chars() { + match ch { + '"' => write!(f, "\\\"")?, + '\\' => write!(f, "\\\\")?, + '\n' => write!(f, "\\n")?, + '\r' => write!(f, "\\r")?, + '\t' => write!(f, "\\t")?, + ch if ch.is_control() => write!(f, "\\u{:04x}", ch as u32)?, + ch => write!(f, "{}", ch)? + } + } + Ok(()) +} + +#[allow(dead_code)] +/// Writes a metadata field value in JSON format. +pub(super) fn write_metadata_value(f: &mut Formatter<'_>, value: &FieldValue) -> FmtResult { + match value { + FieldValue::Str(s) => { + write!(f, "\"")?; + write_json_escaped(f, s.as_ref())?; + write!(f, "\"") + } + FieldValue::I64(v) => write!(f, "{}", v), + FieldValue::U64(v) => write!(f, "{}", v), + FieldValue::F64(v) => { + if v.is_finite() { + write!(f, "{}", v) + } else { + write!(f, "null") + } + } + FieldValue::Bool(v) => write!(f, "{}", v), + FieldValue::Uuid(v) => write!(f, "\"{}\"", v), + FieldValue::Duration(v) => { + write!( + f, + r#"{{"secs":{},"nanos":{}}}"#, + v.as_secs(), + v.subsec_nanos() + ) + } + FieldValue::Ip(v) => write!(f, "\"{}\"", v), + #[cfg(feature = "serde_json")] + FieldValue::Json(v) => write!(f, "{}", v) + } +} + +#[allow(dead_code)] +/// Writes the JSON header with kind, code, and optional message. +pub(super) fn write_json_header( + f: &mut Formatter<'_>, + kind: &crate::AppErrorKind, + code: &crate::AppCode, + message: Option<&str>, + edit_policy: crate::MessageEditPolicy +) -> FmtResult { + write!(f, r#"{{"kind":"{:?}","code":"{}""#, kind, code)?; + if !matches!(edit_policy, crate::MessageEditPolicy::Redact) + && let Some(msg) = message + { + write!(f, ",\"message\":\"")?; + write_json_escaped(f, msg)?; + write!(f, "\"")?; + } + Ok(()) +} + +#[allow(dead_code)] +/// Writes metadata as JSON object, respecting field redaction policies. +pub(super) fn write_metadata_json(f: &mut Formatter<'_>, metadata: &crate::Metadata) -> FmtResult { + use crate::FieldRedaction; + + if metadata.is_empty() { + return Ok(()); + } + + let has_public_fields = metadata + .iter_with_redaction() + .any(|(_, _, redaction)| !matches!(redaction, FieldRedaction::Redact)); + + if !has_public_fields { + return Ok(()); + } + + write!(f, r#","metadata":{{"#)?; + let mut first = true; + for (name, value, redaction) in metadata.iter_with_redaction() { + if matches!(redaction, FieldRedaction::Redact) { + continue; + } + if !first { + write!(f, ",")?; + } + first = false; + write!(f, r#""{}":"#, name)?; + write_metadata_value(f, value)?; + } + write!(f, "}}") +} diff --git a/src/app_error/core/display/local.rs b/src/app_error/core/display/local.rs new file mode 100644 index 0000000..528df9b --- /dev/null +++ b/src/app_error/core/display/local.rs @@ -0,0 +1,263 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Local/development mode formatting (human-readable). + +use alloc::string::ToString; +use core::{ + error::Error as CoreError, + fmt::{Formatter, Result as FmtResult} +}; + +use crate::app_error::core::error::Error; +// Internal styling - uses colored when available, identity otherwise +#[cfg(feature = "colored")] +use crate::colored::style; + +#[cfg(not(feature = "colored"))] +#[allow(dead_code)] +mod style { + use alloc::string::{String, ToString}; + + macro_rules! identity_style { + ($($name:ident),* $(,)?) => { + $( + #[inline] + pub fn $name(text: impl AsRef) -> String { + text.as_ref().to_string() + } + )* + }; + } + + identity_style! { + error_code, + error_message, + source_context, + metadata_key, + hint_label, + hint_text, + suggestion_label, + suggestion_text, + command, + docs_label, + url, + related_label, + backtrace_label, + backtrace_arrow, + backtrace_function, + backtrace_location, + } + + #[inline] + pub fn backtrace_link(display: &str, _absolute_path: &str, _line: Option) -> String { + display.to_string() + } +} + +#[allow(dead_code)] +impl Error { + /// Formats error in local/development mode (human-readable). + /// + /// # Arguments + /// + /// * `f` - Formatter to write output to + /// + /// # Examples + /// + /// ``` + /// use masterror::AppError; + /// + /// let error = AppError::internal("Database error"); + /// let output = format!("{}", error); + /// // In local mode: multi-line human-readable format with full context + /// ``` + #[cfg(not(test))] + pub(crate) fn fmt_local(&self, f: &mut Formatter<'_>) -> FmtResult { + self.fmt_local_impl(f) + } + + #[cfg(test)] + #[allow(missing_docs)] + pub fn fmt_local(&self, f: &mut Formatter<'_>) -> FmtResult { + self.fmt_local_impl(f) + } + + pub(super) fn fmt_local_impl(&self, f: &mut Formatter<'_>) -> FmtResult { + writeln!(f, "{}", self.kind)?; + writeln!(f, "Code: {}", style::error_code(self.code.to_string()))?; + if let Some(msg) = &self.message { + writeln!(f, "Message: {}", style::error_message(msg))?; + } + self.fmt_source_chain(f)?; + self.fmt_metadata(f)?; + self.fmt_diagnostics(f)?; + self.fmt_backtrace(f)?; + Ok(()) + } + + #[cfg(feature = "backtrace")] + fn fmt_backtrace(&self, f: &mut Formatter<'_>) -> FmtResult { + if let Some(bt) = self.backtrace_short() { + writeln!(f)?; + writeln!(f, "{}:", style::backtrace_label("Backtrace"))?; + + #[cfg(feature = "std")] + let cwd = std::env::current_dir().ok(); + #[cfg(not(feature = "std"))] + let cwd: Option = None; + + for line in bt.lines() { + // Parse "→ function at file:line" format + if let Some(rest) = line.strip_prefix("→ ") + && let Some((func, loc)) = rest.split_once(" at ") + { + // Parse file:line from location + let (file, line_num) = if let Some((f, l)) = loc.rsplit_once(':') { + (f, l.parse::().ok()) + } else { + (loc, None) + }; + + // Resolve to absolute path + #[cfg(feature = "std")] + let location_styled = if let Some(ref cwd) = cwd { + let abs_path = cwd.join(file); + let abs_str = abs_path.to_string_lossy(); + style::backtrace_link(loc, &abs_str, line_num) + } else { + style::backtrace_location(loc) + }; + #[cfg(not(feature = "std"))] + let location_styled = style::backtrace_location(loc); + + writeln!( + f, + " {} {} {} {}", + style::backtrace_arrow("→"), + style::backtrace_function(func), + style::backtrace_label("at"), + location_styled + )?; + continue; + } + writeln!(f, " {}", line)?; + } + } + Ok(()) + } + + #[cfg(not(feature = "backtrace"))] + fn fmt_backtrace(&self, _f: &mut Formatter<'_>) -> FmtResult { + Ok(()) + } + + fn fmt_source_chain(&self, f: &mut Formatter<'_>) -> FmtResult { + if let Some(source) = &self.source { + writeln!(f)?; + let mut current: &dyn CoreError = source.as_ref(); + let mut depth = 0; + while depth < 10 { + writeln!( + f, + " {}: {}", + style::source_context("Caused by"), + style::source_context(current.to_string()) + )?; + if let Some(next) = current.source() { + current = next; + depth += 1; + } else { + break; + } + } + } + Ok(()) + } + + fn fmt_metadata(&self, f: &mut Formatter<'_>) -> FmtResult { + if !self.metadata.is_empty() { + writeln!(f)?; + writeln!(f, "Context:")?; + for (key, value) in self.metadata.iter() { + writeln!(f, " {}: {}", style::metadata_key(key), value)?; + } + } + Ok(()) + } + + fn fmt_diagnostics(&self, f: &mut Formatter<'_>) -> FmtResult { + use crate::app_error::diagnostics::DiagnosticVisibility; + + if let Some(diag) = &self.diagnostics { + let min_visibility = DiagnosticVisibility::DevOnly; + + // Hints + let hints: alloc::vec::Vec<_> = diag.visible_hints(min_visibility).collect(); + if !hints.is_empty() { + writeln!(f)?; + for hint in hints { + writeln!( + f, + " {}: {}", + style::hint_label("hint"), + style::hint_text(&hint.message) + )?; + } + } + + // Suggestions + for suggestion in diag.visible_suggestions(min_visibility) { + writeln!(f)?; + write!( + f, + " {}: {}", + style::suggestion_label("suggestion"), + style::suggestion_text(&suggestion.message) + )?; + if let Some(cmd) = &suggestion.command { + writeln!(f)?; + writeln!(f, " {}", style::command(cmd))?; + } else { + writeln!(f)?; + } + } + + // Documentation link + if let Some(doc) = diag.visible_doc_link(min_visibility) { + writeln!(f)?; + if let Some(title) = &doc.title { + writeln!( + f, + " {}: {} ({})", + style::docs_label("docs"), + title, + style::url(&doc.url) + )?; + } else { + writeln!( + f, + " {}: {}", + style::docs_label("docs"), + style::url(&doc.url) + )?; + } + } + + // Related codes + if !diag.related_codes.is_empty() { + writeln!(f)?; + write!(f, " {}: ", style::related_label("see also"))?; + for (i, code) in diag.related_codes.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", style::error_code(code))?; + } + writeln!(f)?; + } + } + Ok(()) + } +} diff --git a/src/app_error/core/display/mode.rs b/src/app_error/core/display/mode.rs new file mode 100644 index 0000000..dd88b49 --- /dev/null +++ b/src/app_error/core/display/mode.rs @@ -0,0 +1,145 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Display mode detection and configuration. + +use core::sync::atomic::{AtomicU8, Ordering}; + +/// Display mode for error output. +/// +/// Controls the structure and verbosity of error messages based on +/// the deployment environment. The mode is determined by the +/// `MASTERROR_ENV` environment variable or auto-detected based on +/// build configuration and runtime environment. +/// +/// # Examples +/// +/// ``` +/// use masterror::DisplayMode; +/// +/// let mode = DisplayMode::current(); +/// match mode { +/// DisplayMode::Prod => println!("Production mode: JSON output"), +/// DisplayMode::Local => println!("Local mode: Human-readable output"), +/// DisplayMode::Staging => println!("Staging mode: JSON with context") +/// } +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DisplayMode { + /// Production mode: lightweight JSON, minimal fields, no sensitive data. + /// + /// Output includes only: `kind`, `code`, `message` (if not redacted). + /// Metadata is filtered to exclude sensitive fields. + /// Source chain and backtrace are excluded. + /// + /// # Example Output + /// + /// ```json + /// {"kind":"NotFound","code":"NOT_FOUND","message":"User not found"} + /// ``` + Prod = 0, + + /// Development mode: human-readable, full context. + /// + /// Output includes: error details, full source chain, complete metadata, + /// and backtrace (if enabled). Supports colored output when the `colored` + /// feature is enabled and output is a TTY. + /// + /// # Example Output + /// + /// ```text + /// Error: NotFound + /// Code: NOT_FOUND + /// Message: User not found + /// + /// Caused by: database query failed + /// Caused by: connection timeout + /// + /// Context: + /// user_id: 12345 + /// ``` + Local = 1, + + /// Staging mode: JSON with additional context. + /// + /// Output includes: `kind`, `code`, `message`, limited `source_chain`, + /// and filtered metadata. No backtrace. + /// + /// # Example Output + /// + /// ```json + /// {"kind":"NotFound","code":"NOT_FOUND","message":"User not found","source_chain":["database error"],"metadata":{"user_id":12345}} + /// ``` + Staging = 2 +} + +impl DisplayMode { + /// Returns the current display mode based on environment configuration. + /// + /// The mode is determined by checking (in order): + /// 1. `MASTERROR_ENV` environment variable (`prod`, `local`, or `staging`) + /// 2. Kubernetes environment detection (`KUBERNETES_SERVICE_HOST`) + /// 3. Build configuration (`cfg!(debug_assertions)`) + /// + /// The result is cached for performance. + /// + /// # Examples + /// + /// ``` + /// use masterror::DisplayMode; + /// + /// let mode = DisplayMode::current(); + /// assert!(matches!( + /// mode, + /// DisplayMode::Prod | DisplayMode::Local | DisplayMode::Staging + /// )); + /// ``` + #[must_use] + pub fn current() -> Self { + static CACHED_MODE: AtomicU8 = AtomicU8::new(255); + let cached = CACHED_MODE.load(Ordering::Relaxed); + if cached != 255 { + return match cached { + 0 => Self::Prod, + 1 => Self::Local, + 2 => Self::Staging, + _ => unreachable!() + }; + } + let mode = Self::detect(); + CACHED_MODE.store(mode as u8, Ordering::Relaxed); + mode + } + + /// Detects the appropriate display mode from environment. + /// + /// This is an internal helper called by [`current()`](Self::current). + pub(crate) fn detect() -> Self { + #[cfg(feature = "std")] + { + use std::env::var; + if let Ok(env) = var("MASTERROR_ENV") { + return match env.as_str() { + "prod" | "production" => Self::Prod, + "local" | "dev" | "development" => Self::Local, + "staging" | "stage" => Self::Staging, + _ => Self::detect_auto() + }; + } + if var("KUBERNETES_SERVICE_HOST").is_ok() { + return Self::Prod; + } + } + Self::detect_auto() + } + + /// Auto-detects mode based on build configuration. + pub(crate) fn detect_auto() -> Self { + if cfg!(debug_assertions) { + Self::Local + } else { + Self::Prod + } + } +} diff --git a/src/app_error/core/display/prod.rs b/src/app_error/core/display/prod.rs new file mode 100644 index 0000000..c017282 --- /dev/null +++ b/src/app_error/core/display/prod.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Production mode formatting (compact JSON). + +use core::fmt::{Formatter, Result as FmtResult}; + +use super::helpers::{write_json_header, write_metadata_json}; +use crate::app_error::core::error::Error; + +#[allow(dead_code)] +impl Error { + /// Formats error in production mode (compact JSON). + /// + /// # Arguments + /// + /// * `f` - Formatter to write output to + /// + /// # Examples + /// + /// ``` + /// use masterror::AppError; + /// + /// let error = AppError::not_found("User not found"); + /// let output = format!("{}", error); + /// // In prod mode: {"kind":"NotFound","code":"NOT_FOUND","message":"User not found"} + /// ``` + #[cfg(not(test))] + pub(crate) fn fmt_prod(&self, f: &mut Formatter<'_>) -> FmtResult { + self.fmt_prod_impl(f) + } + + #[cfg(test)] + #[allow(missing_docs)] + pub fn fmt_prod(&self, f: &mut Formatter<'_>) -> FmtResult { + self.fmt_prod_impl(f) + } + + pub(super) fn fmt_prod_impl(&self, f: &mut Formatter<'_>) -> FmtResult { + write_json_header( + f, + &self.kind, + &self.code, + self.message.as_deref(), + self.edit_policy + )?; + write_metadata_json(f, &self.metadata)?; + write!(f, "}}") + } +} diff --git a/src/app_error/core/display/staging.rs b/src/app_error/core/display/staging.rs new file mode 100644 index 0000000..b51575b --- /dev/null +++ b/src/app_error/core/display/staging.rs @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Staging mode formatting (JSON with context). + +use alloc::string::ToString; +use core::{ + error::Error as CoreError, + fmt::{Formatter, Result as FmtResult} +}; + +use super::helpers::{write_json_escaped, write_json_header, write_metadata_json}; +use crate::app_error::core::error::Error; + +#[allow(dead_code)] +impl Error { + /// Formats error in staging mode (JSON with context). + /// + /// # Arguments + /// + /// * `f` - Formatter to write output to + /// + /// # Examples + /// + /// ``` + /// use masterror::AppError; + /// + /// let error = AppError::service("Service unavailable"); + /// let output = format!("{}", error); + /// // In staging mode: JSON with source_chain and metadata + /// ``` + #[cfg(not(test))] + pub(crate) fn fmt_staging(&self, f: &mut Formatter<'_>) -> FmtResult { + self.fmt_staging_impl(f) + } + + #[cfg(test)] + #[allow(missing_docs)] + pub fn fmt_staging(&self, f: &mut Formatter<'_>) -> FmtResult { + self.fmt_staging_impl(f) + } + + pub(super) fn fmt_staging_impl(&self, f: &mut Formatter<'_>) -> FmtResult { + write_json_header( + f, + &self.kind, + &self.code, + self.message.as_deref(), + self.edit_policy + )?; + self.fmt_staging_source_chain(f)?; + write_metadata_json(f, &self.metadata)?; + write!(f, "}}") + } + + fn fmt_staging_source_chain(&self, f: &mut Formatter<'_>) -> FmtResult { + if let Some(source) = &self.source { + write!(f, r#","source_chain":["#)?; + let mut current: &dyn CoreError = source.as_ref(); + let mut depth = 0; + let mut first = true; + while depth < 5 { + if !first { + write!(f, ",")?; + } + first = false; + write!(f, "\"")?; + write_json_escaped(f, ¤t.to_string())?; + write!(f, "\"")?; + if let Some(next) = current.source() { + current = next; + depth += 1; + } else { + break; + } + } + write!(f, "]")?; + } + Ok(()) + } +} diff --git a/src/app_error/core/display/tests.rs b/src/app_error/core/display/tests.rs new file mode 100644 index 0000000..446c5b4 --- /dev/null +++ b/src/app_error/core/display/tests.rs @@ -0,0 +1,449 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Tests for display module. + +use core::fmt::{Formatter, Result as FmtResult}; + +use super::DisplayMode; +use crate::{AppError, field}; + +// ───────────────────────────────────────────────────────────────────────────── +// DisplayMode tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn display_mode_current_returns_valid_mode() { + let mode = DisplayMode::current(); + assert!(matches!( + mode, + DisplayMode::Prod | DisplayMode::Local | DisplayMode::Staging + )); +} + +#[test] +fn display_mode_detect_auto_returns_local_in_debug() { + if cfg!(debug_assertions) { + assert_eq!(DisplayMode::detect_auto(), DisplayMode::Local); + } else { + assert_eq!(DisplayMode::detect_auto(), DisplayMode::Prod); + } +} + +#[test] +fn display_mode_current_caches_result() { + let first = DisplayMode::current(); + let second = DisplayMode::current(); + assert_eq!(first, second); +} + +#[test] +fn display_mode_detect_auto_returns_prod_in_release() { + if !cfg!(debug_assertions) { + assert_eq!(DisplayMode::detect_auto(), DisplayMode::Prod); + } +} + +// Note: Environment-based mode detection tests (MASTERROR_ENV, +// KUBERNETES_SERVICE_HOST) cannot be tested without unsafe env var manipulation +// which is forbidden by #![deny(unsafe_code)]. These code paths are tested via +// integration tests and manual verification. + +// ───────────────────────────────────────────────────────────────────────────── +// Production format tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn fmt_prod_outputs_json() { + let error = AppError::not_found("User not found"); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""kind":"NotFound""#)); + assert!(output.contains(r#""code":"NOT_FOUND""#)); + assert!(output.contains(r#""message":"User not found""#)); +} + +#[test] +fn fmt_prod_excludes_redacted_message() { + let error = AppError::internal("secret").redactable(); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(!output.contains("secret")); +} + +#[test] +fn fmt_prod_includes_metadata() { + let error = AppError::not_found("User not found").with_field(field::u64("user_id", 12345)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""metadata""#)); + assert!(output.contains(r#""user_id":12345"#)); +} + +#[test] +fn fmt_prod_excludes_sensitive_metadata() { + let error = AppError::internal("Error").with_field(field::str("password", "secret")); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(!output.contains("secret")); +} + +#[test] +fn fmt_prod_escapes_special_chars() { + let error = AppError::internal("Line\nwith\"quotes\""); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#"\n"#)); + assert!(output.contains(r#"\""#)); +} + +#[test] +fn fmt_prod_handles_infinity_in_metadata() { + let error = AppError::internal("Error").with_field(field::f64("ratio", f64::INFINITY)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains("null")); +} + +#[test] +fn fmt_prod_formats_duration_metadata() { + use core::time::Duration; + let error = AppError::internal("Error") + .with_field(field::duration("elapsed", Duration::from_millis(1500))); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""secs":1"#)); + assert!(output.contains(r#""nanos":500000000"#)); +} + +#[test] +fn fmt_prod_formats_bool_metadata() { + let error = AppError::internal("Error").with_field(field::bool("active", true)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""active":true"#)); +} + +#[cfg(feature = "std")] +#[test] +fn fmt_prod_formats_ip_metadata() { + use std::net::IpAddr; + let ip: IpAddr = "192.168.1.1".parse().unwrap(); + let error = AppError::internal("Error").with_field(field::ip("client_ip", ip)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""client_ip":"192.168.1.1""#)); +} + +#[test] +fn fmt_prod_formats_uuid_metadata() { + use uuid::Uuid; + let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); + let error = AppError::internal("Error").with_field(field::uuid("request_id", uuid)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""request_id":"550e8400-e29b-41d4-a716-446655440000""#)); +} + +#[cfg(feature = "serde_json")] +#[test] +fn fmt_prod_formats_json_metadata() { + let json = serde_json::json!({"nested": "value"}); + let error = AppError::internal("Error").with_field(field::json("data", json)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""data":"#)); +} + +#[test] +fn fmt_prod_without_message() { + let error = AppError::bare(crate::AppErrorKind::Internal); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""kind":"Internal""#)); + assert!(!output.contains(r#""message""#)); +} + +#[test] +fn fmt_prod_with_multiple_metadata_fields() { + let error = AppError::not_found("test") + .with_field(field::str("first", "value1")) + .with_field(field::u64("second", 42)) + .with_field(field::bool("third", true)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""first":"value1""#)); + assert!(output.contains(r#""second":42"#)); + assert!(output.contains(r#""third":true"#)); +} + +#[test] +fn fmt_prod_escapes_backslash() { + let error = AppError::internal("path\\to\\file"); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#"path\\to\\file"#)); +} + +#[test] +fn fmt_prod_with_i64_metadata() { + let error = AppError::internal("test").with_field(field::i64("count", -100)); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""count":-100"#)); +} + +#[test] +fn fmt_prod_with_string_metadata() { + let error = AppError::internal("test").with_field(field::str("name", "value")); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#""name":"value""#)); +} + +#[test] +fn fmt_prod_escapes_control_chars() { + let error = AppError::internal("test\x00\x1F"); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#"\u0000"#)); + assert!(output.contains(r#"\u001f"#)); +} + +#[test] +fn fmt_prod_escapes_tab_and_carriage_return() { + let error = AppError::internal("line\ttab\rreturn"); + let output = format!("{}", error.fmt_prod_wrapper()); + assert!(output.contains(r#"\t"#)); + assert!(output.contains(r#"\r"#)); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Local format tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn fmt_local_outputs_human_readable() { + let error = AppError::not_found("User not found"); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("Not found")); + assert!(output.contains("Code: NOT_FOUND") || output.contains("Code:")); + assert!(output.contains("Message: User not found") || output.contains("Message:")); +} + +#[cfg(feature = "std")] +#[test] +fn fmt_local_includes_source_chain() { + use std::io::Error as IoError; + let io_err = IoError::other("connection failed"); + let error = AppError::internal("Database error").with_source(io_err); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("Caused by")); + assert!(output.contains("connection failed")); +} + +#[test] +fn fmt_local_without_message() { + let error = AppError::bare(crate::AppErrorKind::BadRequest); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("Bad request")); + assert!(!output.contains("Message:")); +} + +#[test] +fn fmt_local_with_metadata() { + let error = AppError::internal("Error") + .with_field(field::str("key", "value")) + .with_field(field::i64("count", -42)); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("Context:")); + assert!(output.contains("key")); + assert!(output.contains("value") || output.contains("-42")); +} + +#[cfg(feature = "colored")] +#[test] +fn fmt_local_with_deep_source_chain() { + use std::io::{Error as IoError, ErrorKind}; + let io1 = IoError::new(ErrorKind::NotFound, "level 1"); + let io2 = IoError::other(io1); + let error = AppError::internal("top").with_source(io2); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("Caused by")); + assert!(output.contains("level 1")); +} + +#[test] +fn fmt_local_with_hints() { + let error = AppError::not_found("Resource missing") + .with_hint("Check the resource ID") + .with_hint("Verify permissions"); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("hint")); + assert!(output.contains("Check the resource ID")); +} + +#[test] +fn fmt_local_with_suggestions() { + let error = AppError::service("Service unavailable") + .with_suggestion("Retry the request") + .with_suggestion_cmd("Check service status", "systemctl status myservice"); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("suggestion")); + assert!(output.contains("Retry the request")); + assert!(output.contains("systemctl status myservice")); +} + +#[test] +fn fmt_local_with_doc_link() { + let error = AppError::unauthorized("Authentication required") + .with_docs("https://docs.example.com/auth"); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("docs")); + assert!(output.contains("https://docs.example.com/auth")); +} + +#[test] +fn fmt_local_with_doc_link_titled() { + let error = AppError::forbidden("Access denied") + .with_docs_titled("https://docs.example.com/rbac", "RBAC Guide"); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("docs")); + assert!(output.contains("RBAC Guide")); +} + +#[test] +fn fmt_local_with_related_codes() { + let error = AppError::database_with_message("Connection failed") + .with_related_code("DB_POOL_EXHAUSTED") + .with_related_code("DB_TIMEOUT"); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("see also")); + assert!(output.contains("DB_POOL_EXHAUSTED")); +} + +#[test] +fn fmt_local_with_all_diagnostics() { + let error = AppError::internal("Critical failure") + .with_hint("Check logs for details") + .with_suggestion_cmd("View logs", "journalctl -u myapp") + .with_docs_titled("https://docs.example.com/troubleshoot", "Troubleshooting") + .with_related_code("ERR_STARTUP_FAILED"); + let output = format!("{}", error.fmt_local_wrapper()); + assert!(output.contains("hint")); + assert!(output.contains("suggestion")); + assert!(output.contains("docs")); + assert!(output.contains("see also")); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Staging format tests +// ───────────────────────────────────────────────────────────────────────────── + +#[test] +fn fmt_staging_outputs_json_with_context() { + let error = AppError::service("Service unavailable"); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(output.contains(r#""kind":"Service""#)); + assert!(output.contains(r#""code":"SERVICE""#)); +} + +#[cfg(feature = "std")] +#[test] +fn fmt_staging_includes_source_chain() { + use std::io::Error as IoError; + let io_err = IoError::other("timeout"); + let error = AppError::network("Network error").with_source(io_err); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(output.contains(r#""source_chain""#)); + assert!(output.contains("timeout")); +} + +#[test] +fn fmt_staging_without_message() { + let error = AppError::bare(crate::AppErrorKind::Timeout); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(output.contains(r#""kind":"Timeout""#)); + assert!(!output.contains(r#""message""#)); +} + +#[test] +fn fmt_staging_with_metadata() { + let error = AppError::service("Service error").with_field(field::u64("retry_count", 3)); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(output.contains(r#""metadata""#)); + assert!(output.contains(r#""retry_count":3"#)); +} + +#[test] +fn fmt_staging_with_redacted_message() { + let error = AppError::internal("sensitive data").redactable(); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(!output.contains("sensitive data")); +} + +#[test] +fn fmt_staging_with_multiple_metadata_fields() { + let error = AppError::service("error") + .with_field(field::str("key1", "value1")) + .with_field(field::u64("key2", 123)) + .with_field(field::bool("key3", false)); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(output.contains(r#""key1":"value1""#)); + assert!(output.contains(r#""key2":123"#)); + assert!(output.contains(r#""key3":false"#)); +} + +#[cfg(feature = "std")] +#[test] +fn fmt_staging_with_deep_source_chain() { + use std::io::{Error as IoError, ErrorKind}; + let io1 = IoError::new(ErrorKind::NotFound, "inner error"); + let io2 = IoError::other(io1); + let error = AppError::service("outer").with_source(io2); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(output.contains(r#""source_chain""#)); + assert!(output.contains("inner error")); +} + +#[test] +fn fmt_staging_with_redacted_and_public_metadata() { + let error = AppError::internal("test") + .with_field(field::str("public", "visible")) + .with_field(field::str("password", "secret")); + let output = format!("{}", error.fmt_staging_wrapper()); + assert!(output.contains(r#""public":"visible""#)); + assert!(!output.contains("secret")); +} + +// ───────────────────────────────────────────────────────────────────────────── +// Helper wrapper for testing +// ───────────────────────────────────────────────────────────────────────────── + +use crate::app_error::core::error::Error; + +impl Error { + fn fmt_wrapper(&self, mode: FormatterMode) -> FormatterWrapper<'_> { + FormatterWrapper { + error: self, + mode + } + } + + fn fmt_prod_wrapper(&self) -> FormatterWrapper<'_> { + self.fmt_wrapper(FormatterMode::Prod) + } + + fn fmt_local_wrapper(&self) -> FormatterWrapper<'_> { + self.fmt_wrapper(FormatterMode::Local) + } + + fn fmt_staging_wrapper(&self) -> FormatterWrapper<'_> { + self.fmt_wrapper(FormatterMode::Staging) + } +} + +enum FormatterMode { + Prod, + Local, + Staging +} + +struct FormatterWrapper<'a> { + error: &'a Error, + mode: FormatterMode +} + +impl core::fmt::Display for FormatterWrapper<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self.mode { + FormatterMode::Prod => self.error.fmt_prod(f), + FormatterMode::Local => self.error.fmt_local(f), + FormatterMode::Staging => self.error.fmt_staging(f) + } + } +} diff --git a/src/app_error/core/error.rs b/src/app_error/core/error.rs index 9bb9564..0697b92 100644 --- a/src/app_error/core/error.rs +++ b/src/app_error/core/error.rs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-FileCopyrightText: 2025-2026 RAprogramm // // SPDX-License-Identifier: MIT @@ -18,7 +18,10 @@ use serde_json::Value as JsonValue; #[cfg(not(feature = "backtrace"))] use super::types::CapturedBacktrace; use super::types::MessageEditPolicy; -use crate::{AppCode, AppErrorKind, RetryAdvice, app_error::metadata::Metadata}; +use crate::{ + AppCode, AppErrorKind, RetryAdvice, + app_error::{diagnostics::Diagnostics, metadata::Metadata} +}; /// Internal representation of error state. /// @@ -49,6 +52,10 @@ pub struct ErrorInner { #[cfg(not(feature = "serde_json"))] pub details: Option, pub source: Option>, + /// Diagnostic information (hints, suggestions, documentation). + /// + /// Stored as `Option>` for zero-cost when not used. + pub diagnostics: Option>, #[cfg(feature = "backtrace")] pub backtrace: Option>, #[cfg(feature = "backtrace")] @@ -93,42 +100,7 @@ impl DerefMut for Error { impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - #[cfg(not(feature = "colored"))] - { - Display::fmt(&self.kind, f) - } - #[cfg(feature = "colored")] - { - use crate::colored::style; - writeln!(f, "Error: {}", self.kind)?; - writeln!(f, "Code: {}", style::error_code(self.code.to_string()))?; - if let Some(msg) = &self.message { - writeln!(f, "Message: {}", style::error_message(msg))?; - } - if let Some(source) = &self.source { - writeln!(f)?; - let mut current: &dyn CoreError = source.as_ref(); - let mut depth = 0; - while depth < 10 { - write!(f, " {}: ", style::source_context("Caused by"))?; - writeln!(f, "{}", style::source_context(current.to_string()))?; - if let Some(next) = current.source() { - current = next; - depth += 1; - } else { - break; - } - } - } - if !self.metadata.is_empty() { - writeln!(f)?; - writeln!(f, "Context:")?; - for (key, value) in self.metadata.iter() { - writeln!(f, " {}: {}", style::metadata_key(key), value)?; - } - } - Ok(()) - } + self.fmt_local(f) } } @@ -194,8 +166,9 @@ impl Error { www_authenticate: None, details: None, source: None, + diagnostics: None, #[cfg(feature = "backtrace")] - backtrace: None, + backtrace: super::backtrace::capture_backtrace_snapshot(), #[cfg(feature = "backtrace")] captured_backtrace: OnceLock::new(), telemetry_dirty: AtomicBool::new(true), diff --git a/src/app_error/core/introspection.rs b/src/app_error/core/introspection.rs index f27c6d8..ed67583 100644 --- a/src/app_error/core/introspection.rs +++ b/src/app_error/core/introspection.rs @@ -70,6 +70,124 @@ impl Error { .map(Arc::clone) } + /// Returns a filtered, human-readable backtrace string. + /// + /// Filters out internal masterror frames and standard library runtime + /// frames, showing only application code. + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "backtrace")] + /// # { + /// use masterror::AppError; + /// + /// let err = AppError::internal("test"); + /// if let Some(bt) = err.backtrace_short() { + /// println!("{}", bt); + /// } + /// # } + /// ``` + #[cfg(feature = "backtrace")] + #[must_use] + pub fn backtrace_short(&self) -> Option { + use alloc::{string::String, vec::Vec}; + + let bt = self.backtrace()?; + let bt_str = alloc::format!("{}", bt); + + let mut frames: Vec<(String, String)> = Vec::new(); + let mut current_fn: Option = None; + + for line in bt_str.lines() { + let trimmed = line.trim(); + if trimmed.is_empty() { + continue; + } + + // Skip internal frames + if Self::is_internal_frame(trimmed) { + current_fn = None; + continue; + } + + // Function line: " 4: crate::module::function" + if let Some(fn_name) = Self::parse_function_line(trimmed) { + current_fn = Some(fn_name); + } + // Location line: " at ./src/main.rs:16:13" + else if let Some(location) = Self::parse_location_line(trimmed) + && let Some(fn_name) = current_fn.take() + { + frames.push((fn_name, location)); + } + } + + if frames.is_empty() { + return None; + } + + let result: Vec = frames + .into_iter() + .map(|(func, loc)| alloc::format!("→ {} at {}", func, loc)) + .collect(); + + Some(result.join("\n")) + } + + #[cfg(feature = "backtrace")] + fn is_internal_frame(line: &str) -> bool { + line.contains("masterror::") + || line.contains("/masterror/src/") + || line.contains("std::rt::") + || line.contains("std::panic") + || line.contains("core::ops::function") + || line.contains("core::panicking") + || line.contains("std::sys::backtrace") + || line.contains("std::backtrace") + || line.contains("__libc_") + || line.contains("_start") + || line.contains("") + || line.contains("/rustc/") + || line.contains("/rustlib/src/rust/library/") + || line.ends_with(": main") + || line == "main" + } + + #[cfg(feature = "backtrace")] + fn parse_function_line(line: &str) -> Option { + // Format: " 4: crate::module::function" or " 4: function" + let colon_pos = line.find(':')?; + let prefix = &line[..colon_pos]; + if !prefix.trim().chars().all(|c| c.is_ascii_digit()) { + return None; + } + let fn_full = line[colon_pos + 1..].trim(); + if fn_full.is_empty() { + return None; + } + // Extract just the function name (last segment after ::) + let fn_name = fn_full.rsplit("::").next().unwrap_or(fn_full); + Some(fn_name.into()) + } + + #[cfg(feature = "backtrace")] + fn parse_location_line(line: &str) -> Option { + // Format: " at ./src/main.rs:16:13" + let at_pos = line.find("at ")?; + let location = line[at_pos + 3..].trim(); + // Simplify path: remove ./ prefix + let location = location.strip_prefix("./").unwrap_or(location); + // Remove column number (keep only file:line) + if let Some((file_line, _col)) = location.rsplit_once(':') + && file_line.rsplit_once(':').is_some() + { + // file:line format + return Some(file_line.into()); + } + Some(location.into()) + } + /// Borrow the source if present. /// /// # Examples diff --git a/src/app_error/diagnostics.rs b/src/app_error/diagnostics.rs new file mode 100644 index 0000000..69a31d1 --- /dev/null +++ b/src/app_error/diagnostics.rs @@ -0,0 +1,509 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Diagnostic information for enhanced error reporting. +//! +//! This module provides rich diagnostic capabilities for errors, inspired by +//! compiler diagnostics (rustc, miette) but designed for runtime application +//! errors. +//! +//! # Features +//! +//! - **Hints**: Contextual advice explaining why an error occurred +//! - **Suggestions**: Actionable fixes with optional commands/code snippets +//! - **Documentation links**: URLs to detailed explanations +//! - **Related codes**: Cross-references to related error codes +//! - **Visibility control**: Per-item visibility for dev/staging/prod +//! environments +//! +//! # Example +//! +//! ```rust +//! use masterror::{AppError, DiagnosticVisibility}; +//! +//! let err = AppError::not_found("User not found") +//! .with_hint("Check if the user ID is correct") +//! .with_hint("User might have been deleted") +//! .with_suggestion_cmd("List all users to verify", "curl -X GET /api/users") +//! .with_docs("https://docs.example.com/errors/USER_NOT_FOUND"); +//! ``` +//! +//! # Display Modes +//! +//! Diagnostics are filtered based on [`DisplayMode`](crate::DisplayMode): +//! +//! | Visibility | Local | Staging | Prod | +//! |------------|-------|---------|------| +//! | `DevOnly` | ✅ | ❌ | ❌ | +//! | `Internal` | ✅ | ✅ | ❌ | +//! | `Public` | ✅ | ✅ | ✅ | + +use alloc::borrow::Cow; + +use super::inline_vec::InlineVec; + +/// Visibility of diagnostic information across environments. +/// +/// Controls where hints, suggestions, and other diagnostic information +/// are displayed based on the deployment environment. +/// +/// # Ordering +/// +/// Variants are ordered from most restrictive to least restrictive: +/// `DevOnly < Internal < Public`. This enables filtering with simple +/// comparisons. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[repr(u8)] +pub enum DiagnosticVisibility { + /// Shown only in Local mode (development). + /// + /// Use for internal debugging hints that may expose implementation + /// details or sensitive information. + #[default] + DevOnly = 0, + + /// Shown in Local and Staging environments. + /// + /// Use for hints that help with testing and debugging but should + /// not reach production users. + Internal = 1, + + /// Shown everywhere including Production. + /// + /// Use for user-facing hints and documentation links that help + /// end users understand and resolve errors. + Public = 2 +} + +/// A single hint providing context about an error. +/// +/// Hints explain why an error might have occurred without necessarily +/// providing a fix. They help developers and users understand the +/// error context. +/// +/// # Example +/// +/// ```rust +/// use masterror::diagnostics::{DiagnosticVisibility, Hint}; +/// +/// let hint = Hint { +/// message: "Database connection pool may be exhausted".into(), +/// visibility: DiagnosticVisibility::Internal +/// }; +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Hint { + /// The hint message. + pub message: Cow<'static, str>, + + /// Where this hint should be displayed. + pub visibility: DiagnosticVisibility +} + +impl Hint { + /// Creates a new hint with default (DevOnly) visibility. + #[must_use] + pub fn new(message: impl Into>) -> Self { + Self { + message: message.into(), + visibility: DiagnosticVisibility::DevOnly + } + } + + /// Creates a new hint with specified visibility. + #[must_use] + pub fn with_visibility( + message: impl Into>, + visibility: DiagnosticVisibility + ) -> Self { + Self { + message: message.into(), + visibility + } + } + + /// Creates a public hint visible in all environments. + #[must_use] + pub fn public(message: impl Into>) -> Self { + Self::with_visibility(message, DiagnosticVisibility::Public) + } + + /// Creates an internal hint visible in Local and Staging. + #[must_use] + pub fn internal(message: impl Into>) -> Self { + Self::with_visibility(message, DiagnosticVisibility::Internal) + } +} + +/// An actionable suggestion to fix an error. +/// +/// Suggestions provide concrete steps users can take to resolve an error, +/// optionally including a command or code snippet. +/// +/// # Example +/// +/// ```rust +/// use masterror::diagnostics::{DiagnosticVisibility, Suggestion}; +/// +/// let suggestion = Suggestion { +/// message: "Check if PostgreSQL is running".into(), +/// command: Some("systemctl status postgresql".into()), +/// visibility: DiagnosticVisibility::DevOnly +/// }; +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Suggestion { + /// Human-readable description of the suggestion. + pub message: Cow<'static, str>, + + /// Optional command or code snippet. + /// + /// When present, displayed in a distinct style (monospace, highlighted) + /// to indicate it can be copied and executed. + pub command: Option>, + + /// Where this suggestion should be displayed. + pub visibility: DiagnosticVisibility +} + +impl Suggestion { + /// Creates a new suggestion without a command. + #[must_use] + pub fn new(message: impl Into>) -> Self { + Self { + message: message.into(), + command: None, + visibility: DiagnosticVisibility::DevOnly + } + } + + /// Creates a new suggestion with a command. + #[must_use] + pub fn with_command( + message: impl Into>, + command: impl Into> + ) -> Self { + Self { + message: message.into(), + command: Some(command.into()), + visibility: DiagnosticVisibility::DevOnly + } + } + + /// Sets the visibility for this suggestion. + #[must_use] + pub fn visibility(mut self, visibility: DiagnosticVisibility) -> Self { + self.visibility = visibility; + self + } +} + +/// A link to documentation explaining the error. +/// +/// Documentation links provide detailed explanations and context that +/// don't fit in hint messages. They typically point to error catalogs, +/// API documentation, or troubleshooting guides. +/// +/// # Example +/// +/// ```rust +/// use masterror::diagnostics::{DiagnosticVisibility, DocLink}; +/// +/// let doc = DocLink { +/// url: "https://docs.example.com/errors/E001".into(), +/// title: Some("Connection Errors".into()), +/// visibility: DiagnosticVisibility::Public +/// }; +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DocLink { + /// URL to documentation. + pub url: Cow<'static, str>, + + /// Optional human-readable title for the link. + pub title: Option>, + + /// Where this link should be displayed. + /// + /// Documentation links are typically `Public` since they help + /// end users understand errors. + pub visibility: DiagnosticVisibility +} + +impl DocLink { + /// Creates a new documentation link with public visibility. + #[must_use] + pub fn new(url: impl Into>) -> Self { + Self { + url: url.into(), + title: None, + visibility: DiagnosticVisibility::Public + } + } + + /// Creates a new documentation link with a title. + #[must_use] + pub fn with_title( + url: impl Into>, + title: impl Into> + ) -> Self { + Self { + url: url.into(), + title: Some(title.into()), + visibility: DiagnosticVisibility::Public + } + } + + /// Sets the visibility for this link. + #[must_use] + pub fn visibility(mut self, visibility: DiagnosticVisibility) -> Self { + self.visibility = visibility; + self + } +} + +/// Complete diagnostic information for an error. +/// +/// This structure collects all diagnostic information associated with an +/// error. It is stored in `Option>` to ensure zero cost +/// when diagnostics are not used. +/// +/// # Memory Layout +/// +/// The structure uses `InlineVec` for hints and suggestions, which stores +/// up to 4 elements inline without heap allocation. This optimizes for the +/// common case of 1-2 hints/suggestions per error. +/// +/// # Example +/// +/// ```rust +/// use masterror::diagnostics::{Diagnostics, DocLink, Hint, Suggestion}; +/// +/// let mut diag = Diagnostics::new(); +/// diag.hints.push(Hint::new("Check configuration")); +/// diag.suggestions.push(Suggestion::with_command( +/// "Restart the service", +/// "systemctl restart myapp" +/// )); +/// diag.doc_link = Some(DocLink::new("https://docs.example.com/errors")); +/// ``` +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct Diagnostics { + /// Contextual hints explaining the error. + /// + /// Hints provide context without necessarily offering a solution. + /// Multiple hints can be attached to explain different aspects. + pub hints: InlineVec, + + /// Actionable suggestions to fix the error. + /// + /// Suggestions provide concrete steps to resolve the error. + /// Usually 0-2 suggestions are most helpful. + pub suggestions: InlineVec, + + /// Link to detailed documentation. + /// + /// Only one documentation link is supported per error to avoid + /// overwhelming users with choices. + pub doc_link: Option, + + /// Related error codes for cross-reference. + /// + /// Helps users discover related errors that might provide additional + /// context or alternative explanations. + pub related_codes: InlineVec> +} + +impl Diagnostics { + /// Creates an empty diagnostics container. + #[must_use] + pub const fn new() -> Self { + Self { + hints: InlineVec::new(), + suggestions: InlineVec::new(), + doc_link: None, + related_codes: InlineVec::new() + } + } + + /// Returns `true` if no diagnostic information is present. + #[must_use] + pub fn is_empty(&self) -> bool { + self.hints.is_empty() + && self.suggestions.is_empty() + && self.doc_link.is_none() + && self.related_codes.is_empty() + } + + /// Returns `true` if any diagnostic information has the given visibility + /// or higher. + #[must_use] + pub fn has_visible_content(&self, min_visibility: DiagnosticVisibility) -> bool { + self.hints.iter().any(|h| h.visibility >= min_visibility) + || self + .suggestions + .iter() + .any(|s| s.visibility >= min_visibility) + || self + .doc_link + .as_ref() + .is_some_and(|d| d.visibility >= min_visibility) + } + + /// Returns an iterator over hints visible at the given level. + pub fn visible_hints( + &self, + min_visibility: DiagnosticVisibility + ) -> impl Iterator { + self.hints + .iter() + .filter(move |h| h.visibility >= min_visibility) + } + + /// Returns an iterator over suggestions visible at the given level. + pub fn visible_suggestions( + &self, + min_visibility: DiagnosticVisibility + ) -> impl Iterator { + self.suggestions + .iter() + .filter(move |s| s.visibility >= min_visibility) + } + + /// Returns the documentation link if visible at the given level. + #[must_use] + pub fn visible_doc_link(&self, min_visibility: DiagnosticVisibility) -> Option<&DocLink> { + self.doc_link + .as_ref() + .filter(|d| d.visibility >= min_visibility) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn visibility_ordering() { + assert!(DiagnosticVisibility::DevOnly < DiagnosticVisibility::Internal); + assert!(DiagnosticVisibility::Internal < DiagnosticVisibility::Public); + } + + #[test] + fn hint_constructors() { + let hint = Hint::new("test"); + assert_eq!(hint.visibility, DiagnosticVisibility::DevOnly); + + let public = Hint::public("test"); + assert_eq!(public.visibility, DiagnosticVisibility::Public); + + let internal = Hint::internal("test"); + assert_eq!(internal.visibility, DiagnosticVisibility::Internal); + } + + #[test] + fn suggestion_constructors() { + let suggestion = Suggestion::new("do this"); + assert!(suggestion.command.is_none()); + + let with_cmd = Suggestion::with_command("do this", "some command"); + assert_eq!(with_cmd.command.as_deref(), Some("some command")); + } + + #[test] + fn doc_link_constructors() { + let link = DocLink::new("https://example.com"); + assert!(link.title.is_none()); + assert_eq!(link.visibility, DiagnosticVisibility::Public); + + let titled = DocLink::with_title("https://example.com", "Example"); + assert_eq!(titled.title.as_deref(), Some("Example")); + } + + #[test] + fn diagnostics_is_empty() { + let diag = Diagnostics::new(); + assert!(diag.is_empty()); + + let mut diag = Diagnostics::new(); + diag.hints.push(Hint::new("test")); + assert!(!diag.is_empty()); + } + + #[test] + fn diagnostics_visibility_filtering() { + let mut diag = Diagnostics::new(); + diag.hints.push(Hint::new("dev hint")); + diag.hints.push(Hint::internal("internal hint")); + diag.hints.push(Hint::public("public hint")); + + // DevOnly level sees all + let dev_hints: Vec<_> = diag.visible_hints(DiagnosticVisibility::DevOnly).collect(); + assert_eq!(dev_hints.len(), 3); + + // Internal level sees internal + public + let internal_hints: Vec<_> = diag.visible_hints(DiagnosticVisibility::Internal).collect(); + assert_eq!(internal_hints.len(), 2); + + // Public level sees only public + let public_hints: Vec<_> = diag.visible_hints(DiagnosticVisibility::Public).collect(); + assert_eq!(public_hints.len(), 1); + assert_eq!(public_hints[0].message, "public hint"); + } + + #[test] + fn diagnostics_has_visible_content() { + let mut diag = Diagnostics::new(); + assert!(!diag.has_visible_content(DiagnosticVisibility::DevOnly)); + + diag.hints.push(Hint::new("dev only")); + assert!(diag.has_visible_content(DiagnosticVisibility::DevOnly)); + assert!(!diag.has_visible_content(DiagnosticVisibility::Internal)); + assert!(!diag.has_visible_content(DiagnosticVisibility::Public)); + + diag.suggestions + .push(Suggestion::new("fix it").visibility(DiagnosticVisibility::Public)); + assert!(diag.has_visible_content(DiagnosticVisibility::Public)); + } + + #[test] + fn diagnostics_doc_link_visibility() { + let mut diag = Diagnostics::new(); + diag.doc_link = Some(DocLink::new("https://example.com")); + + assert!( + diag.visible_doc_link(DiagnosticVisibility::Public) + .is_some() + ); + assert!( + diag.visible_doc_link(DiagnosticVisibility::Internal) + .is_some() + ); + assert!( + diag.visible_doc_link(DiagnosticVisibility::DevOnly) + .is_some() + ); + + // Change to internal visibility + diag.doc_link = + Some(DocLink::new("https://example.com").visibility(DiagnosticVisibility::Internal)); + assert!( + diag.visible_doc_link(DiagnosticVisibility::Internal) + .is_some() + ); + assert!( + diag.visible_doc_link(DiagnosticVisibility::Public) + .is_none() + ); + } + + #[test] + fn cow_static_str() { + let hint = Hint::new("static string"); + assert!(matches!(hint.message, Cow::Borrowed(_))); + + let hint = Hint::new(alloc::string::String::from("owned string")); + assert!(matches!(hint.message, Cow::Owned(_))); + } +} diff --git a/src/app_error/inline_vec.rs b/src/app_error/inline_vec.rs index d24e6df..f02efb4 100644 --- a/src/app_error/inline_vec.rs +++ b/src/app_error/inline_vec.rs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-FileCopyrightText: 2025-2026 RAprogramm // // SPDX-License-Identifier: MIT @@ -37,12 +37,12 @@ const INLINE_CAPACITY: usize = 4; /// assert_eq!(vec.len(), 2); /// assert!(vec.is_inline()); // Still on stack /// ``` -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct InlineVec { storage: Storage } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] enum Storage { /// Inline storage for 0-4 elements using fixed arrays. /// @@ -286,8 +286,16 @@ impl IntoIterator for InlineVec { type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { + let vec: Vec = match self.storage { + Storage::Empty => Vec::new(), + Storage::One(a) => alloc::vec![a], + Storage::Two([a, b]) => alloc::vec![a, b], + Storage::Three([a, b, c]) => alloc::vec![a, b, c], + Storage::Four([a, b, c, d]) => alloc::vec![a, b, c, d], + Storage::Heap(vec) => vec + }; IntoIter { - storage: self.storage + inner: vec.into_iter() } } } @@ -330,38 +338,29 @@ impl ExactSizeIterator for Iter<'_, T> {} /// Owning iterator for [`InlineVec`]. #[derive(Debug)] pub struct IntoIter { - storage: Storage + inner: alloc::vec::IntoIter } impl Iterator for IntoIter { type Item = T; + #[inline] fn next(&mut self) -> Option { - match &mut self.storage { - Storage::Empty => None, - Storage::One(_) => match core::mem::take(&mut self.storage) { - Storage::One(a) => Some(a), - _ => unreachable!() - }, - Storage::Two(_) | Storage::Three(_) | Storage::Four(_) => { - // Convert to heap storage for easier iteration - let items: Vec = match core::mem::take(&mut self.storage) { - Storage::Two([a, b]) => alloc::vec![a, b], - Storage::Three([a, b, c]) => alloc::vec![a, b, c], - Storage::Four([a, b, c, d]) => alloc::vec![a, b, c, d], - _ => unreachable!() - }; - self.storage = Storage::Heap(items); - self.next() - } - Storage::Heap(vec) => { - if vec.is_empty() { - None - } else { - Some(vec.remove(0)) - } - } - } + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +impl ExactSizeIterator for IntoIter {} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.inner.next_back() } } @@ -533,4 +532,381 @@ mod tests { } assert_eq!(vec[0], 10); } + + #[test] + fn test_get_three_elements() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + assert_eq!(vec.get(0), Some(&1)); + assert_eq!(vec.get(1), Some(&2)); + assert_eq!(vec.get(2), Some(&3)); + assert_eq!(vec.get(3), None); + } + + #[test] + fn test_get_four_elements() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + vec.push(4); + assert_eq!(vec.get(0), Some(&1)); + assert_eq!(vec.get(3), Some(&4)); + assert_eq!(vec.get(4), None); + } + + #[test] + fn test_get_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=6 { + vec.push(i); + } + assert!(!vec.is_inline()); + assert_eq!(vec.get(0), Some(&1)); + assert_eq!(vec.get(5), Some(&6)); + assert_eq!(vec.get(6), None); + } + + #[test] + fn test_get_mut_three_elements() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + *vec.get_mut(2).unwrap() = 30; + assert_eq!(vec[2], 30); + assert!(vec.get_mut(3).is_none()); + } + + #[test] + fn test_get_mut_four_elements() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + vec.push(4); + *vec.get_mut(3).unwrap() = 40; + assert_eq!(vec[3], 40); + assert!(vec.get_mut(4).is_none()); + } + + #[test] + fn test_get_mut_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=6 { + vec.push(i); + } + *vec.get_mut(5).unwrap() = 60; + assert_eq!(vec[5], 60); + assert!(vec.get_mut(6).is_none()); + } + + #[test] + fn test_insert_empty() { + let mut vec: InlineVec = InlineVec::new(); + vec.insert(0, 42); + assert_eq!(&*vec, &[42]); + } + + #[test] + fn test_insert_three_all_positions() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(3); + vec.insert(1, 2); + assert_eq!(&*vec, &[1, 2, 3]); + + let mut vec2: InlineVec = InlineVec::new(); + vec2.push(2); + vec2.push(3); + vec2.insert(0, 1); + assert_eq!(&*vec2, &[1, 2, 3]); + + let mut vec3: InlineVec = InlineVec::new(); + vec3.push(1); + vec3.push(2); + vec3.insert(2, 3); + assert_eq!(&*vec3, &[1, 2, 3]); + } + + #[test] + fn test_insert_four_all_positions() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(2); + vec.push(3); + vec.push(4); + vec.insert(0, 1); + assert_eq!(&*vec, &[1, 2, 3, 4]); + + let mut vec2: InlineVec = InlineVec::new(); + vec2.push(1); + vec2.push(3); + vec2.push(4); + vec2.insert(1, 2); + assert_eq!(&*vec2, &[1, 2, 3, 4]); + + let mut vec3: InlineVec = InlineVec::new(); + vec3.push(1); + vec3.push(2); + vec3.push(4); + vec3.insert(2, 3); + assert_eq!(&*vec3, &[1, 2, 3, 4]); + + let mut vec4: InlineVec = InlineVec::new(); + vec4.push(1); + vec4.push(2); + vec4.push(3); + vec4.insert(3, 4); + assert_eq!(&*vec4, &[1, 2, 3, 4]); + } + + #[test] + fn test_insert_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=6 { + vec.push(i); + } + vec.insert(3, 99); + assert_eq!(vec[3], 99); + assert_eq!(vec.len(), 7); + } + + #[test] + fn test_into_iter_three() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + let collected: alloc::vec::Vec<_> = vec.into_iter().collect(); + assert_eq!(collected, alloc::vec![1, 2, 3]); + } + + #[test] + fn test_into_iter_four() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + vec.push(4); + let collected: alloc::vec::Vec<_> = vec.into_iter().collect(); + assert_eq!(collected, alloc::vec![1, 2, 3, 4]); + } + + #[test] + fn test_into_iter_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=6 { + vec.push(i); + } + let collected: alloc::vec::Vec<_> = vec.into_iter().collect(); + assert_eq!(collected, alloc::vec![1, 2, 3, 4, 5, 6]); + } + + #[test] + fn test_into_iter_empty_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=5 { + vec.push(i); + } + let mut iter = vec.into_iter(); + for _ in 0..5 { + iter.next(); + } + assert!(iter.next().is_none()); + } + + #[test] + fn test_binary_search_by_key() { + let mut vec: InlineVec<(i32, &str)> = InlineVec::new(); + vec.push((1, "a")); + vec.push((3, "c")); + vec.push((5, "e")); + assert_eq!(vec.binary_search_by_key(&3, |&(k, _)| k), Ok(1)); + assert_eq!(vec.binary_search_by_key(&2, |&(k, _)| k), Err(1)); + assert_eq!(vec.binary_search_by_key(&6, |&(k, _)| k), Err(3)); + } + + #[test] + fn test_iter_mut() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + for val in vec.iter_mut() { + *val *= 10; + } + assert_eq!(&*vec, &[10, 20, 30]); + } + + #[test] + fn test_iter_size_hint() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + vec.push(3); + let mut iter = vec.iter(); + assert_eq!(iter.size_hint(), (3, Some(3))); + iter.next(); + assert_eq!(iter.size_hint(), (2, Some(2))); + iter.next(); + iter.next(); + assert_eq!(iter.size_hint(), (0, Some(0))); + } + + #[test] + fn test_exact_size_iterator() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + let iter = vec.iter(); + assert_eq!(iter.len(), 2); + } + + #[test] + fn test_into_iter_for_ref() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + let collected: alloc::vec::Vec<_> = (&vec).into_iter().copied().collect(); + assert_eq!(collected, alloc::vec![1, 2]); + } + + #[test] + fn test_default() { + let vec: InlineVec = InlineVec::default(); + assert!(vec.is_empty()); + } + + #[test] + fn test_as_slice() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + let slice = vec.as_slice(); + assert_eq!(slice, &[1, 2]); + } + + #[test] + fn test_as_mut_slice() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + vec.push(2); + let slice = vec.as_mut_slice(); + slice[0] = 10; + assert_eq!(vec[0], 10); + } + + #[test] + fn test_push_to_heap_then_more() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=10 { + vec.push(i); + } + assert!(!vec.is_inline()); + assert_eq!(vec.len(), 10); + } + + #[test] + fn test_deref_empty() { + let vec: InlineVec = InlineVec::new(); + let slice: &[i32] = &vec; + assert!(slice.is_empty()); + } + + #[test] + fn test_deref_mut_empty() { + let mut vec: InlineVec = InlineVec::new(); + let slice: &mut [i32] = &mut vec; + assert!(slice.is_empty()); + } + + #[test] + fn test_deref_one() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(42); + let slice: &[i32] = &vec; + assert_eq!(slice, &[42]); + } + + #[test] + fn test_deref_mut_one() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(42); + let slice: &mut [i32] = &mut vec; + slice[0] = 99; + assert_eq!(vec[0], 99); + } + + #[test] + fn test_deref_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=6 { + vec.push(i); + } + let slice: &[i32] = &vec; + assert_eq!(slice, &[1, 2, 3, 4, 5, 6]); + } + + #[test] + fn test_deref_mut_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=6 { + vec.push(i); + } + let slice: &mut [i32] = &mut vec; + slice[5] = 60; + assert_eq!(vec[5], 60); + } + + #[test] + fn test_get_empty() { + let vec: InlineVec = InlineVec::new(); + assert!(vec.get(0).is_none()); + } + + #[test] + fn test_get_mut_empty() { + let mut vec: InlineVec = InlineVec::new(); + assert!(vec.get_mut(0).is_none()); + } + + #[test] + fn test_get_one_out_of_bounds() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + assert!(vec.get(1).is_none()); + } + + #[test] + fn test_get_mut_one_out_of_bounds() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(1); + assert!(vec.get_mut(1).is_none()); + } + + #[test] + fn test_len_heap() { + let mut vec: InlineVec = InlineVec::new(); + for i in 1..=10 { + vec.push(i); + } + assert_eq!(vec.len(), 10); + } + + #[test] + fn test_into_iter_one() { + let mut vec: InlineVec = InlineVec::new(); + vec.push(42); + let collected: alloc::vec::Vec<_> = vec.into_iter().collect(); + assert_eq!(collected, alloc::vec![42]); + } + + #[test] + fn test_into_iter_empty() { + let vec: InlineVec = InlineVec::new(); + let collected: alloc::vec::Vec<_> = vec.into_iter().collect(); + assert!(collected.is_empty()); + } } diff --git a/src/app_error/metadata.rs b/src/app_error/metadata.rs index 672fe7e..e5d1f0b 100644 --- a/src/app_error/metadata.rs +++ b/src/app_error/metadata.rs @@ -638,4 +638,149 @@ mod tests { let text = duration_to_string(Duration::from_micros(1500)); assert_eq!(text, "0.0015s"); } + + #[test] + fn duration_to_string_whole_seconds() { + let text = duration_to_string(Duration::from_secs(5)); + assert_eq!(text, "5s"); + } + + #[test] + fn duration_to_string_with_nanos() { + let text = duration_to_string(Duration::new(1, 500_000_000)); + assert_eq!(text, "1.5s"); + } + + #[test] + fn field_value_display_all_types() { + assert_eq!(FieldValue::Str(Cow::Borrowed("hello")).to_string(), "hello"); + assert_eq!(FieldValue::I64(-42).to_string(), "-42"); + assert_eq!(FieldValue::U64(100).to_string(), "100"); + assert_eq!(FieldValue::F64(1.5).to_string(), "1.5"); + assert_eq!(FieldValue::Bool(true).to_string(), "true"); + assert_eq!(FieldValue::Bool(false).to_string(), "false"); + + let uuid = Uuid::nil(); + assert_eq!( + FieldValue::Uuid(uuid).to_string(), + "00000000-0000-0000-0000-000000000000" + ); + + let dur = Duration::from_millis(1500); + assert_eq!(FieldValue::Duration(dur).to_string(), "1.5s"); + + let ip = IpAddr::from(Ipv4Addr::LOCALHOST); + assert_eq!(FieldValue::Ip(ip).to_string(), "127.0.0.1"); + } + + #[cfg(feature = "serde_json")] + #[test] + fn field_value_display_json() { + let value = FieldValue::Json(json!({"key": "value"})); + assert!(value.to_string().contains("key")); + } + + #[test] + fn metadata_extend() { + let mut meta = Metadata::new(); + meta.extend([field::str("a", "1"), field::str("b", "2")]); + assert_eq!(meta.len(), 2); + assert_eq!(meta.get("a"), Some(&FieldValue::Str(Cow::Borrowed("1")))); + assert_eq!(meta.get("b"), Some(&FieldValue::Str(Cow::Borrowed("2")))); + } + + #[test] + fn metadata_get_field() { + let meta = Metadata::from_fields([field::i64("count", 42)]); + let field = meta.get_field("count"); + assert!(field.is_some()); + let field = field.unwrap(); + assert_eq!(field.name(), "count"); + assert_eq!(field.value(), &FieldValue::I64(42)); + } + + #[test] + fn metadata_get_nonexistent() { + let meta = Metadata::new(); + assert!(meta.get("missing").is_none()); + assert!(meta.get_field("missing").is_none()); + assert!(meta.redaction("missing").is_none()); + } + + #[test] + fn metadata_set_redaction() { + let mut meta = Metadata::from_fields([field::str("secret", "value")]); + meta.set_redaction("secret", FieldRedaction::Redact); + assert_eq!(meta.redaction("secret"), Some(FieldRedaction::Redact)); + } + + #[test] + fn metadata_set_redaction_nonexistent() { + let mut meta = Metadata::new(); + meta.set_redaction("missing", FieldRedaction::Redact); + assert!(meta.redaction("missing").is_none()); + } + + #[test] + fn metadata_iter_with_redaction() { + let meta = Metadata::from_fields([ + field::str("public", "value1"), + field::str("password", "secret") + ]); + let items: Vec<_> = meta.iter_with_redaction().collect(); + assert_eq!(items.len(), 2); + let password_item = items.iter().find(|(n, _, _)| *n == "password").unwrap(); + assert_eq!(password_item.2, FieldRedaction::Redact); + } + + #[test] + fn metadata_into_iter() { + let meta = Metadata::from_fields([field::i64("a", 1), field::i64("b", 2)]); + let fields: Vec<_> = meta.into_iter().collect(); + assert_eq!(fields.len(), 2); + } + + #[test] + fn field_default_redaction_non_sensitive() { + let field = field::str("user_id", "abc123"); + assert_eq!(field.redaction(), FieldRedaction::None); + } + + #[test] + fn field_with_redaction() { + let field = field::str("public", "value").with_redaction(FieldRedaction::Hash); + assert_eq!(field.redaction(), FieldRedaction::Hash); + } + + #[test] + fn field_redaction_default() { + assert_eq!(FieldRedaction::default(), FieldRedaction::None); + } + + #[test] + fn field_value_partial_eq() { + let v1 = FieldValue::I64(42); + let v2 = FieldValue::I64(42); + let v3 = FieldValue::I64(43); + assert_eq!(v1, v2); + assert_ne!(v1, v3); + } + + #[test] + fn metadata_len_and_is_empty() { + let empty = Metadata::new(); + assert!(empty.is_empty()); + assert_eq!(empty.len(), 0); + + let meta = Metadata::from_fields([field::i64("x", 1)]); + assert!(!meta.is_empty()); + assert_eq!(meta.len(), 1); + } + + #[test] + fn field_into_value() { + let field = field::u64("count", 100); + let value = field.into_value(); + assert_eq!(value, FieldValue::U64(100)); + } } diff --git a/src/code/app_code.rs b/src/code/app_code.rs index d46b585..bcce29f 100644 --- a/src/code/app_code.rs +++ b/src/code/app_code.rs @@ -447,4 +447,216 @@ mod tests { let err = AppCode::from_str("NOT-A-REAL-CODE").unwrap_err(); assert_eq!(err, ParseAppCodeError); } + + #[test] + fn from_str_parses_all_static_codes() { + let codes = [ + ("NOT_FOUND", AppCode::NotFound), + ("VALIDATION", AppCode::Validation), + ("CONFLICT", AppCode::Conflict), + ("USER_ALREADY_EXISTS", AppCode::UserAlreadyExists), + ("UNAUTHORIZED", AppCode::Unauthorized), + ("FORBIDDEN", AppCode::Forbidden), + ("NOT_IMPLEMENTED", AppCode::NotImplemented), + ("BAD_REQUEST", AppCode::BadRequest), + ("RATE_LIMITED", AppCode::RateLimited), + ("TELEGRAM_AUTH", AppCode::TelegramAuth), + ("INVALID_JWT", AppCode::InvalidJwt), + ("INTERNAL", AppCode::Internal), + ("DATABASE", AppCode::Database), + ("SERVICE", AppCode::Service), + ("CONFIG", AppCode::Config), + ("TURNKEY", AppCode::Turnkey), + ("TIMEOUT", AppCode::Timeout), + ("NETWORK", AppCode::Network), + ("DEPENDENCY_UNAVAILABLE", AppCode::DependencyUnavailable), + ("SERIALIZATION", AppCode::Serialization), + ("DESERIALIZATION", AppCode::Deserialization), + ("EXTERNAL_API", AppCode::ExternalApi), + ("QUEUE", AppCode::Queue), + ("CACHE", AppCode::Cache) + ]; + for (s, expected) in codes { + let parsed = AppCode::from_str(s).expect(s); + assert_eq!(parsed, expected, "mismatch for {s}"); + } + } + + #[test] + fn from_kind_covers_all_variants() { + let mappings = [ + (AppErrorKind::NotFound, AppCode::NotFound), + (AppErrorKind::Validation, AppCode::Validation), + (AppErrorKind::Conflict, AppCode::Conflict), + (AppErrorKind::Unauthorized, AppCode::Unauthorized), + (AppErrorKind::Forbidden, AppCode::Forbidden), + (AppErrorKind::NotImplemented, AppCode::NotImplemented), + (AppErrorKind::BadRequest, AppCode::BadRequest), + (AppErrorKind::RateLimited, AppCode::RateLimited), + (AppErrorKind::TelegramAuth, AppCode::TelegramAuth), + (AppErrorKind::InvalidJwt, AppCode::InvalidJwt), + (AppErrorKind::Internal, AppCode::Internal), + (AppErrorKind::Database, AppCode::Database), + (AppErrorKind::Service, AppCode::Service), + (AppErrorKind::Config, AppCode::Config), + (AppErrorKind::Turnkey, AppCode::Turnkey), + (AppErrorKind::Timeout, AppCode::Timeout), + (AppErrorKind::Network, AppCode::Network), + ( + AppErrorKind::DependencyUnavailable, + AppCode::DependencyUnavailable + ), + (AppErrorKind::Serialization, AppCode::Serialization), + (AppErrorKind::Deserialization, AppCode::Deserialization), + (AppErrorKind::ExternalApi, AppCode::ExternalApi), + (AppErrorKind::Queue, AppCode::Queue), + (AppErrorKind::Cache, AppCode::Cache) + ]; + for (kind, expected) in mappings { + assert_eq!(AppCode::from(kind), expected, "mismatch for {kind:?}"); + } + } + + #[test] + fn is_valid_literal_rejects_empty() { + assert!(AppCode::try_new(String::new()).is_err()); + } + + #[test] + fn is_valid_literal_rejects_leading_underscore() { + assert!(AppCode::try_new(String::from("_INVALID")).is_err()); + } + + #[test] + fn is_valid_literal_rejects_trailing_underscore() { + assert!(AppCode::try_new(String::from("INVALID_")).is_err()); + } + + #[test] + fn is_valid_literal_rejects_double_underscore() { + assert!(AppCode::try_new(String::from("INVALID__CODE")).is_err()); + } + + #[test] + fn is_valid_literal_rejects_lowercase() { + assert!(AppCode::try_new(String::from("invalid_code")).is_err()); + } + + #[test] + fn is_valid_literal_accepts_numbers() { + assert!(AppCode::try_new(String::from("ERROR_404")).is_ok()); + assert!(AppCode::try_new(String::from("E404")).is_ok()); + } + + #[test] + fn serde_roundtrip() { + let code = AppCode::NotFound; + let json = serde_json::to_string(&code).expect("serialize"); + assert_eq!(json, "\"NOT_FOUND\""); + let parsed: AppCode = serde_json::from_str(&json).expect("deserialize"); + assert_eq!(parsed, code); + } + + #[test] + fn serde_custom_code_roundtrip() { + let code = AppCode::new("CUSTOM_ERROR"); + let json = serde_json::to_string(&code).expect("serialize"); + let parsed: AppCode = serde_json::from_str(&json).expect("deserialize"); + assert_eq!(parsed, code); + } + + #[test] + fn serde_deserialize_rejects_invalid() { + let result: Result = serde_json::from_str("\"invalid-code\""); + assert!(result.is_err()); + } + + #[test] + fn parse_error_display() { + let err = ParseAppCodeError; + assert!(!err.to_string().is_empty()); + } + + #[test] + fn debug_impl() { + let code = AppCode::NotFound; + let debug = format!("{:?}", code); + assert!(debug.contains("NotFound") || debug.contains("NOT_FOUND")); + } + + #[test] + fn clone_and_eq() { + let code = AppCode::new("CLONED_CODE"); + let cloned = code.clone(); + assert_eq!(code, cloned); + } + + #[test] + fn hash_impl_same_for_equal_codes() { + use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher} + }; + + let code1 = AppCode::NotFound; + let code2 = AppCode::from_str("NOT_FOUND").unwrap(); + let mut hasher1 = DefaultHasher::new(); + let mut hasher2 = DefaultHasher::new(); + code1.hash(&mut hasher1); + code2.hash(&mut hasher2); + assert_eq!(hasher1.finish(), hasher2.finish()); + } + + #[test] + fn hash_impl_different_for_different_codes() { + use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher} + }; + + let code1 = AppCode::NotFound; + let code2 = AppCode::Internal; + let mut hasher1 = DefaultHasher::new(); + let mut hasher2 = DefaultHasher::new(); + code1.hash(&mut hasher1); + code2.hash(&mut hasher2); + assert_ne!(hasher1.finish(), hasher2.finish()); + } + + #[test] + fn parse_error_source_is_none() { + use core::error::Error; + let err = ParseAppCodeError; + assert!(err.source().is_none()); + } + + #[test] + fn hashset_works_with_app_code() { + use std::collections::HashSet; + let mut set = HashSet::new(); + set.insert(AppCode::NotFound); + set.insert(AppCode::Internal); + set.insert(AppCode::NotFound); + assert_eq!(set.len(), 2); + assert!(set.contains(&AppCode::NotFound)); + } + + #[test] + fn custom_code_ne_builtin() { + let custom = AppCode::new("CUSTOM"); + assert_ne!(custom, AppCode::NotFound); + assert_ne!(custom, AppCode::Internal); + } + + #[test] + fn try_new_with_str_slice() { + let code = AppCode::try_new("SLICE_CODE").unwrap(); + assert_eq!(code.as_str(), "SLICE_CODE"); + } + + #[test] + fn from_str_empty() { + let result = AppCode::from_str(""); + assert!(result.is_err()); + } } diff --git a/src/colored.rs b/src/colored.rs index 2bb2f23..9b8c0c2 100644 --- a/src/colored.rs +++ b/src/colored.rs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-FileCopyrightText: 2025-2026 RAprogramm // // SPDX-License-Identifier: MIT @@ -81,299 +81,23 @@ //! Terminal detection is cached per-process, resulting in negligible overhead. //! Color styling only allocates when colors are actually applied. +#[cfg(feature = "std")] +mod std_style; + +#[cfg(not(feature = "std"))] +mod nostd_style; + +#[cfg(test)] +mod tests; + /// Color styling functions with automatic TTY detection. /// /// Each function applies appropriate ANSI color codes when stderr supports /// colors. When colors are not supported, the original text is returned /// unchanged. -#[cfg(feature = "std")] pub mod style { - use owo_colors::{OwoColorize, Stream}; - - /// Style critical error kind text in red. - /// - /// Use this for error kinds that indicate critical failures requiring - /// immediate attention. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "colored")] { - /// use masterror::colored::style; - /// - /// let styled = style::error_kind_critical("ServiceUnavailable"); - /// eprintln!("Kind: {}", styled); - /// # } - /// ``` - /// - /// # Color Behavior - /// - /// - TTY: Red text - /// - Non-TTY: Plain text - /// - NO_COLOR=1: Plain text - pub fn error_kind_critical(text: impl AsRef) -> String { - text.as_ref() - .if_supports_color(Stream::Stderr, |t| t.red()) - .to_string() - } - - /// Style warning-level error kind text in yellow. - /// - /// Use this for error kinds that indicate recoverable issues or warnings. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "colored")] { - /// use masterror::colored::style; - /// - /// let styled = style::error_kind_warning("BadRequest"); - /// eprintln!("Kind: {}", styled); - /// # } - /// ``` - /// - /// # Color Behavior - /// - /// - TTY: Yellow text - /// - Non-TTY: Plain text - /// - NO_COLOR=1: Plain text - pub fn error_kind_warning(text: impl AsRef) -> String { - text.as_ref() - .if_supports_color(Stream::Stderr, |t| t.yellow()) - .to_string() - } - - /// Style error code text in cyan for easy visual scanning. - /// - /// Use this for machine-readable error codes that users need to reference - /// in documentation or support requests. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "colored")] { - /// use masterror::colored::style; - /// - /// let styled = style::error_code("ERR_DATABASE_001"); - /// eprintln!("Code: {}", styled); - /// # } - /// ``` - /// - /// # Color Behavior - /// - /// - TTY: Cyan text - /// - Non-TTY: Plain text - /// - NO_COLOR=1: Plain text - pub fn error_code(text: impl AsRef) -> String { - text.as_ref() - .if_supports_color(Stream::Stderr, |t| t.cyan()) - .to_string() - } - - /// Style error message text in bright white for maximum readability. - /// - /// Use this for the primary error message that describes what went wrong. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "colored")] { - /// use masterror::colored::style; - /// - /// let styled = style::error_message("Failed to connect to database"); - /// eprintln!("{}", styled); - /// # } - /// ``` - /// - /// # Color Behavior - /// - /// - TTY: Bright white text - /// - Non-TTY: Plain text - /// - NO_COLOR=1: Plain text - pub fn error_message(text: impl AsRef) -> String { - text.as_ref() - .if_supports_color(Stream::Stderr, |t| t.bright_white()) - .to_string() - } - - /// Style source context text with dimmed appearance. - /// - /// Use this for error source chains and contextual information that is - /// important but secondary to the main error message. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "colored")] { - /// use masterror::colored::style; - /// - /// let styled = style::source_context("Caused by: Connection timeout"); - /// eprintln!("{}", styled); - /// # } - /// ``` - /// - /// # Color Behavior - /// - /// - TTY: Dimmed text - /// - Non-TTY: Plain text - /// - NO_COLOR=1: Plain text - pub fn source_context(text: impl AsRef) -> String { - text.as_ref() - .if_supports_color(Stream::Stderr, |t| t.dimmed()) - .to_string() - } - - /// Style metadata key text in green. - /// - /// Use this for structured metadata keys in error context to visually - /// separate keys from values. - /// - /// # Examples - /// - /// ```rust - /// # #[cfg(feature = "colored")] { - /// use masterror::colored::style; - /// - /// let key = style::metadata_key("request_id"); - /// eprintln!("{}: abc123", key); - /// # } - /// ``` - /// - /// # Color Behavior - /// - /// - TTY: Green text - /// - Non-TTY: Plain text - /// - NO_COLOR=1: Plain text - pub fn metadata_key(text: impl AsRef) -> String { - text.as_ref() - .if_supports_color(Stream::Stderr, |t| t.green()) - .to_string() - } -} - -/// No-op styling for no-std builds. -#[cfg(not(feature = "std"))] -pub mod style { - /// Style critical error kind text in red. - pub fn error_kind_critical(text: impl AsRef) -> String { - text.as_ref().to_string() - } - - /// Style warning-level error kind text in yellow. - pub fn error_kind_warning(text: impl AsRef) -> String { - text.as_ref().to_string() - } - - /// Style error code text in cyan for easy visual scanning. - pub fn error_code(text: impl AsRef) -> String { - text.as_ref().to_string() - } - - /// Style error message text in bright white for maximum readability. - pub fn error_message(text: impl AsRef) -> String { - text.as_ref().to_string() - } - - /// Style source context text with dimmed appearance. - pub fn source_context(text: impl AsRef) -> String { - text.as_ref().to_string() - } - - /// Style metadata key text in green. - pub fn metadata_key(text: impl AsRef) -> String { - text.as_ref().to_string() - } -} - -#[cfg(all(test, not(feature = "std")))] -mod nostd_tests { - use super::style; - - #[test] - fn error_kind_critical_returns_plain_text() { - assert_eq!(style::error_kind_critical("test"), "test"); - } - - #[test] - fn error_kind_warning_returns_plain_text() { - assert_eq!(style::error_kind_warning("test"), "test"); - } - - #[test] - fn error_code_returns_plain_text() { - assert_eq!(style::error_code("ERR_001"), "ERR_001"); - } - - #[test] - fn error_message_returns_plain_text() { - assert_eq!(style::error_message("message"), "message"); - } - - #[test] - fn source_context_returns_plain_text() { - assert_eq!(style::source_context("context"), "context"); - } - - #[test] - fn metadata_key_returns_plain_text() { - assert_eq!(style::metadata_key("key"), "key"); - } -} - -#[cfg(all(test, feature = "std"))] -mod tests { - use super::style; - - #[test] - fn error_kind_critical_produces_output() { - let result = style::error_kind_critical("ServiceUnavailable"); - assert!(!result.is_empty()); - assert!(result.contains("ServiceUnavailable")); - } - - #[test] - fn error_kind_warning_produces_output() { - let result = style::error_kind_warning("BadRequest"); - assert!(!result.is_empty()); - assert!(result.contains("BadRequest")); - } - - #[test] - fn error_code_produces_output() { - let result = style::error_code("ERR_001"); - assert!(!result.is_empty()); - assert!(result.contains("ERR_001")); - } - - #[test] - fn error_message_produces_output() { - let result = style::error_message("Connection failed"); - assert!(!result.is_empty()); - assert!(result.contains("Connection failed")); - } - - #[test] - fn source_context_produces_output() { - let result = style::source_context("Caused by: timeout"); - assert!(!result.is_empty()); - assert!(result.contains("Caused by: timeout")); - } - - #[test] - fn metadata_key_produces_output() { - let result = style::metadata_key("request_id"); - assert!(!result.is_empty()); - assert!(result.contains("request_id")); - } - - #[test] - fn style_functions_preserve_content() { - let input = "test content with special chars: äöü"; - assert!(style::error_kind_critical(input).contains(input)); - assert!(style::error_kind_warning(input).contains(input)); - assert!(style::error_code(input).contains(input)); - assert!(style::error_message(input).contains(input)); - assert!(style::source_context(input).contains(input)); - assert!(style::metadata_key(input).contains(input)); - } + #[cfg(not(feature = "std"))] + pub use super::nostd_style::*; + #[cfg(feature = "std")] + pub use super::std_style::*; } diff --git a/src/colored/nostd_style.rs b/src/colored/nostd_style.rs new file mode 100644 index 0000000..d0b1039 --- /dev/null +++ b/src/colored/nostd_style.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! No-op styling functions for no-std builds. +//! +//! All functions return the input text unchanged, providing API compatibility +//! with the std feature while avoiding any allocations beyond string +//! conversion. + +use alloc::string::{String, ToString}; + +macro_rules! identity_style { + ($($(#[$meta:meta])* $name:ident),* $(,)?) => { + $( + $(#[$meta])* + #[inline] + pub fn $name(text: impl AsRef) -> String { + text.as_ref().to_string() + } + )* + }; +} + +identity_style! { + /// Style critical error kind text (no-op in no-std). + error_kind_critical, + /// Style warning-level error kind text (no-op in no-std). + error_kind_warning, + /// Style error code text (no-op in no-std). + error_code, + /// Style error message text (no-op in no-std). + error_message, + /// Style source context text (no-op in no-std). + source_context, + /// Style metadata key text (no-op in no-std). + metadata_key, + /// Style hint label (no-op in no-std). + hint_label, + /// Style hint message (no-op in no-std). + hint_text, + /// Style suggestion label (no-op in no-std). + suggestion_label, + /// Style suggestion message (no-op in no-std). + suggestion_text, + /// Style command/code snippet (no-op in no-std). + command, + /// Style documentation link label (no-op in no-std). + docs_label, + /// Style URL (no-op in no-std). + url, + /// Style "see also" label (no-op in no-std). + related_label, + /// Style backtrace header label (no-op in no-std). + backtrace_label, + /// Style backtrace arrow symbol (no-op in no-std). + backtrace_arrow, + /// Style backtrace function name (no-op in no-std). + backtrace_function, + /// Style backtrace file location (no-op in no-std). + backtrace_location, +} + +/// Create a clickable hyperlink (no-op in no-std). +#[inline] +pub fn backtrace_link(display: &str, _absolute_path: &str, _line: Option) -> String { + display.to_string() +} diff --git a/src/colored/std_style.rs b/src/colored/std_style.rs new file mode 100644 index 0000000..b9d43b6 --- /dev/null +++ b/src/colored/std_style.rs @@ -0,0 +1,362 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Color styling functions using owo_colors with automatic TTY detection. + +use owo_colors::{OwoColorize, Stream, Style}; + +/// Style critical error kind text in red. +/// +/// Use this for error kinds that indicate critical failures requiring +/// immediate attention. +/// +/// # Examples +/// +/// ```rust +/// # #[cfg(feature = "colored")] { +/// use masterror::colored::style; +/// +/// let styled = style::error_kind_critical("ServiceUnavailable"); +/// eprintln!("Kind: {}", styled); +/// # } +/// ``` +/// +/// # Color Behavior +/// +/// - TTY: Red text +/// - Non-TTY: Plain text +/// - NO_COLOR=1: Plain text +pub fn error_kind_critical(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.red()) + .to_string() +} + +/// Style warning-level error kind text in yellow. +/// +/// Use this for error kinds that indicate recoverable issues or warnings. +/// +/// # Examples +/// +/// ```rust +/// # #[cfg(feature = "colored")] { +/// use masterror::colored::style; +/// +/// let styled = style::error_kind_warning("BadRequest"); +/// eprintln!("Kind: {}", styled); +/// # } +/// ``` +/// +/// # Color Behavior +/// +/// - TTY: Yellow text +/// - Non-TTY: Plain text +/// - NO_COLOR=1: Plain text +pub fn error_kind_warning(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.yellow()) + .to_string() +} + +/// Style error code text in cyan for easy visual scanning. +/// +/// Use this for machine-readable error codes that users need to reference +/// in documentation or support requests. +/// +/// # Examples +/// +/// ```rust +/// # #[cfg(feature = "colored")] { +/// use masterror::colored::style; +/// +/// let styled = style::error_code("ERR_DATABASE_001"); +/// eprintln!("Code: {}", styled); +/// # } +/// ``` +/// +/// # Color Behavior +/// +/// - TTY: Cyan text +/// - Non-TTY: Plain text +/// - NO_COLOR=1: Plain text +pub fn error_code(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.cyan()) + .to_string() +} + +/// Style error message text in bright white for maximum readability. +/// +/// Use this for the primary error message that describes what went wrong. +/// +/// # Examples +/// +/// ```rust +/// # #[cfg(feature = "colored")] { +/// use masterror::colored::style; +/// +/// let styled = style::error_message("Failed to connect to database"); +/// eprintln!("{}", styled); +/// # } +/// ``` +/// +/// # Color Behavior +/// +/// - TTY: Bright white text +/// - Non-TTY: Plain text +/// - NO_COLOR=1: Plain text +pub fn error_message(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.bright_white()) + .to_string() +} + +/// Style source context text with dimmed appearance. +/// +/// Use this for error source chains and contextual information that is +/// important but secondary to the main error message. +/// +/// # Examples +/// +/// ```rust +/// # #[cfg(feature = "colored")] { +/// use masterror::colored::style; +/// +/// let styled = style::source_context("Caused by: Connection timeout"); +/// eprintln!("{}", styled); +/// # } +/// ``` +/// +/// # Color Behavior +/// +/// - TTY: Dimmed text +/// - Non-TTY: Plain text +/// - NO_COLOR=1: Plain text +pub fn source_context(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.dimmed()) + .to_string() +} + +/// Style metadata key text in green. +/// +/// Use this for structured metadata keys in error context to visually +/// separate keys from values. +/// +/// # Examples +/// +/// ```rust +/// # #[cfg(feature = "colored")] { +/// use masterror::colored::style; +/// +/// let key = style::metadata_key("request_id"); +/// eprintln!("{}: abc123", key); +/// # } +/// ``` +/// +/// # Color Behavior +/// +/// - TTY: Green text +/// - Non-TTY: Plain text +/// - NO_COLOR=1: Plain text +pub fn metadata_key(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.green()) + .to_string() +} + +// ───────────────────────────────────────────────────────────────────────────── +// Diagnostic styling +// ───────────────────────────────────────────────────────────────────────────── + +/// Style hint label in blue. +/// +/// # Color Behavior +/// +/// - TTY: Blue text +/// - Non-TTY: Plain text +pub fn hint_label(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.blue()) + .to_string() +} + +/// Style hint message in bright blue. +/// +/// # Color Behavior +/// +/// - TTY: Bright blue text +/// - Non-TTY: Plain text +pub fn hint_text(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.bright_blue()) + .to_string() +} + +/// Style suggestion label in magenta. +/// +/// # Color Behavior +/// +/// - TTY: Magenta text +/// - Non-TTY: Plain text +pub fn suggestion_label(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.magenta()) + .to_string() +} + +/// Style suggestion message in bright magenta. +/// +/// # Color Behavior +/// +/// - TTY: Bright magenta text +/// - Non-TTY: Plain text +pub fn suggestion_text(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.bright_magenta()) + .to_string() +} + +/// Style command/code snippet in bold bright white. +/// +/// # Color Behavior +/// +/// - TTY: Bold bright white text +/// - Non-TTY: Plain text +pub fn command(text: impl AsRef) -> String { + let style = Style::new().bold().bright_white(); + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.style(style)) + .to_string() +} + +/// Style documentation link label in cyan. +/// +/// # Color Behavior +/// +/// - TTY: Cyan text +/// - Non-TTY: Plain text +pub fn docs_label(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.cyan()) + .to_string() +} + +/// Style URL in underlined cyan. +/// +/// # Color Behavior +/// +/// - TTY: Underlined cyan text +/// - Non-TTY: Plain text +pub fn url(text: impl AsRef) -> String { + let style = Style::new().underline().cyan(); + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.style(style)) + .to_string() +} + +/// Style "see also" label in dimmed text. +/// +/// # Color Behavior +/// +/// - TTY: Dimmed text +/// - Non-TTY: Plain text +pub fn related_label(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.dimmed()) + .to_string() +} + +// ───────────────────────────────────────────────────────────────────────────── +// Backtrace styling +// ───────────────────────────────────────────────────────────────────────────── + +/// Style backtrace header label in dimmed text. +/// +/// # Color Behavior +/// +/// - TTY: Dimmed text +/// - Non-TTY: Plain text +pub fn backtrace_label(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.dimmed()) + .to_string() +} + +/// Style backtrace arrow symbol in yellow. +/// +/// # Color Behavior +/// +/// - TTY: Yellow text +/// - Non-TTY: Plain text +pub fn backtrace_arrow(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.yellow()) + .to_string() +} + +/// Style backtrace function name in bright cyan. +/// +/// # Color Behavior +/// +/// - TTY: Bright cyan text +/// - Non-TTY: Plain text +pub fn backtrace_function(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.bright_cyan()) + .to_string() +} + +/// Style backtrace file location in dimmed text. +/// +/// # Color Behavior +/// +/// - TTY: Dimmed text +/// - Non-TTY: Plain text +pub fn backtrace_location(text: impl AsRef) -> String { + text.as_ref() + .if_supports_color(Stream::Stderr, |t| t.dimmed()) + .to_string() +} + +/// Create a clickable hyperlink for file location in backtrace. +/// +/// Uses OSC 8 escape sequences supported by modern terminals. +/// Falls back to plain text if not a TTY. +/// +/// # Arguments +/// +/// * `display` - Text to display (e.g., "src/main.rs:16") +/// * `absolute_path` - Absolute file path for the link +/// * `line` - Line number (optional) +/// +/// # Color Behavior +/// +/// - TTY: Clickable hyperlink with dimmed text +/// - Non-TTY: Plain text +pub fn backtrace_link(display: &str, absolute_path: &str, line: Option) -> String { + use std::io::IsTerminal; + + if !std::io::stderr().is_terminal() { + return display.to_string(); + } + + // Check NO_COLOR + if std::env::var_os("NO_COLOR").is_some() { + return display.to_string(); + } + + let url = if let Some(ln) = line { + format!("editor://open?path={}&line={}", absolute_path, ln) + } else { + format!("editor://open?path={}", absolute_path) + }; + + // OSC 8 hyperlink: \x1b]8;;URL\x07TEXT\x1b]8;;\x07 + let styled = display + .if_supports_color(Stream::Stderr, |t| t.dimmed()) + .to_string(); + + format!("\x1b]8;;{}\x07{}\x1b]8;;\x07", url, styled) +} diff --git a/src/colored/tests.rs b/src/colored/tests.rs new file mode 100644 index 0000000..1fcb020 --- /dev/null +++ b/src/colored/tests.rs @@ -0,0 +1,147 @@ +// SPDX-FileCopyrightText: 2025-2026 RAprogramm +// +// SPDX-License-Identifier: MIT + +//! Tests for colored styling module. + +#[cfg(feature = "std")] +mod std_tests { + use crate::colored::style::*; + + macro_rules! test_style_produces_output { + ($($name:ident($func:ident, $input:expr)),* $(,)?) => { + $( + #[test] + fn $name() { + let result = $func($input); + assert!(!result.is_empty()); + assert!(result.contains($input)); + } + )* + }; + } + + test_style_produces_output! { + error_kind_critical_produces_output(error_kind_critical, "ServiceUnavailable"), + error_kind_warning_produces_output(error_kind_warning, "BadRequest"), + error_code_produces_output(error_code, "ERR_001"), + error_message_produces_output(error_message, "Connection failed"), + source_context_produces_output(source_context, "Caused by: timeout"), + metadata_key_produces_output(metadata_key, "request_id"), + hint_label_produces_output(hint_label, "hint"), + hint_text_produces_output(hint_text, "Try restarting the service"), + suggestion_label_produces_output(suggestion_label, "suggestion"), + suggestion_text_produces_output(suggestion_text, "Run cargo clean"), + command_produces_output(command, "cargo build --release"), + docs_label_produces_output(docs_label, "docs"), + url_produces_output(url, "https://docs.rs/masterror"), + related_label_produces_output(related_label, "see also"), + } + + // ───────────────────────────────────────────────────────────────────────── + // Content preservation tests + // ───────────────────────────────────────────────────────────────────────── + + #[test] + fn all_style_functions_preserve_content() { + let input = "test content with special chars: äöü"; + assert!(error_kind_critical(input).contains(input)); + assert!(error_kind_warning(input).contains(input)); + assert!(error_code(input).contains(input)); + assert!(error_message(input).contains(input)); + assert!(source_context(input).contains(input)); + assert!(metadata_key(input).contains(input)); + } + + #[test] + fn diagnostic_functions_preserve_content() { + let input = "content with unicode: 日本語"; + assert!(hint_label(input).contains(input)); + assert!(hint_text(input).contains(input)); + assert!(suggestion_label(input).contains(input)); + assert!(suggestion_text(input).contains(input)); + assert!(command(input).contains(input)); + assert!(docs_label(input).contains(input)); + assert!(url(input).contains(input)); + assert!(related_label(input).contains(input)); + } + + // ───────────────────────────────────────────────────────────────────────── + // Edge case tests + // ───────────────────────────────────────────────────────────────────────── + + #[test] + fn empty_string_returns_empty() { + assert!(error_kind_critical("").is_empty() || error_kind_critical("").contains("")); + assert!(error_code("").is_empty() || error_code("").contains("")); + assert!(command("").is_empty() || command("").contains("")); + } + + #[test] + fn whitespace_preserved() { + let input = " spaced text "; + assert!(error_message(input).contains(input)); + assert!(hint_text(input).contains(input)); + } + + #[test] + fn newlines_preserved() { + let input = "line1\nline2\nline3"; + assert!(error_message(input).contains(input)); + assert!(suggestion_text(input).contains(input)); + } + + #[test] + fn special_chars_preserved() { + let input = "path/to/file.rs:42:13"; + assert!(error_message(input).contains(input)); + assert!(source_context(input).contains(input)); + } + + #[test] + fn ansi_escape_sequences_in_input_preserved() { + let input = "\x1b[31mred\x1b[0m"; + let result = error_message(input); + assert!(result.contains("red")); + } +} + +#[cfg(not(feature = "std"))] +mod nostd_tests { + use crate::colored::style::*; + + macro_rules! test_style_returns_plain { + ($($name:ident($func:ident, $input:expr)),* $(,)?) => { + $( + #[test] + fn $name() { + assert_eq!($func($input), $input); + } + )* + }; + } + + test_style_returns_plain! { + error_kind_critical_returns_plain_text(error_kind_critical, "test"), + error_kind_warning_returns_plain_text(error_kind_warning, "test"), + error_code_returns_plain_text(error_code, "ERR_001"), + error_message_returns_plain_text(error_message, "message"), + source_context_returns_plain_text(source_context, "context"), + metadata_key_returns_plain_text(metadata_key, "key"), + hint_label_returns_plain_text(hint_label, "hint"), + hint_text_returns_plain_text(hint_text, "help text"), + suggestion_label_returns_plain_text(suggestion_label, "suggestion"), + suggestion_text_returns_plain_text(suggestion_text, "try this"), + command_returns_plain_text(command, "cargo build"), + docs_label_returns_plain_text(docs_label, "docs"), + url_returns_plain_text(url, "https://example.com"), + related_label_returns_plain_text(related_label, "see also"), + empty_error_kind_critical(error_kind_critical, ""), + empty_error_code(error_code, ""), + empty_command(command, ""), + unicode_error_message(error_message, "エラー: 日本語テスト"), + unicode_hint_text(hint_text, "エラー: 日本語テスト"), + special_chars_source_context(source_context, "file.rs:42:13 -> error"), + special_chars_suggestion_text(suggestion_text, "file.rs:42:13 -> error"), + } +} diff --git a/src/convert/config.rs b/src/convert/config.rs index 2432b49..bc79f48 100644 --- a/src/convert/config.rs +++ b/src/convert/config.rs @@ -116,4 +116,156 @@ mod tests { Some(&FieldValue::Str("message".into())) ); } + + #[test] + fn frozen_error_maps_correctly() { + let err = ConfigError::Frozen; + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + assert_eq!( + app_err.metadata().get("config.phase"), + Some(&FieldValue::Str("frozen".into())) + ); + } + + #[test] + fn not_found_error_captures_key() { + let err = ConfigError::NotFound("database.url".into()); + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("config.phase"), + Some(&FieldValue::Str("not_found".into())) + ); + assert_eq!( + metadata.get("config.key"), + Some(&FieldValue::Str("database.url".into())) + ); + } + + #[test] + fn path_parse_error_maps_correctly() { + let err = ConfigError::PathParse { + cause: Box::new(std::io::Error::other("invalid path")) + }; + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + assert_eq!( + app_err.metadata().get("config.phase"), + Some(&FieldValue::Str("path_parse".into())) + ); + } + + #[test] + fn file_parse_error_without_uri() { + let err = ConfigError::FileParse { + uri: None, + cause: Box::new(std::io::Error::other("disk")) + }; + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + assert_eq!( + app_err.metadata().get("config.phase"), + Some(&FieldValue::Str("file_parse".into())) + ); + assert!(app_err.metadata().get("config.uri").is_none()); + } + + #[test] + fn file_parse_error_with_uri() { + let err = ConfigError::FileParse { + uri: Some("/etc/app/config.toml".into()), + cause: Box::new(std::io::Error::other("disk")) + }; + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("config.phase"), + Some(&FieldValue::Str("file_parse".into())) + ); + assert_eq!( + metadata.get("config.uri"), + Some(&FieldValue::Str("/etc/app/config.toml".into())) + ); + } + + #[test] + fn at_error_with_all_fields() { + let err = ConfigError::At { + origin: Some("env.toml".into()), + key: Some("database.host".into()), + error: Box::new(ConfigError::Message("invalid".into())) + }; + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("config.phase"), + Some(&FieldValue::Str("at".into())) + ); + assert_eq!( + metadata.get("config.origin"), + Some(&FieldValue::Str("env.toml".into())) + ); + assert_eq!( + metadata.get("config.key"), + Some(&FieldValue::Str("database.host".into())) + ); + } + + #[test] + fn at_error_without_optional_fields() { + let err = ConfigError::At { + origin: None, + key: None, + error: Box::new(ConfigError::Message("error".into())) + }; + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("config.phase"), + Some(&FieldValue::Str("at".into())) + ); + assert!(metadata.get("config.origin").is_none()); + assert!(metadata.get("config.key").is_none()); + } + + #[test] + fn message_error_preserves_message() { + let err = ConfigError::Message("custom error message".into()); + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("config.phase"), + Some(&FieldValue::Str("message".into())) + ); + assert_eq!( + metadata.get("config.message"), + Some(&FieldValue::Str("custom error message".into())) + ); + } + + #[test] + fn foreign_error_maps_correctly() { + let foreign_err = Box::new(std::io::Error::other("external")) + as Box; + let err = ConfigError::Foreign(foreign_err); + let app_err = Error::from(err); + assert!(matches!(app_err.kind, AppErrorKind::Config)); + assert_eq!( + app_err.metadata().get("config.phase"), + Some(&FieldValue::Str("foreign".into())) + ); + } + + #[test] + fn error_preserves_source() { + let err = ConfigError::Message("source test".into()); + let app_err = Error::from(err); + assert!(app_err.source_ref().is_some()); + } } diff --git a/src/convert/redis.rs b/src/convert/redis.rs index bce2e3c..9756aab 100644 --- a/src/convert/redis.rs +++ b/src/convert/redis.rs @@ -149,4 +149,128 @@ mod tests { let app_err: Error = redis_err.into(); assert!(matches!(app_err.kind, AppErrorKind::Cache)); } + + #[test] + fn io_error_maps_to_dependency_unavailable() { + let redis_err = RedisError::from((ErrorKind::Io, "connection timeout")); + let app_err: Error = redis_err.into(); + assert!(matches!(app_err.kind, AppErrorKind::DependencyUnavailable)); + } + + #[test] + fn connection_refused_maps_to_dependency_unavailable() { + let redis_err = RedisError::from((ErrorKind::Io, "connection refused")); + let app_err: Error = redis_err.into(); + assert!(matches!(app_err.kind, AppErrorKind::DependencyUnavailable)); + } + + #[test] + fn metadata_contains_category() { + let redis_err = RedisError::from((ErrorKind::Client, "test")); + let app_err: Error = redis_err.into(); + let metadata = app_err.metadata(); + assert!(metadata.get("redis.category").is_some()); + } + + #[test] + fn metadata_contains_timeout_flag() { + let redis_err = RedisError::from((ErrorKind::Client, "test")); + let app_err: Error = redis_err.into(); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("redis.is_timeout"), + Some(&FieldValue::Bool(false)) + ); + } + + #[test] + fn metadata_contains_cluster_error_flag() { + let redis_err = RedisError::from((ErrorKind::Client, "test")); + let app_err: Error = redis_err.into(); + let metadata = app_err.metadata(); + assert_eq!( + metadata.get("redis.is_cluster_error"), + Some(&FieldValue::Bool(false)) + ); + } + + #[test] + fn metadata_contains_connection_flags() { + let redis_err = RedisError::from((ErrorKind::Client, "test")); + let app_err: Error = redis_err.into(); + let metadata = app_err.metadata(); + assert!(metadata.get("redis.is_connection_refused").is_some()); + assert!(metadata.get("redis.is_connection_dropped").is_some()); + } + + #[test] + fn retry_method_no_retry() { + let (label, after) = retry_method_details(RetryMethod::NoRetry); + assert_eq!(label, "NoRetry"); + assert_eq!(after, None); + } + + #[test] + fn retry_method_retry_immediately() { + let (label, after) = retry_method_details(RetryMethod::RetryImmediately); + assert_eq!(label, "RetryImmediately"); + assert_eq!(after, Some(0)); + } + + #[test] + fn retry_method_ask_redirect() { + let (label, after) = retry_method_details(RetryMethod::AskRedirect); + assert_eq!(label, "AskRedirect"); + assert_eq!(after, Some(0)); + } + + #[test] + fn retry_method_moved_redirect() { + let (label, after) = retry_method_details(RetryMethod::MovedRedirect); + assert_eq!(label, "MovedRedirect"); + assert_eq!(after, Some(0)); + } + + #[test] + fn retry_method_reconnect() { + let (label, after) = retry_method_details(RetryMethod::Reconnect); + assert_eq!(label, "Reconnect"); + assert_eq!(after, Some(1)); + } + + #[test] + fn retry_method_reconnect_from_initial() { + let (label, after) = retry_method_details(RetryMethod::ReconnectFromInitialConnections); + assert_eq!(label, "ReconnectFromInitialConnections"); + assert_eq!(after, Some(1)); + } + + #[test] + fn retry_method_wait_and_retry() { + let (label, after) = retry_method_details(RetryMethod::WaitAndRetry); + assert_eq!(label, "WaitAndRetry"); + assert_eq!(after, Some(2)); + } + + #[test] + fn error_preserves_source() { + let redis_err = RedisError::from((ErrorKind::Client, "test")); + let app_err: Error = redis_err.into(); + assert!(app_err.source_ref().is_some()); + } + + #[test] + fn metadata_contains_retry_method() { + let redis_err = RedisError::from((ErrorKind::Client, "test")); + let app_err: Error = redis_err.into(); + let metadata = app_err.metadata(); + assert!(metadata.get("redis.retry_method").is_some()); + } + + #[test] + fn parse_error_maps_to_cache() { + let redis_err = RedisError::from((ErrorKind::Parse, "invalid response")); + let app_err: Error = redis_err.into(); + assert!(matches!(app_err.kind, AppErrorKind::Cache)); + } } diff --git a/src/convert/reqwest.rs b/src/convert/reqwest.rs index 7b73c31..925a304 100644 --- a/src/convert/reqwest.rs +++ b/src/convert/reqwest.rs @@ -153,191 +153,191 @@ fn classify_reqwest_error(err: &ReqwestError) -> (Context, Option) { #[cfg(all(test, feature = "reqwest", feature = "tokio"))] mod tests { - use std::time::Duration; + use std::{net::SocketAddr, time::Duration}; use reqwest::Client; - use tokio::{net::TcpListener, time::sleep}; + use tokio::{net::TcpListener, task::JoinHandle, time::sleep}; use super::*; use crate::{AppCode, AppErrorKind, FieldRedaction, FieldValue}; + /// Mock HTTP server that returns a fixed response. + struct MockServer { + addr: SocketAddr, + handle: JoinHandle<()> + } + + impl MockServer { + /// Start server that returns the given HTTP response. + async fn with_response(response: &'static [u8]) -> Self { + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + + let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); + let addr = listener.local_addr().expect("addr"); + let handle = tokio::spawn(async move { + let (mut socket, _) = listener.accept().await.expect("accept"); + let mut buf = [0_u8; 1024]; + let _ = socket.read(&mut buf).await; + let _ = socket.write_all(response).await; + }); + Self { + addr, + handle + } + } + + /// Start server that delays indefinitely (for timeout tests). + async fn delayed() -> Self { + let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); + let addr = listener.local_addr().expect("addr"); + let handle = tokio::spawn(async move { + let (_socket, _) = listener.accept().await.expect("accept"); + sleep(Duration::from_secs(60)).await; + }); + Self { + addr, + handle + } + } + + fn url(&self) -> String { + format!("http://{}", self.addr) + } + + fn url_with_path(&self, path: &str) -> String { + format!("http://{}{}", self.addr, path) + } + } + + impl Drop for MockServer { + fn drop(&mut self) { + self.handle.abort(); + } + } + + /// Get status error from mock server response. + async fn status_error_from(server: &MockServer) -> Error { + let response = Client::new().get(server.url()).send().await.expect("send"); + response + .error_for_status() + .expect_err("status error") + .into() + } + #[tokio::test] async fn timeout_sets_category_and_metadata() { - let listener = TcpListener::bind("127.0.0.1:0") - .await - .expect("bind listener"); - let addr = listener.local_addr().expect("listener addr"); - let server = tokio::spawn(async move { - let (_socket, _) = listener.accept().await.expect("accept"); - sleep(Duration::from_secs(5)).await; - }); + let server = MockServer::delayed().await; let client = Client::builder() .timeout(Duration::from_millis(50)) .build() .expect("client"); let err = client - .get(format!("http://{addr}")) + .get(server.url()) .send() .await .expect_err("expected timeout"); let app_err: Error = err.into(); assert_eq!(app_err.kind, AppErrorKind::Timeout); - let metadata = app_err.metadata(); assert_eq!( - metadata.get("reqwest.is_timeout"), + app_err.metadata().get("reqwest.is_timeout"), Some(&FieldValue::Bool(true)) ); - assert_eq!(metadata.redaction("http.url"), Some(FieldRedaction::Hash)); - server.abort(); + assert_eq!( + app_err.metadata().redaction("http.url"), + Some(FieldRedaction::Hash) + ); } #[tokio::test] async fn status_error_maps_retry_and_rate_limit() { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("addr"); - let server = tokio::spawn(async move { - let (mut socket, _) = listener.accept().await.expect("accept"); - let mut buf = [0_u8; 1024]; - let _ = socket.read(&mut buf).await; - let response = b"HTTP/1.1 429 Too Many Requests\r\ncontent-length: 0\r\n\r\n"; - let _ = socket.write_all(response).await; - }); - let client = Client::new(); - let response = client - .get(format!("http://{addr}")) - .send() - .await - .expect("send"); - let err = response.error_for_status().expect_err("status error"); - let app_err: Error = err.into(); + let server = MockServer::with_response( + b"HTTP/1.1 429 Too Many Requests\r\ncontent-length: 0\r\n\r\n" + ) + .await; + let app_err = status_error_from(&server).await; assert_eq!(app_err.kind, AppErrorKind::RateLimited); assert_eq!(app_err.code, AppCode::RateLimited); assert_eq!(app_err.retry.map(|r| r.after_seconds), Some(1)); - let metadata = app_err.metadata(); - assert_eq!(metadata.get("http.status"), Some(&FieldValue::U64(429))); assert_eq!( - metadata.get("http.port"), - Some(&FieldValue::U64(u64::from(addr.port()))) + app_err.metadata().get("http.status"), + Some(&FieldValue::U64(429)) + ); + assert_eq!( + app_err.metadata().get("http.port"), + Some(&FieldValue::U64(u64::from(server.addr.port()))) ); - server.abort(); } #[tokio::test] async fn server_error_maps_to_dependency_unavailable() { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("addr"); - let server = tokio::spawn(async move { - let (mut socket, _) = listener.accept().await.expect("accept"); - let mut buf = [0_u8; 1024]; - let _ = socket.read(&mut buf).await; - let response = b"HTTP/1.1 500 Internal Server Error\r\ncontent-length: 0\r\n\r\n"; - let _ = socket.write_all(response).await; - }); - let client = Client::new(); - let response = client - .get(format!("http://{addr}")) - .send() - .await - .expect("send"); - let err = response.error_for_status().expect_err("status error"); - let app_err: Error = err.into(); + let server = MockServer::with_response( + b"HTTP/1.1 500 Internal Server Error\r\ncontent-length: 0\r\n\r\n" + ) + .await; + let app_err = status_error_from(&server).await; assert_eq!(app_err.kind, AppErrorKind::DependencyUnavailable); - let metadata = app_err.metadata(); - assert_eq!(metadata.get("http.status"), Some(&FieldValue::U64(500))); - server.abort(); + assert_eq!( + app_err.metadata().get("http.status"), + Some(&FieldValue::U64(500)) + ); } #[tokio::test] async fn request_timeout_status_maps_to_timeout() { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("addr"); - let server = tokio::spawn(async move { - let (mut socket, _) = listener.accept().await.expect("accept"); - let mut buf = [0_u8; 1024]; - let _ = socket.read(&mut buf).await; - let response = b"HTTP/1.1 408 Request Timeout\r\ncontent-length: 0\r\n\r\n"; - let _ = socket.write_all(response).await; - }); - let client = Client::new(); - let response = client - .get(format!("http://{addr}")) - .send() - .await - .expect("send"); - let err = response.error_for_status().expect_err("status error"); - let app_err: Error = err.into(); + let server = MockServer::with_response( + b"HTTP/1.1 408 Request Timeout\r\ncontent-length: 0\r\n\r\n" + ) + .await; + let app_err = status_error_from(&server).await; assert_eq!(app_err.kind, AppErrorKind::Timeout); - let metadata = app_err.metadata(); - assert_eq!(metadata.get("http.status"), Some(&FieldValue::U64(408))); - server.abort(); + assert_eq!( + app_err.metadata().get("http.status"), + Some(&FieldValue::U64(408)) + ); } #[tokio::test] async fn client_error_maps_to_external_api() { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("addr"); - let server = tokio::spawn(async move { - let (mut socket, _) = listener.accept().await.expect("accept"); - let mut buf = [0_u8; 1024]; - let _ = socket.read(&mut buf).await; - let response = b"HTTP/1.1 400 Bad Request\r\ncontent-length: 0\r\n\r\n"; - let _ = socket.write_all(response).await; - }); - let client = Client::new(); - let response = client - .get(format!("http://{addr}")) - .send() - .await - .expect("send"); - let err = response.error_for_status().expect_err("status error"); - let app_err: Error = err.into(); + let server = + MockServer::with_response(b"HTTP/1.1 400 Bad Request\r\ncontent-length: 0\r\n\r\n") + .await; + let app_err = status_error_from(&server).await; assert_eq!(app_err.kind, AppErrorKind::ExternalApi); - let metadata = app_err.metadata(); - assert_eq!(metadata.get("http.status"), Some(&FieldValue::U64(400))); - server.abort(); + assert_eq!( + app_err.metadata().get("http.status"), + Some(&FieldValue::U64(400)) + ); } #[tokio::test] async fn connect_error_maps_to_network() { - let client = Client::new(); - let err = client + let err = Client::new() .get("http://127.0.0.1:1") .send() .await .expect_err("connection refused"); let app_err: Error = err.into(); assert_eq!(app_err.kind, AppErrorKind::Network); - let metadata = app_err.metadata(); assert_eq!( - metadata.get("reqwest.is_connect"), + app_err.metadata().get("reqwest.is_connect"), Some(&FieldValue::Bool(true)) ); } #[tokio::test] async fn url_metadata_is_captured() { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("addr"); - let server = tokio::spawn(async move { - let (mut socket, _) = listener.accept().await.expect("accept"); - let mut buf = [0_u8; 1024]; - let _ = socket.read(&mut buf).await; - let response = b"HTTP/1.1 404 Not Found\r\ncontent-length: 0\r\n\r\n"; - let _ = socket.write_all(response).await; - }); - let client = Client::new(); - let response = client - .get(format!("http://{addr}/api/v1/test")) + let server = + MockServer::with_response(b"HTTP/1.1 404 Not Found\r\ncontent-length: 0\r\n\r\n") + .await; + let response = Client::new() + .get(server.url_with_path("/api/v1/test")) .send() .await .expect("send"); - let err = response.error_for_status().expect_err("status error"); - let app_err: Error = err.into(); + let app_err: Error = response + .error_for_status() + .expect_err("status error") + .into(); let metadata = app_err.metadata(); assert_eq!( metadata.get("http.host"), @@ -345,7 +345,7 @@ mod tests { ); assert_eq!( metadata.get("http.port"), - Some(&FieldValue::U64(u64::from(addr.port()))) + Some(&FieldValue::U64(u64::from(server.addr.port()))) ); assert_eq!( metadata.get("http.path"), @@ -356,41 +356,23 @@ mod tests { Some(&FieldValue::Str("http".into())) ); assert_eq!(metadata.redaction("http.url"), Some(FieldRedaction::Hash)); - server.abort(); } #[tokio::test] async fn status_reason_is_captured() { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("addr"); - let server = tokio::spawn(async move { - let (mut socket, _) = listener.accept().await.expect("accept"); - let mut buf = [0_u8; 1024]; - let _ = socket.read(&mut buf).await; - let response = b"HTTP/1.1 403 Forbidden\r\ncontent-length: 0\r\n\r\n"; - let _ = socket.write_all(response).await; - }); - let client = Client::new(); - let response = client - .get(format!("http://{addr}")) - .send() - .await - .expect("send"); - let err = response.error_for_status().expect_err("status error"); - let app_err: Error = err.into(); - let metadata = app_err.metadata(); + let server = + MockServer::with_response(b"HTTP/1.1 403 Forbidden\r\ncontent-length: 0\r\n\r\n") + .await; + let app_err = status_error_from(&server).await; assert_eq!( - metadata.get("http.status_reason"), + app_err.metadata().get("http.status_reason"), Some(&FieldValue::Str("Forbidden".into())) ); - server.abort(); } #[tokio::test] async fn all_reqwest_flags_are_captured() { - let client = Client::new(); - let err = client + let err = Client::new() .get("http://127.0.0.1:1") .send() .await @@ -408,25 +390,11 @@ mod tests { #[tokio::test] async fn service_unavailable_maps_correctly() { - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("addr"); - let server = tokio::spawn(async move { - let (mut socket, _) = listener.accept().await.expect("accept"); - let mut buf = [0_u8; 1024]; - let _ = socket.read(&mut buf).await; - let response = b"HTTP/1.1 503 Service Unavailable\r\ncontent-length: 0\r\n\r\n"; - let _ = socket.write_all(response).await; - }); - let client = Client::new(); - let response = client - .get(format!("http://{addr}")) - .send() - .await - .expect("send"); - let err = response.error_for_status().expect_err("status error"); - let app_err: Error = err.into(); + let server = MockServer::with_response( + b"HTTP/1.1 503 Service Unavailable\r\ncontent-length: 0\r\n\r\n" + ) + .await; + let app_err = status_error_from(&server).await; assert_eq!(app_err.kind, AppErrorKind::DependencyUnavailable); - server.abort(); } } diff --git a/src/convert/sqlx.rs b/src/convert/sqlx.rs index 09ddecb..5c00ebb 100644 --- a/src/convert/sqlx.rs +++ b/src/convert/sqlx.rs @@ -46,7 +46,15 @@ use sqlx_core::error::{DatabaseError, Error as SqlxError, ErrorKind as SqlxError #[cfg(any(feature = "sqlx", feature = "sqlx-migrate"))] use crate::{AppCode, AppErrorKind, Context, Error, field}; -#[cfg(feature = "sqlx")] +#[cfg(all(feature = "sqlx", feature = "phf"))] +static SQLSTATE_CODE_OVERRIDES: phf::Map<&'static str, AppCode> = phf::phf_map! { + "23505" => AppCode::UserAlreadyExists, + "23503" => AppCode::Conflict, + "23502" => AppCode::Validation, + "23514" => AppCode::Validation, +}; + +#[cfg(all(feature = "sqlx", not(feature = "phf")))] const SQLSTATE_CODE_OVERRIDES: &[(&str, AppCode)] = &[ ("23505", AppCode::UserAlreadyExists), ("23503", AppCode::Conflict), @@ -54,7 +62,13 @@ const SQLSTATE_CODE_OVERRIDES: &[(&str, AppCode)] = &[ ("23514", AppCode::Validation) ]; -#[cfg(feature = "sqlx")] +#[cfg(all(feature = "sqlx", feature = "phf"))] +static SQLSTATE_RETRY_HINTS: phf::Map<&'static str, u64> = phf::phf_map! { + "40001" => 1, + "55P03" => 1, +}; + +#[cfg(all(feature = "sqlx", not(feature = "phf")))] const SQLSTATE_RETRY_HINTS: &[(&str, u64)] = &[("40001", 1), ("55P03", 1)]; /// Map a `sqlx_core::error::Error` into [`struct@crate::Error`]. @@ -220,17 +234,29 @@ fn classify_database_error(error: &(dyn DatabaseError + 'static)) -> (Context, O let code = error.code().map(|code| code.into_owned()); if let Some(ref sqlstate) = code { context = context.with(field::str("db.code", sqlstate.clone())); - if let Some((_, secs)) = SQLSTATE_RETRY_HINTS - .iter() - .find(|(state, _)| *state == sqlstate.as_str()) + #[cfg(feature = "phf")] { - retry_after = Some(*secs); + if let Some(&secs) = SQLSTATE_RETRY_HINTS.get(sqlstate.as_str()) { + retry_after = Some(secs); + } + if let Some(app_code) = SQLSTATE_CODE_OVERRIDES.get(sqlstate.as_str()) { + code_override = Some(app_code.clone()); + } } - if let Some((_, app_code)) = SQLSTATE_CODE_OVERRIDES - .iter() - .find(|(state, _)| *state == sqlstate.as_str()) + #[cfg(not(feature = "phf"))] { - code_override = Some(app_code.clone()); + if let Some((_, secs)) = SQLSTATE_RETRY_HINTS + .iter() + .find(|(state, _)| *state == sqlstate.as_str()) + { + retry_after = Some(*secs); + } + if let Some((_, app_code)) = SQLSTATE_CODE_OVERRIDES + .iter() + .find(|(state, _)| *state == sqlstate.as_str()) + { + code_override = Some(app_code.clone()); + } } } let category = match error.kind() { @@ -419,4 +445,286 @@ mod tests_sqlx { } } } + + #[test] + fn pool_timed_out_maps_to_timeout() { + let err: Error = SqlxError::PoolTimedOut.into(); + assert_eq!(err.kind, AppErrorKind::Timeout); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("pool_timeout".into())) + ); + assert_eq!(err.retry.map(|r| r.after_seconds), Some(1)); + } + + #[test] + fn pool_closed_maps_to_dependency_unavailable() { + let err: Error = SqlxError::PoolClosed.into(); + assert_eq!(err.kind, AppErrorKind::DependencyUnavailable); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("pool_closed".into())) + ); + } + + #[test] + fn worker_crashed_maps_to_dependency_unavailable() { + let err: Error = SqlxError::WorkerCrashed.into(); + assert_eq!(err.kind, AppErrorKind::DependencyUnavailable); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("worker_crashed".into())) + ); + assert_eq!(err.retry.map(|r| r.after_seconds), Some(1)); + } + + #[test] + fn configuration_maps_to_config() { + let err: Error = + SqlxError::Configuration(Box::new(std::io::Error::other("bad config"))).into(); + assert_eq!(err.kind, AppErrorKind::Config); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("configuration".into())) + ); + } + + #[test] + fn invalid_argument_maps_to_bad_request() { + let err: Error = SqlxError::InvalidArgument("wrong arg".into()).into(); + assert_eq!(err.kind, AppErrorKind::BadRequest); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("invalid_argument".into())) + ); + assert_eq!( + err.metadata().get("db.argument"), + Some(&FieldValue::Str("wrong arg".into())) + ); + } + + #[test] + fn column_decode_maps_to_deserialization() { + let err: Error = SqlxError::ColumnDecode { + index: "col1".into(), + source: Box::new(std::io::Error::other("decode failed")) + } + .into(); + assert_eq!(err.kind, AppErrorKind::Deserialization); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("column_decode".into())) + ); + assert_eq!( + err.metadata().get("db.column"), + Some(&FieldValue::Str("col1".into())) + ); + } + + #[test] + fn column_not_found_maps_to_internal() { + let err: Error = SqlxError::ColumnNotFound("missing_col".into()).into(); + assert_eq!(err.kind, AppErrorKind::Internal); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("column_not_found".into())) + ); + assert_eq!( + err.metadata().get("db.column"), + Some(&FieldValue::Str("missing_col".into())) + ); + } + + #[test] + fn column_index_out_of_bounds_maps_to_internal() { + let err: Error = SqlxError::ColumnIndexOutOfBounds { + index: 5, len: 3 + } + .into(); + assert_eq!(err.kind, AppErrorKind::Internal); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("column_index_out_of_bounds".into())) + ); + assert_eq!(err.metadata().get("db.index"), Some(&FieldValue::U64(5))); + assert_eq!(err.metadata().get("db.len"), Some(&FieldValue::U64(3))); + } + + #[test] + fn type_not_found_maps_to_internal() { + let err: Error = SqlxError::TypeNotFound { + type_name: "custom_type".into() + } + .into(); + assert_eq!(err.kind, AppErrorKind::Internal); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("type_not_found".into())) + ); + assert_eq!( + err.metadata().get("db.type"), + Some(&FieldValue::Str("custom_type".into())) + ); + } + + #[test] + fn encode_maps_to_serialization() { + let err: Error = + SqlxError::Encode(Box::new(std::io::Error::other("encode failed"))).into(); + assert_eq!(err.kind, AppErrorKind::Serialization); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("encode".into())) + ); + } + + #[test] + fn decode_maps_to_deserialization() { + let err: Error = + SqlxError::Decode(Box::new(std::io::Error::other("decode failed"))).into(); + assert_eq!(err.kind, AppErrorKind::Deserialization); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("decode".into())) + ); + } + + #[test] + fn protocol_maps_to_dependency_unavailable() { + let err: Error = SqlxError::Protocol("protocol error".into()).into(); + assert_eq!(err.kind, AppErrorKind::DependencyUnavailable); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("protocol".into())) + ); + assert_eq!(err.retry.map(|r| r.after_seconds), Some(1)); + } + + #[test] + fn tls_maps_to_network() { + let err: Error = SqlxError::Tls(Box::new(std::io::Error::other("tls failed"))).into(); + assert_eq!(err.kind, AppErrorKind::Network); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("tls".into())) + ); + assert_eq!(err.retry.map(|r| r.after_seconds), Some(1)); + } + + #[test] + fn any_driver_error_maps_to_database() { + let err: Error = + SqlxError::AnyDriverError(Box::new(std::io::Error::other("driver error"))).into(); + assert_eq!(err.kind, AppErrorKind::Database); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("driver_error".into())) + ); + } + + #[test] + fn invalid_savepoint_maps_to_internal() { + let err: Error = SqlxError::InvalidSavePointStatement.into(); + assert_eq!(err.kind, AppErrorKind::Internal); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("invalid_savepoint".into())) + ); + } + + #[test] + fn begin_failed_maps_to_dependency_unavailable() { + let err: Error = SqlxError::BeginFailed.into(); + assert_eq!(err.kind, AppErrorKind::DependencyUnavailable); + assert_eq!( + err.metadata().get("db.reason"), + Some(&FieldValue::Str("begin_failed".into())) + ); + assert_eq!(err.retry.map(|r| r.after_seconds), Some(1)); + } + + #[test] + fn foreign_key_violation_maps_to_conflict() { + let db_err = DummyDbError { + message: "foreign key violation".into(), + code: Some("23503".into()), + constraint: Some("fk_user".into()), + table: Some("orders".into()), + kind: SqlxErrorKind::ForeignKeyViolation + }; + let err: Error = SqlxError::Database(Box::new(db_err)).into(); + assert_eq!(err.kind, AppErrorKind::Conflict); + assert_eq!(err.code, AppCode::Conflict); + } + + #[test] + fn not_null_violation_maps_to_validation() { + let db_err = DummyDbError { + message: "not null violation".into(), + code: Some("23502".into()), + constraint: None, + table: None, + kind: SqlxErrorKind::NotNullViolation + }; + let err: Error = SqlxError::Database(Box::new(db_err)).into(); + assert_eq!(err.kind, AppErrorKind::Validation); + assert_eq!(err.code, AppCode::Validation); + } + + #[test] + fn check_violation_maps_to_validation() { + let db_err = DummyDbError { + message: "check violation".into(), + code: Some("23514".into()), + constraint: Some("positive_amount".into()), + table: None, + kind: SqlxErrorKind::CheckViolation + }; + let err: Error = SqlxError::Database(Box::new(db_err)).into(); + assert_eq!(err.kind, AppErrorKind::Validation); + assert_eq!(err.code, AppCode::Validation); + } + + #[test] + fn lock_not_available_carries_retry_hint() { + let db_err = DummyDbError { + message: "lock not available".into(), + code: Some("55P03".into()), + constraint: None, + table: None, + kind: SqlxErrorKind::Other + }; + let err: Error = SqlxError::Database(Box::new(db_err)).into(); + assert_eq!(err.retry.map(|r| r.after_seconds), Some(1)); + } + + #[test] + fn database_error_without_code() { + let db_err = DummyDbError { + message: "unknown error".into(), + code: None, + constraint: None, + table: None, + kind: SqlxErrorKind::Other + }; + let err: Error = SqlxError::Database(Box::new(db_err)).into(); + assert_eq!(err.kind, AppErrorKind::Database); + assert!(err.metadata().get("db.code").is_none()); + } + + #[test] + fn database_error_captures_table() { + let db_err = DummyDbError { + message: "error".into(), + code: None, + constraint: None, + table: Some("users".into()), + kind: SqlxErrorKind::Other + }; + let err: Error = SqlxError::Database(Box::new(db_err)).into(); + assert_eq!( + err.metadata().get("db.table"), + Some(&FieldValue::Str("users".into())) + ); + } } diff --git a/src/convert/tokio.rs b/src/convert/tokio.rs index 03713cb..7b5c92b 100644 --- a/src/convert/tokio.rs +++ b/src/convert/tokio.rs @@ -83,13 +83,17 @@ mod tests { use super::*; use crate::{AppErrorKind, FieldValue}; - #[tokio::test] - async fn elapsed_maps_to_timeout() { + async fn make_timeout_error() -> Error { let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) + timeout(Duration::from_millis(1), fut) .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + .expect_err("expect timeout") + .into() + } + + #[tokio::test] + async fn elapsed_maps_to_timeout() { + let app_err = make_timeout_error().await; assert!(matches!(app_err.kind, AppErrorKind::Timeout)); assert_eq!( app_err.metadata().get("timeout.source"), @@ -99,62 +103,37 @@ mod tests { #[tokio::test] async fn elapsed_conversion_preserves_source() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + let app_err = make_timeout_error().await; assert!(app_err.source().is_some()); } #[tokio::test] async fn elapsed_error_display() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + let app_err = make_timeout_error().await; let display = format!("{}", app_err); assert!(!display.is_empty()); } #[tokio::test] async fn elapsed_error_debug() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + let app_err = make_timeout_error().await; let debug = format!("{:?}", app_err); assert!(debug.contains("Timeout")); } #[tokio::test] async fn elapsed_metadata_contains_source_field() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); - let metadata = app_err.metadata(); + let app_err = make_timeout_error().await; assert_eq!( - metadata.get("timeout.source"), + app_err.metadata().get("timeout.source"), Some(&FieldValue::Str("tokio::time::timeout".into())) ); } #[tokio::test] async fn multiple_elapsed_errors_convert_consistently() { - let fut1 = sleep(Duration::from_millis(20)); - let err1 = timeout(Duration::from_millis(1), fut1) - .await - .expect_err("expect timeout"); - let app_err1: Error = err1.into(); - let fut2 = sleep(Duration::from_millis(30)); - let err2 = timeout(Duration::from_millis(1), fut2) - .await - .expect_err("expect timeout"); - let app_err2: Error = err2.into(); + let app_err1 = make_timeout_error().await; + let app_err2 = make_timeout_error().await; assert!(matches!(app_err1.kind, AppErrorKind::Timeout)); assert!(matches!(app_err2.kind, AppErrorKind::Timeout)); assert_eq!( @@ -165,21 +144,13 @@ mod tests { #[tokio::test] async fn elapsed_kind_is_exactly_timeout() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + let app_err = make_timeout_error().await; assert_eq!(app_err.kind, AppErrorKind::Timeout); } #[tokio::test] async fn elapsed_source_is_elapsed_type() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + let app_err = make_timeout_error().await; let source = app_err.source().expect("source should exist"); assert!(source.is::()); } @@ -196,11 +167,7 @@ mod tests { #[tokio::test] async fn elapsed_error_implements_std_error() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + let app_err = make_timeout_error().await; let _: &dyn StdError = &app_err; } @@ -216,11 +183,7 @@ mod tests { #[tokio::test] async fn elapsed_metadata_is_not_empty() { - let fut = sleep(Duration::from_millis(20)); - let err = timeout(Duration::from_millis(1), fut) - .await - .expect_err("expect timeout"); - let app_err: Error = err.into(); + let app_err = make_timeout_error().await; assert!(!app_err.metadata().is_empty()); } } diff --git a/src/convert/validator.rs b/src/convert/validator.rs index 601d57c..fa0118c 100644 --- a/src/convert/validator.rs +++ b/src/convert/validator.rs @@ -124,6 +124,16 @@ mod tests { val: i32 } + #[derive(Validate)] + struct MultiField { + #[validate(length(min = 5))] + name: String, + #[validate(range(min = 0, max = 100))] + age: i32, + #[validate(email)] + email: String + } + #[test] fn validation_errors_map_to_validation_kind() { let bad = Payload { @@ -137,4 +147,131 @@ mod tests { Some(&FieldValue::U64(1)) ); } + + #[test] + fn multiple_field_errors_captured() { + let bad = MultiField { + name: "abc".into(), + age: -1, + email: "not-an-email".into() + }; + let validation_errors = bad.validate().unwrap_err(); + let err: Error = validation_errors.into(); + assert!(matches!(err.kind, AppErrorKind::Validation)); + let metadata = err.metadata(); + assert_eq!( + metadata.get("validation.field_count"), + Some(&FieldValue::U64(3)) + ); + assert_eq!( + metadata.get("validation.error_count"), + Some(&FieldValue::U64(3)) + ); + } + + #[test] + fn validation_fields_metadata_present() { + let bad = MultiField { + name: "ab".into(), + age: 200, + email: "bad".into() + }; + let validation_errors = bad.validate().unwrap_err(); + let err: Error = validation_errors.into(); + let metadata = err.metadata(); + let fields = metadata.get("validation.fields"); + assert!(fields.is_some()); + if let Some(FieldValue::Str(fields_str)) = fields { + assert!( + fields_str.contains("name") + || fields_str.contains("age") + || fields_str.contains("email") + ); + } + } + + #[test] + fn validation_codes_metadata_present() { + let bad = Payload { + val: -5 + }; + let validation_errors = bad.validate().unwrap_err(); + let err: Error = validation_errors.into(); + let metadata = err.metadata(); + assert!(metadata.get("validation.codes").is_some()); + } + + #[test] + fn error_preserves_source() { + let bad = Payload { + val: 0 + }; + let validation_errors = bad.validate().unwrap_err(); + let err: Error = validation_errors.into(); + assert!(err.source_ref().is_some()); + } + + #[test] + fn single_field_error_has_correct_count() { + let bad = Payload { + val: 0 + }; + let validation_errors = bad.validate().unwrap_err(); + let err: Error = validation_errors.into(); + let metadata = err.metadata(); + assert_eq!( + metadata.get("validation.error_count"), + Some(&FieldValue::U64(1)) + ); + } + + #[test] + fn fields_truncated_to_three() { + use validator::{ValidationError, ValidationErrors}; + let mut errors = ValidationErrors::new(); + errors.add("field1", ValidationError::new("required")); + errors.add("field2", ValidationError::new("required")); + errors.add("field3", ValidationError::new("required")); + errors.add("field4", ValidationError::new("required")); + let err: Error = errors.into(); + let metadata = err.metadata(); + if let Some(FieldValue::Str(fields)) = metadata.get("validation.fields") { + let count = fields.split(',').count(); + assert!(count <= 3); + } + } + + #[test] + fn codes_truncated_to_three() { + use validator::{ValidationError, ValidationErrors}; + let mut errors = ValidationErrors::new(); + let err1 = ValidationError::new("code1"); + let err2 = ValidationError::new("code2"); + let err3 = ValidationError::new("code3"); + let err4 = ValidationError::new("code4"); + errors.add("field1", err1); + errors.add("field2", err2); + errors.add("field3", err3); + errors.add("field4", err4); + let app_err: Error = errors.into(); + let metadata = app_err.metadata(); + if let Some(FieldValue::Str(codes)) = metadata.get("validation.codes") { + let count = codes.split(',').count(); + assert!(count <= 3); + } + } + + #[test] + fn duplicate_codes_filtered() { + use validator::{ValidationError, ValidationErrors}; + let mut errors = ValidationErrors::new(); + errors.add("field1", ValidationError::new("required")); + errors.add("field2", ValidationError::new("required")); + errors.add("field3", ValidationError::new("required")); + let err: Error = errors.into(); + let metadata = err.metadata(); + if let Some(FieldValue::Str(codes)) = metadata.get("validation.codes") { + assert_eq!(codes.as_ref(), "required"); + } + } } diff --git a/src/error.rs b/src/error.rs index 9a3d13c..0c19db8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -113,4 +113,6 @@ //! ``` /// Parser and formatter helpers for `#[error("...")]` templates. +#[cfg(feature = "derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub mod template; diff --git a/src/kind.rs b/src/kind.rs index 821dfc2..dbb865e 100644 --- a/src/kind.rs +++ b/src/kind.rs @@ -359,4 +359,116 @@ mod tests { let output = BadRequest.to_string(); assert!(output.contains("Bad request")); } + + #[test] + fn http_status_all_variants() { + assert_eq!(NotFound.http_status(), 404); + assert_eq!(Validation.http_status(), 422); + assert_eq!(Conflict.http_status(), 409); + assert_eq!(Unauthorized.http_status(), 401); + assert_eq!(Forbidden.http_status(), 403); + assert_eq!(NotImplemented.http_status(), 501); + assert_eq!(Internal.http_status(), 500); + assert_eq!(BadRequest.http_status(), 400); + assert_eq!(TelegramAuth.http_status(), 401); + assert_eq!(InvalidJwt.http_status(), 401); + assert_eq!(Database.http_status(), 500); + assert_eq!(Service.http_status(), 500); + assert_eq!(Config.http_status(), 500); + assert_eq!(Turnkey.http_status(), 500); + assert_eq!(Timeout.http_status(), 504); + assert_eq!(Network.http_status(), 503); + assert_eq!(RateLimited.http_status(), 429); + assert_eq!(DependencyUnavailable.http_status(), 503); + assert_eq!(Serialization.http_status(), 500); + assert_eq!(Deserialization.http_status(), 500); + assert_eq!(ExternalApi.http_status(), 500); + assert_eq!(Queue.http_status(), 500); + assert_eq!(Cache.http_status(), 500); + } + + #[test] + fn label_all_variants() { + assert_eq!(NotFound.label(), "Not found"); + assert_eq!(Validation.label(), "Validation error"); + assert_eq!(Conflict.label(), "Conflict"); + assert_eq!(Unauthorized.label(), "Unauthorized"); + assert_eq!(Forbidden.label(), "Forbidden"); + assert_eq!(NotImplemented.label(), "Not implemented"); + assert_eq!(Internal.label(), "Internal server error"); + assert_eq!(BadRequest.label(), "Bad request"); + assert_eq!(TelegramAuth.label(), "Telegram authentication error"); + assert_eq!(InvalidJwt.label(), "Invalid JWT"); + assert_eq!(Database.label(), "Database error"); + assert_eq!(Service.label(), "Service error"); + assert_eq!(Config.label(), "Configuration error"); + assert_eq!(Turnkey.label(), "Turnkey error"); + assert_eq!(Timeout.label(), "Operation timed out"); + assert_eq!(Network.label(), "Network error"); + assert_eq!(RateLimited.label(), "Rate limit exceeded"); + assert_eq!( + DependencyUnavailable.label(), + "External dependency unavailable" + ); + assert_eq!(Serialization.label(), "Serialization error"); + assert_eq!(Deserialization.label(), "Deserialization error"); + assert_eq!(ExternalApi.label(), "External API error"); + assert_eq!(Queue.label(), "Queue processing error"); + assert_eq!(Cache.label(), "Cache error"); + } + + #[test] + fn display_all_variants() { + assert_eq!(NotFound.to_string(), NotFound.label()); + assert_eq!(Validation.to_string(), Validation.label()); + assert_eq!(Conflict.to_string(), Conflict.label()); + assert_eq!(Unauthorized.to_string(), Unauthorized.label()); + assert_eq!(Forbidden.to_string(), Forbidden.label()); + assert_eq!(NotImplemented.to_string(), NotImplemented.label()); + assert_eq!(Internal.to_string(), Internal.label()); + assert_eq!(BadRequest.to_string(), BadRequest.label()); + assert_eq!(TelegramAuth.to_string(), TelegramAuth.label()); + assert_eq!(InvalidJwt.to_string(), InvalidJwt.label()); + assert_eq!(Database.to_string(), Database.label()); + assert_eq!(Service.to_string(), Service.label()); + assert_eq!(Config.to_string(), Config.label()); + assert_eq!(Turnkey.to_string(), Turnkey.label()); + assert_eq!(Timeout.to_string(), Timeout.label()); + assert_eq!(Network.to_string(), Network.label()); + assert_eq!(RateLimited.to_string(), RateLimited.label()); + assert_eq!( + DependencyUnavailable.to_string(), + DependencyUnavailable.label() + ); + assert_eq!(Serialization.to_string(), Serialization.label()); + assert_eq!(Deserialization.to_string(), Deserialization.label()); + assert_eq!(ExternalApi.to_string(), ExternalApi.label()); + assert_eq!(Queue.to_string(), Queue.label()); + assert_eq!(Cache.to_string(), Cache.label()); + } + + #[test] + fn error_trait_impl() { + use core::error::Error; + let kind = Internal; + let err: &dyn Error = &kind; + assert!(err.source().is_none()); + } + + #[test] + fn clone_and_copy() { + let kind1 = Internal; + let kind2 = kind1; + let kind3 = kind1; + assert_eq!(kind1, kind2); + assert_eq!(kind2, kind3); + } + + #[test] + fn debug_format() { + let debug_str = format!("{:?}", Internal); + assert_eq!(debug_str, "Internal"); + let debug_str = format!("{:?}", NotFound); + assert_eq!(debug_str, "NotFound"); + } } diff --git a/src/lib.rs b/src/lib.rs index e086186..221bde3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-FileCopyrightText: 2025-2026 RAprogramm // // SPDX-License-Identifier: MIT @@ -371,6 +371,14 @@ pub mod turnkey; #[cfg_attr(docsrs, doc(cfg(feature = "colored")))] pub mod colored; +/// Rust compiler error explanations and best practices. +/// +/// Provides structured knowledge base for understanding compiler errors +/// with translations (en/ru/ko) and actionable fix suggestions. +#[cfg(feature = "knowledge")] +#[cfg_attr(docsrs, doc(cfg(feature = "knowledge")))] +pub use masterror_knowledge as knowledge; + /// Minimal prelude re-exporting core types for handler signatures. pub mod prelude; @@ -378,9 +386,14 @@ pub mod prelude; pub mod mapping; pub use app_error::{ - AppError, AppResult, Context, DisplayMode, Error, ErrorChain, Field, FieldRedaction, - FieldValue, MessageEditPolicy, Metadata, field + AppError, AppResult, Context, DiagnosticVisibility, Diagnostics, DisplayMode, DocLink, Error, + ErrorChain, Field, FieldRedaction, FieldValue, Hint, MessageEditPolicy, Metadata, Suggestion, + field }; +/// Diagnostic types for enhanced error reporting. +pub mod diagnostics { + pub use crate::app_error::diagnostics::*; +} pub use code::{AppCode, ParseAppCodeError}; pub use kind::AppErrorKind; /// Re-export derive macros so users only depend on this crate. @@ -409,6 +422,8 @@ pub use kind::AppErrorKind; /// .into(); /// assert_eq!(code, AppCode::BadRequest); /// ``` +#[cfg(feature = "derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use masterror_derive::{Error, Masterror}; pub use response::{ ErrorResponse, ProblemJson, RetryAdvice, diff --git a/src/response/core.rs b/src/response/core.rs index f605458..c046b1e 100644 --- a/src/response/core.rs +++ b/src/response/core.rs @@ -68,8 +68,11 @@ impl ErrorResponse { /// Returns [`AppError`] if `status` is not a valid HTTP status code. #[allow(clippy::result_large_err)] pub fn new(status: u16, code: AppCode, message: impl Into) -> AppResult { - StatusCode::from_u16(status) - .map_err(|_| AppError::bad_request(format!("invalid HTTP status: {status}")))?; + let Ok(_) = StatusCode::from_u16(status) else { + return Err(AppError::bad_request(format!( + "invalid HTTP status: {status}" + ))); + }; Ok(Self { status, code, diff --git a/src/response/details.rs b/src/response/details.rs index 8a2647d..bc72970 100644 --- a/src/response/details.rs +++ b/src/response/details.rs @@ -66,12 +66,12 @@ impl ErrorResponse { where T: Serialize { - let details = to_value(payload).map_err(|e| AppError::bad_request(e.to_string()))?; + let Ok(details) = to_value(payload) else { + return Err(AppError::bad_request("failed to serialize details")); + }; Ok(self.with_details_json(details)) } } -#[cfg(feature = "serde_json")] -use alloc::string::ToString; #[cfg(test)] mod tests { diff --git a/src/response/tests.rs b/src/response/tests.rs index 94d00f9..eae263a 100644 --- a/src/response/tests.rs +++ b/src/response/tests.rs @@ -730,3 +730,171 @@ fn from_borrowed_app_error_redacts_message() { assert!(!resp.message.contains("secret123")); assert_eq!(err.message.as_deref(), Some("database password: secret123")); } + +// --- ProblemJson tests ------------------------------------------------------- + +#[test] +fn problem_json_from_error_response_empty_message() { + let resp = ErrorResponse::new(500, AppCode::Internal, "").expect("status"); + let problem = ProblemJson::from_error_response(resp); + assert!(problem.detail.is_none()); +} + +#[test] +fn problem_json_from_error_response_with_message() { + let resp = ErrorResponse::new(404, AppCode::NotFound, "user not found").expect("status"); + let problem = ProblemJson::from_error_response(resp); + assert_eq!(problem.detail.as_deref(), Some("user not found")); +} + +#[test] +fn problem_json_status_code_valid() { + let problem = ProblemJson::from_app_error(AppError::not_found("missing")); + assert_eq!(problem.status_code(), http::StatusCode::NOT_FOUND); +} + +#[test] +fn problem_json_grpc_code() { + let problem = ProblemJson::from_app_error(AppError::not_found("missing")); + assert!(problem.grpc.is_some()); + let grpc = problem.grpc.unwrap(); + assert_eq!(grpc.name, "NOT_FOUND"); + assert_eq!(grpc.value, 5); +} + +#[test] +fn problem_json_type_uri() { + let problem = ProblemJson::from_app_error(AppError::not_found("missing")); + assert!(problem.type_uri.is_some()); + assert!(problem.type_uri.unwrap().contains("not-found")); +} + +#[test] +fn problem_json_with_metadata() { + use crate::field; + let err = AppError::service("failed").with_field(field::u64("attempt", 3)); + let problem = ProblemJson::from_app_error(err); + assert!(problem.metadata.is_some()); +} + +#[test] +fn problem_json_with_redacted_metadata() { + use crate::field; + let err = AppError::internal("error") + .with_field(field::str("password", "secret")) + .with_field(field::str("user", "john")); + let problem = ProblemJson::from_app_error(err); + assert!(problem.metadata.is_some()); +} + +#[test] +fn problem_json_redacts_metadata_when_redactable() { + use crate::field; + let err = AppError::internal("error") + .with_field(field::str("data", "value")) + .redactable(); + let problem = ProblemJson::from_app_error(err); + assert!(problem.metadata.is_none()); + assert!(problem.detail.is_none()); +} + +#[test] +fn problem_json_from_ref_with_retry() { + let err = AppError::rate_limited("slow down").with_retry_after_secs(60); + let problem = ProblemJson::from_ref(&err); + assert_eq!(problem.retry_after, Some(60)); +} + +#[test] +fn problem_json_from_ref_with_www_authenticate() { + let err = AppError::unauthorized("need auth").with_www_authenticate("Bearer"); + let problem = ProblemJson::from_ref(&err); + assert_eq!(problem.www_authenticate.as_deref(), Some("Bearer")); +} + +#[test] +fn problem_json_metadata_hash_redaction() { + use crate::field; + let mut err = AppError::service("test"); + err = err.with_field(field::str("api_token", "secret_token_value")); + let problem = ProblemJson::from_app_error(err); + let metadata = problem.metadata.expect("metadata"); + let serialized = serde_json::to_string(&metadata).expect("serialize"); + assert!(!serialized.contains("secret_token_value")); +} + +#[test] +fn problem_json_metadata_last4_redaction() { + use crate::field; + let err = AppError::service("test").with_field(field::str("card_number", "4111111111111111")); + let problem = ProblemJson::from_app_error(err); + let metadata = problem.metadata.expect("metadata"); + let serialized = serde_json::to_string(&metadata).expect("serialize"); + assert!(serialized.contains("1111")); + assert!(!serialized.contains("4111111111111111")); +} + +#[test] +fn problem_json_internal_formatter() { + let problem = ProblemJson::from_app_error(AppError::not_found("user")); + let internal = problem.internal(); + let debug = format!("{:?}", internal); + assert!(debug.contains("ProblemJson")); +} + +#[test] +fn problem_metadata_value_from_field_value() { + use std::{borrow::Cow, net::IpAddr, time::Duration}; + + use uuid::Uuid; + + use crate::{FieldValue, ProblemMetadataValue}; + + let str_val = ProblemMetadataValue::from(FieldValue::Str(Cow::Borrowed("test"))); + assert!(matches!(str_val, ProblemMetadataValue::String(_))); + + let i64_val = ProblemMetadataValue::from(FieldValue::I64(-42)); + assert!(matches!(i64_val, ProblemMetadataValue::I64(-42))); + + let u64_val = ProblemMetadataValue::from(FieldValue::U64(100)); + assert!(matches!(u64_val, ProblemMetadataValue::U64(100))); + + let f64_val = ProblemMetadataValue::from(FieldValue::F64(1.5)); + assert!(matches!(f64_val, ProblemMetadataValue::F64(_))); + + let bool_val = ProblemMetadataValue::from(FieldValue::Bool(true)); + assert!(matches!(bool_val, ProblemMetadataValue::Bool(true))); + + let uuid = Uuid::nil(); + let uuid_val = ProblemMetadataValue::from(FieldValue::Uuid(uuid)); + assert!(matches!(uuid_val, ProblemMetadataValue::String(_))); + + let dur_val = ProblemMetadataValue::from(FieldValue::Duration(Duration::from_secs(5))); + assert!(matches!(dur_val, ProblemMetadataValue::Duration { .. })); + + let ip: IpAddr = "127.0.0.1".parse().unwrap(); + let ip_val = ProblemMetadataValue::from(FieldValue::Ip(ip)); + assert!(matches!(ip_val, ProblemMetadataValue::Ip(_))); +} + +#[cfg(feature = "serde_json")] +#[test] +fn problem_metadata_value_from_json() { + use serde_json::json; + + use crate::{FieldValue, ProblemMetadataValue}; + + let json_val = ProblemMetadataValue::from(FieldValue::Json(json!({"key": "value"}))); + assert!(matches!(json_val, ProblemMetadataValue::Json(_))); +} + +#[test] +fn code_mapping_accessors() { + use crate::mapping_for_code; + let mapping = mapping_for_code(&AppCode::NotFound); + assert_eq!(mapping.http_status(), 404); + assert_eq!(mapping.kind(), AppErrorKind::NotFound); + assert!(mapping.problem_type().contains("not-found")); + let grpc = mapping.grpc(); + assert_eq!(grpc.name, "NOT_FOUND"); +} diff --git a/src/result_ext.rs b/src/result_ext.rs index afe9b65..638eeee 100644 --- a/src/result_ext.rs +++ b/src/result_ext.rs @@ -312,4 +312,64 @@ mod tests { assert_eq!(source.kind, AppErrorKind::BadRequest); assert_eq!(source.message.as_deref(), Some("missing flag")); } + + #[test] + fn context_with_owned_string() { + let result: Result<(), DummyError> = Err(DummyError); + let err = result + .context(String::from("owned message")) + .expect_err("err"); + assert_eq!(err.message.as_deref(), Some("owned message")); + } + + #[test] + fn context_preserves_www_authenticate() { + let base = Error::unauthorized("need auth").with_www_authenticate("Bearer realm=\"api\""); + let err = Result::<(), Error>::Err(base) + .context("auth context") + .expect_err("err"); + assert_eq!( + err.www_authenticate.as_deref(), + Some("Bearer realm=\"api\"") + ); + } + + #[test] + fn context_preserves_retry() { + let base = Error::service("retry later").with_retry_after_secs(30); + let err = Result::<(), Error>::Err(base) + .context("wrapped") + .expect_err("err"); + assert!(err.retry.is_some()); + assert_eq!(err.retry.unwrap().after_seconds, 30); + } + + #[cfg(feature = "serde_json")] + #[test] + fn context_preserves_details() { + let base = Error::internal("error").with_details_json(serde_json::json!({"key": "value"})); + let err = Result::<(), Error>::Err(base) + .context("wrapped") + .expect_err("err"); + assert!(err.details.is_some()); + } + + #[test] + fn ctx_with_custom_code() { + let result: Result<(), DummyError> = Err(DummyError); + let err = result + .ctx(|| Context::new(AppErrorKind::NotFound).code(AppCode::NotFound)) + .expect_err("err"); + assert_eq!(err.kind, AppErrorKind::NotFound); + assert_eq!(err.code, AppCode::NotFound); + } + + #[test] + fn ctx_with_category_change() { + let result: Result<(), DummyError> = Err(DummyError); + let err = result + .ctx(|| Context::new(AppErrorKind::Internal).category(AppErrorKind::Service)) + .expect_err("err"); + assert_eq!(err.kind, AppErrorKind::Service); + } }