diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0d9ef83..e71b004 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,42 +1,22 @@ # tuplities Copilot Instructions -## Architecture Overview -This is a Rust workspace providing tuple utilities. The project is split into three crates for improved compile times: +## Architecture -- `tuplities/`: Main crate that re-exports traits from subcrates -- `tuplities-{snake_trait_name}/`: One of several crates of the suite which provides the `Tuple{camel_trait_name}` trait with derive macro implementation -- `tuplities-derive/`: Procedural macro crate that generates all of the trait implementations for tuples of various sizes +The workspace contains one crate, `tuplities/`. Recursive utilities operate on `()`, singleton tuples `(T,)`, and nested pairs `(Head, Tail)`. -The derive macro generates implementations for tuples from size 0 (unit `()`) up to `MAX_TUPLE_SIZE`, controlled by Cargo features to balance functionality against compile time. +`tuplities/src/flat_bridge.rs` generates flat/nested boundary conversions through internal `macro_rules!` macros. The default flat limit is 8. Features `size-16`, `size-32`, `size-48`, `size-64`, `size-96`, and `size-128` select larger limits, with the largest enabled size taking precedence. -## Key Patterns - -- **Feature-gated sizes**: Use features like `size-16`, `size-32` to control maximum supported tuple size (default: 8). See `tuplities-derive/src/tuple_size.rs` for size configuration logic. -- **Procedural macro generation**: Implementations are generated using `generate_all_sizes()` function that iterates over tuple sizes. See `tuplities-derive/src/tuplities_clone.rs` for the pattern. -- **Type parameter generation**: Use `type_params()` and `indices()` helpers in `tuple_size.rs` for generating generic type lists and field access indices. - -## Developer Workflows -- Build all crates: `cargo build --workspace` -- Run tests: `cargo test --workspace` -- Enable larger tuple support: `cargo build --workspace --features size-32` (propagates to all crates) -- Debug macro expansion: `cargo expand --package tuplities-derive` - -## Code Examples -```rust -// Basic usage -use tuplities::prelude::TupleClone; - -let original = (1, "hello".to_string(), vec![1, 2, 3]); -let cloned = original.tuple_clone(); -assert_eq!(original, cloned); -``` +The crate is `no_std`. The `alloc` feature enables homogeneous vector conversion. The default `flatten-nest` feature enables flat tuple and matrix conversions and includes `alloc`. ## Conventions -- Strict linting: Workspace enforces `missing_docs = "forbid"` and extensive Clippy rules. Always document public APIs. -- Edition 2024: Use modern Rust features available in the 2024 edition. -- Workspace dependencies: Define shared deps in root `Cargo.toml` under `[workspace.dependencies]`. +- Use recursive trait implementations for nested tuple operations. +- Preserve public associated-type equalities used by downstream generic code. +- Keep shared dependencies under `[workspace.dependencies]`. +- Document public APIs and preserve the workspace's Rust and Clippy lints. +- The crate README provides crate-level documentation and executable doctests. +- Use Rust edition `2024` and support the declared minimum compiler. + +## Verification -## Integration Points -- External deps: `syn`, `quote`, `proc-macro2` for macro generation -- Cross-crate communication: Derive crate generates code used by clone crate, re-exported by main crate \ No newline at end of file +Scope checks to `-p tuplities`. Verify default features, `--no-default-features`, `alloc`, and supported flat width configurations. Exercise flat/nested round trips, mutable borrowing, and downstream behavior when changing the bridges. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 26e4d54..e58e908 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,3 +12,7 @@ updates: # The reference selects the Rust toolchain rather than the action version, # so Dependabot reads 1.85.0 as a release and offers a nonexistent 1.120.0. - dependency-name: dtolnay/rust-toolchain + - package-ecosystem: cargo + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6dd42f7..98878d1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,101 +2,118 @@ name: Rust CI on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] + workflow_dispatch: env: CARGO_TERM_COLOR: always + CARGO_BUILD_JOBS: "4" permissions: contents: read jobs: test: - name: Test + name: Tests (${{ matrix.os }}) runs-on: ${{ matrix.os }} + timeout-minutes: 30 strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - rust: [stable, beta, nightly] steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install Rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.rust }} - - name: Cache cargo registry - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo index - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo build - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - - name: Run tests - run: cargo test --verbose - - name: Run tests (release) - run: cargo test --release --verbose + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 + with: + toolchain: stable + - run: cargo test -p tuplities --locked + - run: cargo test -p tuplities --all-features --locked - fmt: - name: Rustfmt + quality: + name: Formatting, linting, and documentation runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - name: Check formatting - run: cargo fmt --all -- --check + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 + with: + toolchain: stable + components: rustfmt, clippy + - run: cargo fmt -p tuplities -- --check + - run: cargo clippy -p tuplities --all-targets --all-features --locked -- -D warnings + - run: cargo doc -p tuplities --no-deps --all-features --locked + env: + RUSTDOCFLAGS: -D warnings - clippy: - name: Clippy + msrv: + name: MSRV and no_std runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - components: clippy - - name: Run clippy - run: cargo clippy --all-targets -- -D warnings + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 + with: + toolchain: 1.85.0 + targets: thumbv7em-none-eabi + - run: cargo check -p tuplities --lib --all-features --locked + - run: cargo check -p tuplities --lib --no-default-features --locked + - run: cargo check -p tuplities --lib --no-default-features --target thumbv7em-none-eabi --locked - doc: - name: Documentation + features: + name: Features (${{ matrix.features || 'core' }}) runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + matrix: + features: + - "" + - alloc + - flatten-nest + - flatten-nest,size-16 + - flatten-nest,size-32 + - flatten-nest,size-48 + - flatten-nest,size-64 + - flatten-nest,size-96 + - flatten-nest,size-128 + - flatten-nest,size-16,size-32 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - - name: Check documentation - run: cargo doc --no-deps --document-private-items - env: - RUSTDOCFLAGS: -D warnings + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 + with: + toolchain: stable + - run: cargo test -p tuplities --no-default-features --features "$FEATURES" --locked + env: + FEATURES: ${{ matrix.features }} coverage: - name: Code Coverage + name: Coverage runs-on: ubuntu-latest + timeout-minutes: 30 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install Rust - uses: dtolnay/rust-toolchain@nightly - with: - components: llvm-tools-preview - - name: Install tarpaulin - uses: taiki-e/install-action@cargo-tarpaulin - - name: Generate coverage - run: cargo tarpaulin --engine=llvm --out xml --workspace --exclude tuplities-derive --run-types AllTargets --run-types Doctests - - name: Upload coverage to Codecov - uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: false + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 + with: + toolchain: nightly + components: llvm-tools-preview + - uses: taiki-e/install-action@e407f7bafb71fd004bc5c2da3032e5470cbb6ef0 + with: + tool: cargo-llvm-cov + fallback: none + - run: cargo llvm-cov -p tuplities --all-targets --all-features --locked --no-report + - run: cargo llvm-cov -p tuplities --doc --all-features --locked --no-clean --lcov --output-path target/coverage.lcov + - uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: target/coverage.lcov + fail_ci_if_error: false diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index bef6c39..d10286b 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -15,11 +15,14 @@ jobs: audit: name: Security Audit runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable + with: + persist-credentials: false - name: Install cargo-audit - run: cargo install cargo-audit - - name: Run security audit - run: cargo audit + uses: taiki-e/install-action@e407f7bafb71fd004bc5c2da3032e5470cbb6ef0 + with: + tool: cargo-audit + fallback: none + - run: cargo audit diff --git a/.github/workflows/workflow-validation.yml b/.github/workflows/workflow-validation.yml new file mode 100644 index 0000000..f7376ac --- /dev/null +++ b/.github/workflows/workflow-validation.yml @@ -0,0 +1,36 @@ +name: Workflow validation + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + validate: + name: Workflow validation + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Install workflow validators + uses: taiki-e/install-action@e407f7bafb71fd004bc5c2da3032e5470cbb6ef0 # v2.87.24 + with: + tool: shellcheck@0.11.0,zizmor@1.30.1 + fallback: none + - name: Install actionlint + run: | + curl --fail --location --max-time 120 --output "$RUNNER_TEMP/actionlint.tar.gz" \ + https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz + printf '%s %s\n' 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 \ + "$RUNNER_TEMP/actionlint.tar.gz" | sha256sum --check + tar --extract --gzip --file "$RUNNER_TEMP/actionlint.tar.gz" --directory "$RUNNER_TEMP" actionlint + - name: Validate workflows + run: '"$RUNNER_TEMP/actionlint"' + - name: Audit workflow security + run: zizmor --offline --strict-collection .github/workflows diff --git a/.gitignore b/.gitignore index 7d2b485..76fcd9d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,15 +9,9 @@ target # MSVC Windows builds of rustc generate these, which store debugging information *.pdb -# Generated by cargo mutants -# Contains mutation testing data -**/mutants.out*/ - # RustRover # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ -build_rs_cov.profraw -cobertura.xml \ No newline at end of file +#.idea/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b0ac589..905cb48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## Added in Unreleased +### `0.2.0` package contract -- `NestedTupleChain` trait for chaining two nested tuples together. -- `NestTupleRef` and `NestTupleMut` traits for converting flat tuples into nested tuples of references and mutable references, respectively. -- `NestedTupleFlattenOption` trait for flattening nested tuples of double options into nested tuples of options. +- One `tuplities` package provides recursive tuple utilities and flat tuple interoperability. +- The `flatten-nest` feature enables flat bridges and `alloc`. +- Flat widths are selected through the existing `size-N` features. +- `NestedTuple` provides structural membership and a compile-time element count. +- Recursive indexing and row access operate without flat tuple support or allocation. +- Declarative `neple!` and `neplety!` construct and name singleton-terminated lists. +- Recursive split, insert, remove, and linear-time reverse consume owned tuple nodes and preserve element types. +- The minimum supported Rust version is `1.85`. +- Public methods provide executable examples for result shapes, borrowed mutation, and conversion errors. +- `cargo llvm-cov` measures runtime targets and doctests. +- CI covers Rust `1.85.0`, allocator-free embedded builds, supported flat widths, and mixed features. +- `unsafe_code` is forbidden. ## [0.1.4] - 2025-12-15 diff --git a/Cargo.lock b/Cargo.lock index 3e741b1..9d1adf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,305 +2,15 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "syn" -version = "2.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "tuplities" -version = "0.1.4" -dependencies = [ - "tuplities-clone", - "tuplities-copy", - "tuplities-debug", - "tuplities-default", - "tuplities-eq", - "tuplities-flatten-nest", - "tuplities-from", - "tuplities-hash", - "tuplities-index", - "tuplities-insert", - "tuplities-len", - "tuplities-mut", - "tuplities-option", - "tuplities-ord", - "tuplities-partial-eq", - "tuplities-partial-ord", - "tuplities-pop-back", - "tuplities-pop-front", - "tuplities-push-back", - "tuplities-push-front", - "tuplities-ref", - "tuplities-remove", - "tuplities-replicate", - "tuplities-reverse", - "tuplities-row", - "tuplities-split", - "tuplities-try-from", -] - -[[package]] -name = "tuplities-clone" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-copy" -version = "0.1.4" -dependencies = [ - "tuplities-clone", - "tuplities-derive", -] - -[[package]] -name = "tuplities-debug" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-default" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-derive" -version = "0.1.4" -dependencies = [ - "proc-macro2", - "quote", - "siphasher", - "syn", - "typenum", -] - -[[package]] -name = "tuplities-eq" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-partial-eq", -] - -[[package]] -name = "tuplities-flatten-nest" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-push-front", - "typenum", -] - -[[package]] -name = "tuplities-from" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-hash" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-eq", -] - -[[package]] -name = "tuplities-index" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-len", - "typenum", -] - -[[package]] -name = "tuplities-insert" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "typenum", -] - -[[package]] -name = "tuplities-len" -version = "0.1.4" +version = "0.2.0" dependencies = [ - "tuplities-derive", "typenum", ] -[[package]] -name = "tuplities-mut" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-option" -version = "0.1.4" -dependencies = [ - "tuplities-default", - "tuplities-derive", -] - -[[package]] -name = "tuplities-ord" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-eq", - "tuplities-partial-ord", -] - -[[package]] -name = "tuplities-partial-eq" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-partial-ord" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-partial-eq", -] - -[[package]] -name = "tuplities-pop-back" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-pop-front" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-push-front", -] - -[[package]] -name = "tuplities-push-back" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-push-front" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-ref" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-remove" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "typenum", -] - -[[package]] -name = "tuplities-replicate" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-reverse" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - -[[package]] -name = "tuplities-row" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "tuplities-index", - "tuplities-len", - "tuplities-mut", - "tuplities-pop-back", - "tuplities-pop-front", - "tuplities-ref", - "typenum", -] - -[[package]] -name = "tuplities-split" -version = "0.1.4" -dependencies = [ - "tuplities-derive", - "typenum", -] - -[[package]] -name = "tuplities-try-from" -version = "0.1.4" -dependencies = [ - "tuplities-derive", -] - [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" diff --git a/Cargo.toml b/Cargo.toml index 57c937a..7151b9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,84 +1,24 @@ [workspace] resolver = "2" -members = [ - "tuplities", - "tuplities-clone", - "tuplities-copy", - "tuplities-debug", - "tuplities-default", - "tuplities-eq", - "tuplities-flatten-nest", - "tuplities-from", - "tuplities-hash", - "tuplities-index", - "tuplities-insert", - "tuplities-len", - "tuplities-mut", - "tuplities-option", - "tuplities-ord", - "tuplities-partial-eq", - "tuplities-partial-ord", - "tuplities-pop-back", - "tuplities-pop-front", - "tuplities-push-back", - "tuplities-push-front", - "tuplities-ref", - "tuplities-remove", - "tuplities-replicate", - "tuplities-reverse", - "tuplities-row", - "tuplities-split", - "tuplities-try-from", - "tuplities-derive", -] +members = ["tuplities"] [workspace.package] authors = ["Luca Cappelletti"] edition = "2024" description = "A collection of utilities for working with tuples in Rust." license = "MIT" -license-file = "LICENSE" repository = "https://github.com/lucacappelletti94/tuplities" -homepage = "https://github.com/lucacappelletti94/tuplities" keywords = ["tuples", "utilities", "metaprogramming", "typenum"] categories = ["development-tools", "data-structures"] -version = "0.1.4" -readme = "README.md" +version = "0.2.0" rust-version = "1.85" [workspace.dependencies] -tuplities-clone = { path = "tuplities-clone", version = "0.1.4" } -tuplities-copy = { path = "tuplities-copy", version = "0.1.4" } -tuplities-debug = { path = "tuplities-debug", version = "0.1.4" } -tuplities-default = { path = "tuplities-default", version = "0.1.4" } -tuplities-eq = { path = "tuplities-eq", version = "0.1.4" } -tuplities-flatten-nest = { path = "tuplities-flatten-nest", version = "0.1.4" } -tuplities-from = { path = "tuplities-from", version = "0.1.4" } -tuplities-hash = { path = "tuplities-hash", version = "0.1.4" } -tuplities-index = { path = "tuplities-index", version = "0.1.4" } -tuplities-insert = { path = "tuplities-insert", version = "0.1.4" } -tuplities-len = { path = "tuplities-len", version = "0.1.4" } -tuplities-mut = { path = "tuplities-mut", version = "0.1.4" } -tuplities-option = { path = "tuplities-option", version = "0.1.4" } -tuplities-ord = { path = "tuplities-ord", version = "0.1.4" } -tuplities-partial-eq = { path = "tuplities-partial-eq", version = "0.1.4" } -tuplities-partial-ord = { path = "tuplities-partial-ord", version = "0.1.4" } -tuplities-pop-back = { path = "tuplities-pop-back", version = "0.1.4" } -tuplities-pop-front = { path = "tuplities-pop-front", version = "0.1.4" } -tuplities-push-back = { path = "tuplities-push-back", version = "0.1.4" } -tuplities-push-front = { path = "tuplities-push-front", version = "0.1.4" } -tuplities-ref = { path = "tuplities-ref", version = "0.1.4" } -tuplities-remove = { path = "tuplities-remove", version = "0.1.4" } -tuplities-replicate = { path = "tuplities-replicate", version = "0.1.4" } -tuplities-reverse = { path = "tuplities-reverse", version = "0.1.4" } -tuplities-row = { path = "tuplities-row", version = "0.1.4" } -tuplities-split = { path = "tuplities-split", version = "0.1.4" } -tuplities-try-from = { path = "tuplities-try-from", version = "0.1.4" } -tuplities-derive = { path = "tuplities-derive", version = "0.1.4" } typenum = { version = "1" } [workspace.lints.rust] +unsafe_code = "forbid" missing_docs = "forbid" unused_macro_rules = "forbid" unconditional_recursion = "forbid" @@ -88,14 +28,9 @@ unused_must_use = "forbid" deprecated = "deny" [workspace.lints.clippy] -unreadable_literal = "allow" -missing_panics_doc = "allow" -new_ret_no_self = "allow" -struct_excessive_bools = "allow" -should_panic_without_expect = "allow" -doc_markdown = "allow" +missing_errors_doc = "forbid" +missing_panics_doc = "forbid" unnecessary_cast = "forbid" -unused_unit = "allow" redundant_clone = "forbid" clone_on_copy = "forbid" pedantic = { level = "deny", priority = -1 } diff --git a/README.md b/README.md index 983a47e..c04e4b3 100644 --- a/README.md +++ b/README.md @@ -1,290 +1,46 @@ # tuplities +[![Crates.io](https://img.shields.io/crates/v/tuplities.svg)](https://crates.io/crates/tuplities) [![Documentation](https://docs.rs/tuplities/badge.svg)](https://docs.rs/tuplities) [![CI](https://github.com/LucaCappelletti94/tuplities/workflows/Rust%20CI/badge.svg)](https://github.com/LucaCappelletti94/tuplities/actions) [![Security Audit](https://github.com/LucaCappelletti94/tuplities/workflows/Security%20Audit/badge.svg)](https://github.com/LucaCappelletti94/tuplities/actions) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![License MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Codecov](https://codecov.io/gh/LucaCappelletti94/tuplities/branch/main/graph/badge.svg)](https://codecov.io/gh/LucaCappelletti94/tuplities) -[![Downloads](https://img.shields.io/crates/d/tuplities.svg)](https://crates.io/crates/tuplities) -Tuple utilities in Rust, fractioned across several crates to improve compile times, providing several useful traits for both variadic programming with tuples as well as flat tuple manipulation. - -The main crate `tuplities` re-exports traits from subcrates in its `prelude` module, so that the subcrates may be compiled in parallel cutting down on overall build times. - -This library is `#[no_std]` compatible, making it suitable for embedded systems and other environments without the standard library. - -```toml -[dependencies] -tuplities = "0.1.4" -``` - -The library provides several traits for working with tuples: - -- [`TupleClone`](https://docs.rs/tuplities-clone/latest/tuplities_clone/trait.TupleClone.html): Provides a [`tuple_clone()`](https://docs.rs/tuplities-clone/latest/tuplities_clone/trait.TupleClone.html#tymethod.tuple_clone) method to clone tuples. All elements must implement `Clone`. -- [`TupleCopy`](https://docs.rs/tuplities-copy/latest/tuplities_copy/trait.TupleCopy.html): Provides a [`tuple_copy()`](https://docs.rs/tuplities-copy/latest/tuplities_copy/trait.TupleCopy.html#tymethod.tuple_copy) method to copy tuples. All elements must implement `Copy`. -- [`TupleDebug`](https://docs.rs/tuplities-debug/latest/tuplities_debug/trait.TupleDebug.html): Provides a [`tuple_debug()`](https://docs.rs/tuplities-debug/latest/tuplities_debug/trait.TupleDebug.html#tymethod.tuple_debug) method that returns a debug string representation of the tuple. All elements must implement `Debug`. -- [`TupleDefault`](https://docs.rs/tuplities-default/latest/tuplities_default/trait.TupleDefault.html): Provides a [`tuple_default()`](https://docs.rs/tuplities-default/latest/tuplities_default/trait.TupleDefault.html#tymethod.tuple_default) method to create default instances of tuples. All elements must implement `Default`. -- [`TupleReplicate`](https://docs.rs/tuplities-replicate/latest/tuplities_replicate/trait.TupleReplicate.html): Provides a [`tuple_replicate(value)`](https://docs.rs/tuplities-replicate/latest/tuplities_replicate/trait.TupleReplicate.html#tymethod.tuple_replicate) method to create tuples by replicating a single value across all positions. The value must implement `Clone` for tuples with 2+ elements, but not for empty tuples or single-element tuples. -- [`TupleHash`](https://docs.rs/tuplities-hash/latest/tuplities_hash/trait.TupleHash.html): Provides a [`tuple_hash()`](https://docs.rs/tuplities-hash/latest/tuplities_hash/trait.TupleHash.html#tymethod.tuple_hash) method to hash tuples with any hasher. All elements must implement `Hash`. -- [`TuplePartialEq`](https://docs.rs/tuplities-partial-eq/latest/tuplities_partial_eq/trait.TuplePartialEq.html): Provides a [`tuple_eq()`](https://docs.rs/tuplities-partial-eq/latest/tuplities_partial_eq/trait.TuplePartialEq.html#tymethod.tuple_eq) method to compare tuples for partial equality. All elements must implement `PartialEq`. -- [`TupleEq`](https://docs.rs/tuplities-eq/latest/tuplities_eq/trait.TupleEq.html): Provides a [`tuple_eq()`](https://docs.rs/tuplities-eq/latest/tuplities_eq/trait.TupleEq.html#tymethod.tuple_eq) method to compare tuples for total equality. All elements must implement `Eq`. -- [`TuplePartialOrd`](https://docs.rs/tuplities-partial-ord/latest/tuplities_partial_ord/trait.TuplePartialOrd.html): Provides a [`tuple_partial_cmp()`](https://docs.rs/tuplities-partial-ord/latest/tuplities_partial_ord/trait.TuplePartialOrd.html#tymethod.tuple_partial_cmp) method to compare tuples for partial ordering. All elements must implement `PartialOrd`. -- [`TupleOrd`](https://docs.rs/tuplities-ord/latest/tuplities_ord/trait.TupleOrd.html): Provides a [`tuple_cmp()`](https://docs.rs/tuplities-ord/latest/tuplities_ord/trait.TupleOrd.html#tymethod.tuple_cmp) method to compare tuples for total ordering. All elements must implement `Ord`. -- [`TupleOption`](https://docs.rs/tuplities-option/latest/tuplities_option/trait.TupleOption.html): Provides a [`transpose()`](https://docs.rs/tuplities-option/latest/tuplities_option/trait.TupleOption.html#tymethod.transpose) method to transpose a tuple of options into an option of a tuple. All elements must be `Option`. -- [`IntoTupleOption`](https://docs.rs/tuplities-option/latest/tuplities_option/trait.IntoTupleOption.html): Provides an [`into_options()`](https://docs.rs/tuplities-option/latest/tuplities_option/trait.IntoTupleOption.html#tymethod.into_options) method to convert a tuple into a tuple of options. -- [`NestedTupleOption`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOption.html): Provides a [`transpose()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOption.html#tymethod.transpose) method to transpose nested tuples of options into options of nested tuples. -- [`IntoNestedTupleOption`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.IntoNestedTupleOption.html): Provides an [`into_options()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.IntoNestedTupleOption.html#tymethod.into_options) method to convert nested tuples into nested tuples of options. -- [`NestedTupleFlattenOption`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleFlattenOption.html): Provides a [`flatten_options()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleFlattenOption.html#tymethod.flatten_options) method to flatten nested tuples of double options into nested tuples of options. -- [`NestedTupleOptionWith`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionWith.html): Provides `first_none_with`, `first_some_with`, and `transpose_or` helpers which operate with a parallel homogeneous nested tuple of `H` used for result/error mapping. -- [`NestedTupleTryFrom`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleTryFrom.html): Provides a [`nested_tuple_try_from()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleTryFrom.html#tymethod.nested_tuple_try_from) method to fallibly convert nested tuple types element-wise using `TryFrom` conversions. -- [`NestedTupleTryInto`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleTryInto.html): Provides a [`nested_tuple_try_into()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleTryInto.html#tymethod.nested_tuple_try_into) convenience method to perform fallible conversions using `NestedTupleTryFrom`. -- [`NestedTupleFrom`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleFrom.html): Provides an infallible [`nested_tuple_from()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleFrom.html#tymethod.nested_tuple_from) method to convert nested tuples using `From` element-wise. -- [`NestedTupleInto`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleInto.html): Provides an infallible [`nested_tuple_into()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleInto.html#tymethod.nested_tuple_into) convenience method to perform conversions using `NestedTupleFrom`. -- [`NestedTupleOptionFrom`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionFrom.html): Provides a [`nested_tuple_option_from()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionFrom.html#tymethod.nested_tuple_option_from) method to convert nested tuples of `Option`s using `From` element-wise. -- [`NestedTupleOptionInto`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionInto.html): Provides a [`nested_tuple_option_into()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionInto.html#tymethod.nested_tuple_option_into) convenience method to perform conversions using `NestedTupleOptionFrom`. -- [`NestedTupleOptionTryFrom`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionTryFrom.html): Provides a [`nested_tuple_option_try_from()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionTryFrom.html#tymethod.nested_tuple_option_try_from) method to fallibly convert nested tuples of `Option`s using `TryFrom` conversions. -- [`NestedTupleOptionTryInto`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionTryInto.html): Provides a [`nested_tuple_option_try_into()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleOptionTryInto.html#tymethod.nested_tuple_option_try_into) convenience method to perform fallible conversions using `NestedTupleOptionTryFrom`. -- [`NestedTupleReplicate`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleReplicate.html): Provides a [`nested_tuple_replicate(value)`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleReplicate.html#tymethod.nested_tuple_replicate) method to create nested tuples by replicating a single value across all positions. -- [`NestedTupleChain`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleChain.html): Provides a [`chain()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleChain.html#tymethod.chain) method to chain two nested tuples. -- [`TupleRef`](https://docs.rs/tuplities-ref/latest/tuplities_ref/trait.TupleRef.html): Provides a [`tuple_ref()`](https://docs.rs/tuplities-ref/latest/tuplities_ref/trait.TupleRef.html#tymethod.tuple_ref) method to get references to each element in the tuple. -- [`TupleMut`](https://docs.rs/tuplities-mut/latest/tuplities_mut/trait.TupleMut.html): Provides a [`tuple_mut()`](https://docs.rs/tuplities-mut/latest/tuplities_mut/trait.TupleMut.html#tymethod.tuple_mut) method to get mutable references to each element in the tuple. -- [`TupleRefMap`](https://docs.rs/tuplities-ref/latest/tuplities_ref/trait.TupleRefMap.html): Provides a [`tuple_ref_map()`](https://docs.rs/tuplities-ref/latest/tuplities_ref/trait.TupleRefMap.html#tymethod.tuple_ref_map) method to apply `TupleRef` to each element of a tuple of tuples, returning a tuple of tuples of references. -- [`TupleMutMap`](https://docs.rs/tuplities-mut/latest/tuplities_mut/trait.TupleMutMap.html): Provides a [`tuple_mut_map()`](https://docs.rs/tuplities-mut/latest/tuplities_mut/trait.TupleMutMap.html#tymethod.tuple_mut_map) method to apply `TupleMut` to each element of a tuple of tuples, returning a tuple of tuples of mutable references. -- [`TuplePopFront`](https://docs.rs/tuplities-pop-front/latest/tuplities_pop_front/trait.TuplePopFront.html): Provides a [`pop_front()`](https://docs.rs/tuplities-pop-front/latest/tuplities_pop_front/trait.TuplePopFront.html#tymethod.pop_front) method to remove and return the first element of the tuple along with the remaining elements as a new tuple. -- [`TuplePopBack`](https://docs.rs/tuplities-pop-back/latest/tuplities_pop_back/trait.TuplePopBack.html): Provides a [`pop_back()`](https://docs.rs/tuplities-pop-back/latest/tuplities_pop_back/trait.TuplePopBack.html#tymethod.pop_back) method to remove and return the last element of the tuple along with the remaining elements as a new tuple. -- [`TuplePushFront`](https://docs.rs/tuplities-push-front/latest/tuplities_push_front/trait.TuplePushFront.html): Provides a [`push_front(element)`](https://docs.rs/tuplities-push-front/latest/tuplities_push_front/trait.TuplePushFront.html#tymethod.push_front) method to add an element to the front of the tuple, returning a new tuple. -- [`TuplePushBack`](https://docs.rs/tuplities-push-back/latest/tuplities_push_back/trait.TuplePushBack.html): Provides a [`push_back(element)`](https://docs.rs/tuplities-push-back/latest/tuplities_push_back/trait.TuplePushBack.html#tymethod.push_back) method to add an element to the back of the tuple, returning a new tuple. -- [`TupleRemove`](https://docs.rs/tuplities-remove/latest/tuplities_remove/trait.TupleRemove.html): Provides a [`remove()`](https://docs.rs/tuplities-remove/latest/tuplities_remove/trait.TupleRemove.html#tymethod.remove) method to remove and return the element at the specified index [`typenum`](https://docs.rs/typenum/latest/typenum/)'s `Idx` of the tuple along with the remaining elements as a new tuple. -- [`TupleInsert`](https://docs.rs/tuplities-insert/latest/tuplities_insert/trait.TupleInsert.html): Provides an [`insert()`](https://docs.rs/tuplities-insert/latest/tuplities_insert/trait.TupleInsert.html#tymethod.insert) method to insert an element at the specified index [`typenum`](https://docs.rs/typenum/latest/typenum/)'s `Idx` into the tuple, returning the tuple with the element inserted. -- [`TupleSplit`](https://docs.rs/tuplities-split/latest/tuplities_split/trait.TupleSplit.html): Provides a [`split()`](https://docs.rs/tuplities-split/latest/tuplities_split/trait.TupleSplit.html#tymethod.split) method to split a tuple at the specified compile-time index [`typenum`](https://docs.rs/typenum/latest/typenum/)'s `Idx`, returning two tuples containing the elements before and at/after the index. -- [`TupleReverse`](https://docs.rs/tuplities-reverse/latest/tuplities_reverse/trait.TupleReverse.html): Provides a [`reverse()`](https://docs.rs/tuplities-reverse/latest/tuplities_reverse/trait.TupleReverse.html#tymethod.reverse) method to reverse the order of elements in a tuple. -- [`TupleTryFrom`](https://docs.rs/tuplities-try-from/latest/tuplities_try_from/trait.TupleTryFrom.html): Provides a [`tuple_try_from()`](https://docs.rs/tuplities-try-from/latest/tuplities_try_from/trait.TupleTryFrom.html#tymethod.tuple_try_from) method to fallibly convert from other types into tuples. -- [`TupleTryInto`](https://docs.rs/tuplities-try-from/latest/tuplities_try_from/trait.TupleTryInto.html): Provides a [`tuple_try_into()`](https://docs.rs/tuplities-try-from/latest/tuplities_try_from/trait.TupleTryInto.html#tymethod.tuple_try_into) method to fallibly convert tuples into other types. -- [`TupleFrom`](https://docs.rs/tuplities-from/latest/tuplities_from/trait.TupleFrom.html): Provides a [`tuple_from()`](https://docs.rs/tuplities-from/latest/tuplities_from/trait.TupleFrom.html#tymethod.tuple_from) method to infallibly convert from other types into tuples. -- [`TupleInto`](https://docs.rs/tuplities-from/latest/tuplities_from/trait.TupleInto.html): Provides a [`tuple_into()`](https://docs.rs/tuplities-from/latest/tuplities_from/trait.TupleInto.html#tymethod.tuple_into) method to infallibly convert tuples into other types. -- [`FlattenNestedTuple`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.FlattenNestedTuple.html): Provides a [`flatten()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.FlattenNestedTuple.html#tymethod.flatten) method to convert nested tuples like `(A, (B, (C,)))` into flat tuples like `(A, B, C)`. -- [`NestTuple`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestTuple.html): Provides a [`nest()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestTuple.html#tymethod.nest) method to convert flat tuples like `(A, B, C)` into nested tuples like `(A, (B, (C,)))`. -- [`NestedTupleIndex`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleIndex.html): Provides a [`nested_index()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleIndex.html#tymethod.nested_index) method to access elements at flat indices in nested tuples using [`typenum`](https://docs.rs/typenum/latest/typenum/)'s `Idx`. -- [`NestedTupleIndexMut`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleIndexMut.html): Provides a [`nested_index_mut()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleIndexMut.html#tymethod.nested_index_mut) method to access mutable elements at flat indices in nested tuples using [`typenum`](https://docs.rs/typenum/latest/typenum/)'s `Idx`. -- [`NestedTupleRef`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRef.html): Provides a [`nested_tuple_ref()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRef.html#tymethod.nested_tuple_ref) method to get nested references to each leaf value of a nested tuple. -- [`NestedTupleMut`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleMut.html): Provides a [`nested_tuple_mut()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleMut.html#tymethod.nested_tuple_mut) method to get nested mutable references to each leaf value of a nested tuple. -- [`NestedTuplePopFront`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePopFront.html): Provides a [`nested_pop_front()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePopFront.html#tymethod.nested_pop_front) method to pop the front element of nested tuples. -- [`NestedTuplePopBack`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePopBack.html): Provides a [`nested_pop_back()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePopBack.html#tymethod.nested_pop_back) method to pop the back element of nested tuples. -- [`NestedTuplePushFront`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePushFront.html): Provides a [`nested_push_front(element)`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePushFront.html#tymethod.nested_push_front) method to push an element to the front of a nested tuple. -- [`NestedTuplePushBack`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePushBack.html): Provides a [`nested_push_back(element)`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTuplePushBack.html#tymethod.nested_push_back) method to push an element to the back of a nested tuple. -- [`NestedTupleRow`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRow.html): Provides a [`nested_tuple_row()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRow.html#tymethod.nested_tuple_row) method to access elements at the specified index across a nested tuple-of-tuples, returning a nested row tuple by value. -- [`NestedTupleRow`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRow.html): Provides a [`nested_tuple_row()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRow.html#tymethod.nested_tuple_row) method to access elements at the specified index across a nested tuple-of-tuples, returning a nested row tuple of references (analogous to `TupleRow`). -- [`NestedTupleRowMut`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRowMut.html): Provides [`nested_tuple_row_mut()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleRowMut.html#tymethod.nested_tuple_row_mut) for mutable nested row access. -- [`NestedTupleStartsWith`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestedTupleStartsWith.html): A marker trait for compile-time verification that a nested tuple starts with the same types as another nested tuple. For example, `(A, (B, (C,)))` implements `NestedTupleStartsWith<(A,)>` and `NestedTupleStartsWith<(A, (B,))>`. -- [`NestTupleMatrix`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestTupleMatrix.html): Provides a [`nest_matrix()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.NestTupleMatrix.html#tymethod.nest_matrix) method to convert flat tuples of flat tuples like `((A, B), (C, D))` into nested tuples of nested tuples like `((A, (B,)), ((C, (D,)),))`. -- [`FlattenNestedTupleMatrix`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.FlattenNestedTupleMatrix.html): Provides a [`flatten_matrix()`](https://docs.rs/tuplities-flatten-nest/latest/tuplities_flatten_nest/trait.FlattenNestedTupleMatrix.html#tymethod.flatten_matrix) method to convert nested tuples of nested tuples back into flat tuples of flat tuples. -- [`TupleLen`](https://docs.rs/tuplities-len/latest/tuplities_len/trait.TupleLen.html): Provides the length of the tuple as a compile-time [`typenum::Unsigned`](https://docs.rs/typenum/latest/typenum/marker_traits/trait.Unsigned.html) type. -- [`UnitTuple`](https://docs.rs/tuplities-len/latest/tuplities_len/trait.UnitTuple.html): A marker trait implemented for empty tuples `()` with `TupleLen`. -- [`SingletonTuple`](https://docs.rs/tuplities-len/latest/tuplities_len/trait.SingletonTuple.html): A marker trait implemented for single-element tuples `(T,)` with `TupleLen`. -- [`PairTuple`](https://docs.rs/tuplities-len/latest/tuplities_len/trait.PairTuple.html): A marker trait implemented for two-element tuples `(T1, T2)` with `TupleLen`. -- [`TupleIndex`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.TupleIndex.html): Provides an [`index()`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.TupleIndex.html#tymethod.index) method to access the element at the specified index [`typenum`](https://docs.rs/typenum/latest/typenum/)'s `Idx` of the tuple. -- [`TupleIndexMut`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.TupleIndexMut.html): Provides an [`index_mut()`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.TupleIndexMut.html#tymethod.index_mut) method to access a mutable reference to the element at the specified index [`typenum`](https://docs.rs/typenum/latest/typenum/)'s `Idx` of the tuple. -- [`FirstTupleIndex`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.FirstTupleIndex.html): A convenience trait providing a [`first_tuple_index()`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.FirstTupleIndex.html#tymethod.first_tuple_index) method to access the first element of a tuple. -- [`LastTupleIndex`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.LastTupleIndex.html): A convenience trait providing a [`last_tuple_index()`](https://docs.rs/tuplities-index/latest/tuplities_index/trait.LastTupleIndex.html#tymethod.last_tuple_index) method to access the last element of a tuple. -- [`TupleRow`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.TupleRow.html): Provides a [`tuple_row()`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.TupleRow.html#tymethod.tuple_row) method to access elements at the specified index across all tuples in a tuple of tuples (row-wise indexing). -- [`TupleRowMut`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.TupleRowMut.html): Provides a [`tuple_row_mut()`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.TupleRowMut.html#tymethod.tuple_row_mut) method to access mutable elements at the specified index across all tuples in a tuple of tuples (mutable row-wise indexing). -- [`FirstTupleRow`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.FirstTupleRow.html): A convenience trait providing a [`first_tuple_row()`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.FirstTupleRow.html#tymethod.first_tuple_row) method to access the first element of each tuple in a tuple of tuples. -- [`LastTupleRow`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.LastTupleRow.html): A convenience trait providing a [`last_tuple_row()`](https://docs.rs/tuplities-row/latest/tuplities_row/trait.LastTupleRow.html#tymethod.last_tuple_row) method to access the last element of each tuple in a tuple of tuples. - -## Variadic Programming with Nested Tuples - -One of the most powerful features of `tuplities` is the ability to perform variadic programming on tuples of arbitrary length by converting them to a nested representation `(Head, (Tail...))`. This allows you to define traits recursively without needing to implement them for every possible tuple size using macros. - -It is important to note that "true" variadic generics are not yet available in Rust. As such, there is still a limit on how large the flat tuples can be, determined by which `size-XX` feature flags are enabled in this crate. However, this nested approach nevertheless allows for an arbitrary level of recursion while maintaining performant compile times, typically in the order of a few seconds even for large tuple sizes. - -Here is an example of how to define a trait that works on tuples of any size where all elements implement `Display`: +Recursive heterogeneous tuple utilities for `no_std` Rust. Use `neple!` to construct lists and `neplety!` to name their types. Traits and macros are available at the crate root and through `tuplities::prelude`. ```rust use tuplities::prelude::*; -use core::fmt::Display; - -// 1. Define flat & nested traits -trait PrintTuple { - fn print_tuple(&self); -} -trait PrintNested { - fn print_nested(&self); -} -// 2. Implement for the base cases -impl PrintNested for () { - fn print_nested(&self) {} -} -impl PrintNested for (Head,) { - fn print_nested(&self) { - println!("{}", self.0); - } -} - -// 3. Implement for the recursive case -impl PrintNested for (Head, Tail) -where - Head: Display, // Current constraint - Tail: PrintNested, // Recursive constraint -{ - fn print_nested(&self) { - println!("{}", self.0); - self.1.print_nested(); - } -} - -// 4. Blanket implementation for nestable tuples -// whose nested form implements PrintNested -impl PrintTuple for T -where - for<'a> &'a T: NestTuple, -{ - fn print_tuple(&self) { - self.nest().print_nested(); - } -} - -// Usage -let tuple = (42, "hello", true); -tuple.print_tuple(); -let another_tuple = (); -another_tuple.print_tuple(); -let yet_another_tuple = ("only one element",); -yet_another_tuple.print_tuple(); +type Values = neplety!(u8, &'static str, bool); +let values: Values = neple!(1_u8, "two").chain(neple!(true)); +assert_eq!(values, (1, ("two", (true,)))); +assert_eq!(values.into_options().transpose(), Some(values)); +assert!(*NestedTupleIndex::::nested_index(&values)); +assert_eq!(Values::LEN, 3); + +let (prefix, suffix) = NestedTupleSplit::::nested_split(values); +let inserted = NestedTupleInsert::::nested_insert(prefix.chain(suffix), 42_u16); +let (removed, remainder) = NestedTupleRemove::::nested_remove(inserted); +assert_eq!(removed, 42); +assert_eq!(remainder.nested_reverse(), neple!(true, "two", 1_u8)); ``` -This pattern is extensively used in libraries like [`diesel-builders`](https://github.com/LucaCappelletti94/diesel-builders/) to build complex, type-safe abstractions over tuples of varying sizes. - -### Comparison with Macro-based Approach - -Without nested tuples, achieving the same result typically requires defining a recursive macro that implements the trait for every tuple size up to a maximum limit. This approach has several downsides: +Split preserves its suffix and singleton-terminates its prefix. Insertion and removal preserve untouched suffixes and singleton-terminate reconstructed empty tails, while reversal produces a singleton-terminated list. Consuming operations accept reference-valued elements and leave borrowed recursive tails untouched, with traversal into borrowed tails rejected. -1. **Code Bloat**: The macro generates a separate implementation for each tuple size, leading to a large amount of generated code. -2. **Compile Times & Quadratic Bounds Growth**: The compiler has to process all these implementations, which significantly increases compile times. The number of trait bounds generated increases quadratically with the maximum tuple size `N` (proportional to `N^2`), as the macro generates implementations for all sizes from 0 to `N`, and size `k` requires `k` bounds. -3. **Maintenance**: Writing and maintaining complex macros can be error-prone and difficult to debug. -4. **Code Coverage**: Code coverage tools often struggle to provide meaningful information for code generated via macros, making it harder to ensure your variadic logic is fully tested. - -Here is how the same trait would be implemented using macros: +The default `flatten-nest` feature provides flat/nested tuple and matrix conversions and enables `alloc`. Flat conversions support widths through 8, with `size-16`, `size-32`, `size-48`, `size-64`, `size-96`, and `size-128` selecting larger limits. Enabling multiple size features selects the largest limit. ```rust -use core::fmt::Display; - -trait PrintTuple { - fn print_tuple(&self); -} - -macro_rules! impl_print_tuple { - // Base case: empty tuple - () => { - impl PrintTuple for () { - fn print_tuple(&self) {} - } - }; - // Recursive step: implement for (Head, Tail...) and recurse - ($Head:ident $(, $Tail:ident)*) => { - impl<$Head: Display, $($Tail: Display),*> PrintTuple for ($Head, $($Tail,)*) { - fn print_tuple(&self) { - #[allow(non_snake_case)] - let ($Head, $($Tail,)*) = self; - println!("{}", $Head); - $(println!("{}", $Tail);)* - } - } - - // Recurse for smaller tuple size - impl_print_tuple!($($Tail),*); - }; -} - -// Invoke once for the maximum size you want to support (e.g., 12) -impl_print_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); +# #[cfg(feature = "flatten-nest")] { +use tuplities::{FlattenNestedTuple, NestTuple}; + +let flat = (String::from("one"), 2_u8, true); +let nested = flat.nest(); +assert_eq!(nested, (String::from("one"), (2, (true,)))); +assert_eq!(nested.flatten(), (String::from("one"), 2, true)); +# } ``` -## Features - -The crate provides optional features to enable specific traits. All features are enabled by default for convenience, but can be selectively disabled to reduce compile time and binary size. - -### Trait Features - -The following features enable individual trait crates: - -- `clone`: Enables `TupleClone` trait -- `copy`: Enables `TupleCopy` trait -- `debug`: Enables `TupleDebug` trait -- `tuple-default`: Enables `TupleDefault` trait -- `eq`: Enables `TupleEq` trait -- `flatten-nest`: Enables `FlattenNestedTuple`, `NestTuple`, `NestedTupleIndex`, `NestedTupleIndexMut`, `NestedTupleTryFrom`, `NestedTupleTryInto`, `NestTupleMatrix`, `FlattenNestedTupleMatrix`, `NestedTupleOption`, `IntoNestedTupleOption`, and `NestedTupleOptionWith` traits -- `from`: Enables `TupleFrom` and `TupleInto` traits -- `hash`: Enables `TupleHash` trait -- `mut`: Enables `TupleMut` and `TupleMutMap` traits -- `option`: Enables `TupleOption` and `IntoTupleOption` traits -- `ord`: Enables `TupleOrd` trait -- `partial-eq`: Enables `TuplePartialEq` trait -- `partial-ord`: Enables `TuplePartialOrd` trait -- `remove`: Enables `TupleRemove` trait -- `insert`: Enables `TupleInsert` trait -- `len`: Enables `TupleLen`, `UnitTuple`, `SingletonTuple`, and `PairTuple` traits -- `index`: Enables `TupleIndex`, `TupleIndexMut`, `FirstTupleIndex`, and `LastTupleIndex` traits -- `pop-front`: Enables `TuplePopFront`, `TupleRefFront`, and `TupleMutFront` traits -- `pop-back`: Enables `TuplePopBack`, `TupleRefBack`, and `TupleMutBack` traits -- `push-front`: Enables `TuplePushFront` trait -- `push-back`: Enables `TuplePushBack` trait -- `ref`: Enables `TupleRef` and `TupleRefMap` traits -- `replicate`: Enables `TupleReplicate` trait -- `reverse`: Enables `TupleReverse` trait -- `row`: Enables `TupleRow`, `TupleRowMut`, `FirstTupleRow`, and `LastTupleRow` traits -- `split`: Enables `TupleSplit` trait -- `try-from`: Enables `TupleTryFrom` and `TupleTryInto` traits - -### Size Features - -Additionally, the crate provides features to generate trait implementations for tuples up to different sizes: 8 (default), 16, 32, 48, 64, 96, or 128 elements. Use the `size-XX` features to enable larger tuple support. - -```toml -[dependencies] -tuplities = { version = "0.1.4", default-features = false, features = ["clone", "index", "size-32"] } -``` - -## Performance - -Compile times scale with tuple size due to code generation. Below are measured build times for different maximum tuple sizes captured via the project's `measure_compile_times.sh` script on a typical development machine. Values are approximate and represent wall-clock `real` times. If you only plan to use variadic nested tuples, you may prefer to use only the `tuplities-flatten-nest` crate, which has significantly lower compile times. - -### tuplities (root crate) - -| Max Tuple Size | Compile Time | -|----------------|--------------| -| 8 (default) | ~4.07s | -| 16 | ~2.71s | -| 32 | ~3.29s | -| 48 | ~4.55s | -| 64 | ~6.83s | -| 96 | ~15.75s | -| 128 | ~32.44s | - -### tuplities-flatten-nest (flatten-nest crate only) - -| Max Tuple Size | Compile Time | -|----------------|--------------| -| 8 (default) | ~3.18s | -| 16 | ~2.45s | -| 32 | ~2.60s | -| 48 | ~2.86s | -| 64 | ~3.40s | -| 96 | ~5.46s | -| 128 | ~9.52s | - -## Architecture - -The project is split into multiple crates for improved compile times: - -- `tuplities/`: Main crate that re-exports traits from subcrates -- `tuplities-{trait_name}/`: Individual crates providing specific traits -- `tuplities-derive/`: Procedural macro crate that generates trait implementations - -## License - -This project is licensed under the MIT License. See the LICENSE file for details. - -## Contribution +Disable default features for the allocator-free recursive core and enable `alloc` for `NestedTupleIntoVec`. Indexing, row access, and `NestedTuple::LEN` depend on recursive structure without flat arity limits. Both singleton-terminated and unit-terminated lists support these operations, including borrowed tails. -Contributions are welcome! Please open issues or pull requests on the [GitHub repository](https://github.com/lucacappelletti94/tuplities). +Rust `1.85` or later is required. Standard traits such as `Clone`, `Copy`, `Debug`, equality, ordering, and hashing compose through nested pairs without additional tuple traits. diff --git a/measure_compile_times.sh b/measure_compile_times.sh deleted file mode 100755 index 9bc6753..0000000 --- a/measure_compile_times.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -# Script to measure compile times for different tuple size features -# Usage: ./measure_compile_times.sh - -set -e - -echo "Measuring compile times for different tuple sizes..." -echo "==================================================" - -# Array of features to test (empty string means default/size-8) -FEATURES=("" "size-16" "size-32" "size-48" "size-64" "size-96" "size-128") - -# Test each feature -echo "Measuring compile times for tuplities crate..." -for feature in "${FEATURES[@]}"; do - if [ -z "$feature" ]; then - echo "Testing default (size-8):" - time (cargo clean && cargo build --quiet) - else - echo "Testing $feature:" - time (cargo clean && cargo build --quiet --features "$feature") - fi - echo "" -done - -# Test each feature for the `tuplities-flatten-nest` crate -echo "Measuring compile times for tuplities-flatten-nest crate..." -for feature in "${FEATURES[@]}"; do - if [ -z "$feature" ]; then - echo "Testing default (size-8):" - time (cd tuplities-flatten-nest && cargo clean && cargo build --quiet) - else - echo "Testing $feature:" - time (cd tuplities-flatten-nest && cargo clean && cargo build --quiet --features "$feature") - fi - echo "" -done - -echo "All measurements completed!" -echo "" -echo "Update the README.md table with the new compile times." -echo "The format should be:" -echo "| Max Tuple Size | Compile Time |" -echo "|----------------|--------------|" -echo "| 8 (default) | ~Xs |" -echo "| 16 | ~Xs |" -echo "| etc... | ~Xs |" \ No newline at end of file diff --git a/tuplities-clone/Cargo.toml b/tuplities-clone/Cargo.toml deleted file mode 100644 index 7437739..0000000 --- a/tuplities-clone/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-clone" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for cloning tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-clone/src/lib.rs b/tuplities-clone/src/lib.rs deleted file mode 100644 index 4307996..0000000 --- a/tuplities-clone/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleClone` trait. - -#[tuplities_derive::impl_tuple_clone] -/// A trait for cloning tuples. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleClone { - #[must_use] - /// Clones `self` into a new instance. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_clone::TupleClone; - /// - /// let tuple = (1, "hello", vec![1, 2, 3]); - /// let cloned_tuple = tuple.tuple_clone(); - /// - /// assert_eq!(tuple, cloned_tuple); - /// ``` - fn tuple_clone(&self) -> Self; -} diff --git a/tuplities-copy/Cargo.toml b/tuplities-copy/Cargo.toml deleted file mode 100644 index 29e9595..0000000 --- a/tuplities-copy/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "tuplities-copy" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for copying tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true -tuplities-clone.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-copy/src/lib.rs b/tuplities-copy/src/lib.rs deleted file mode 100644 index 171459d..0000000 --- a/tuplities-copy/src/lib.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleCopy` trait. - -use tuplities_clone::TupleClone; - -#[tuplities_derive::impl_tuple_copy] -/// A trait for copying tuples. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleCopy: TupleClone { - #[must_use] - /// Copies `self` into a new instance. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_copy::TupleCopy; - /// - /// let tuple = (1, "hello", 3.14); - /// let copied_tuple = tuple.tuple_copy(); - /// - /// assert_eq!(tuple, copied_tuple); - /// ``` - fn tuple_copy(&self) -> Self; -} diff --git a/tuplities-debug/Cargo.toml b/tuplities-debug/Cargo.toml deleted file mode 100644 index e771047..0000000 --- a/tuplities-debug/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-debug" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for debug formatting of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-debug/src/lib.rs b/tuplities-debug/src/lib.rs deleted file mode 100644 index ecca183..0000000 --- a/tuplities-debug/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleDebug` trait. -#![no_std] - -extern crate alloc; - -#[tuplities_derive::impl_tuple_debug] -/// A trait for debugging tuples. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleDebug { - /// Returns a string representation of the tuple for debugging. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_debug::TupleDebug; - /// - /// let tuple = (1, "hello", 3.14); - /// let debug_str = tuple.tuple_debug(); - /// - /// assert_eq!(debug_str, "(1, \"hello\", 3.14)"); - /// ``` - fn tuple_debug(&self) -> alloc::string::String; -} diff --git a/tuplities-default/Cargo.toml b/tuplities-default/Cargo.toml deleted file mode 100644 index 6d884b9..0000000 --- a/tuplities-default/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-default" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for creating default values for tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-default/src/lib.rs b/tuplities-default/src/lib.rs deleted file mode 100644 index 051b127..0000000 --- a/tuplities-default/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleDefault` trait. - -#[tuplities_derive::impl_tuple_default] -/// A trait for creating default instances of tuples. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleDefault { - /// Returns the default value of the tuple. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_default::TupleDefault; - /// - /// let default_tuple: (i32, String, f64) = <(i32, String, f64)>::tuple_default(); - /// - /// assert_eq!(default_tuple, (0, String::new(), 0.0)); - /// ``` - fn tuple_default() -> Self; -} diff --git a/tuplities-derive/Cargo.toml b/tuplities-derive/Cargo.toml deleted file mode 100644 index c8dff5f..0000000 --- a/tuplities-derive/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "tuplities-derive" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "Procedural macros for deriving tuple traits" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[lib] -proc-macro = true - -[dependencies] -syn = { version = "2.0", features = ["full", "extra-traits"] } -quote = "1.0" -proc-macro2 = "1.0" -siphasher = "1.0" -typenum = { workspace = true } - -[features] -default = [] -size-16 = [] -size-32 = [] -size-48 = [] -size-64 = [] -size-96 = [] -size-128 = [] - -[lints] -workspace = true diff --git a/tuplities-derive/src/lib.rs b/tuplities-derive/src/lib.rs deleted file mode 100644 index 77d3459..0000000 --- a/tuplities-derive/src/lib.rs +++ /dev/null @@ -1,303 +0,0 @@ -//! Procedural macros for the tuplities suite. - -use proc_macro::TokenStream; - -mod tuple_size; -mod tuplities_as_ref; -mod tuplities_clone; -mod tuplities_copy; -mod tuplities_debug; -mod tuplities_default; -mod tuplities_eq; -mod tuplities_first_tuple_row; -mod tuplities_from; -mod tuplities_hash; -mod tuplities_index; -mod tuplities_insert; -mod tuplities_last_tuple_row; -mod tuplities_len; -mod tuplities_mut; -mod tuplities_mut_map; -mod tuplities_nest_tuple; -mod tuplities_option; -mod tuplities_ord; -mod tuplities_partial_eq; -mod tuplities_partial_ord; -mod tuplities_pop_back; -mod tuplities_pop_front; -mod tuplities_push_back; -mod tuplities_push_front; -mod tuplities_ref; -mod tuplities_ref_map; -mod tuplities_remove; -mod tuplities_replicate; -mod tuplities_reverse; -mod tuplities_row; -mod tuplities_row_mut; -mod tuplities_split; -mod tuplities_try_from; - -/// Generate `TableIndex` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_clone(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_clone::impl_tuple_clone()); - item.into() -} - -/// Generate `TupleCopy` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_copy(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_copy::impl_tuple_copy()); - item.into() -} - -/// Generate `TupleDebug` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_debug(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_debug::impl_tuple_debug()); - item.into() -} - -/// Generate `TupleDefault` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_default(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_default::impl_tuple_default()); - item.into() -} - -/// Generate `TupleHash` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_hash(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_hash::impl_tuple_hash()); - item.into() -} - -/// Generate `TupleAsRef` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_as_ref(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_as_ref::impl_tuple_as_ref()); - item.into() -} - -/// Generate `TuplePartialEq` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_partial_eq(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_partial_eq::impl_tuple_partial_eq()); - item.into() -} - -/// Generate `TupleEq` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_eq(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_eq::impl_tuple_eq()); - item.into() -} - -/// Generate `TuplePartialOrd` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_partial_ord(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_partial_ord::impl_tuple_partial_ord()); - item.into() -} - -/// Generate `TupleOrd` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_ord(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_ord::impl_tuple_ord()); - item.into() -} - -/// Generate `PopFront` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_pop_front(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_pop_front::impl_pop_front()); - item.into() -} - -/// Generate `PopBack` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_pop_back(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_pop_back::impl_pop_back()); - item.into() -} - -/// Generate `TupleRemove` trait implementations for all tuple sizes and indices. -#[proc_macro_attribute] -pub fn impl_remove(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_remove::impl_remove()); - item.into() -} - -/// Generate `TupleInsert` trait implementations for all tuple sizes and indices. -#[proc_macro_attribute] -pub fn impl_insert(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_insert::impl_insert()); - item.into() -} - -/// Generate `TupleLen` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_len(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_len::impl_len()); - item.into() -} - -/// Generate `TupleIndex` trait implementations for all tuple sizes and indices. -#[proc_macro_attribute] -pub fn impl_tuple_index(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_index::impl_tuple_index()); - item.into() -} - -/// Generate `PushBack` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_push_back(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_push_back::impl_push_back()); - item.into() -} - -/// Generate `PushFront` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_push_front(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_push_front::impl_push_front()); - item.into() -} - -/// Generate `TupleReverse` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_reverse(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_reverse::impl_reverse()); - item.into() -} - -/// Generate `TupleSplit` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_split(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_split::impl_split()); - item.into() -} - -/// Generate `TupleRef` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_ref(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_ref::impl_tuple_ref()); - item.into() -} - -/// Generate `TupleReplicate` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_replicate(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_replicate::impl_tuple_replicate()); - item.into() -} - -/// Generate `TupleMut` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_mut(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_mut::impl_tuple_mut()); - item.into() -} - -/// Generate `TupleRefMap` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_ref_map(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_ref_map::impl_tuple_ref_map()); - item.into() -} - -/// Generate `TupleMutMap` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_mut_map(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_mut_map::impl_tuple_mut_map()); - item.into() -} - -/// Generate `TupleOption` and `IntoTupleOption` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_option(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_option::impl_tuple_option()); - item.extend(tuplities_option::impl_into_tuple_option()); - item.into() -} - -/// Generate `TupleTryFrom` and `TupleTryInto` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_try_from(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_try_from::impl_tuple_try_from()); - item.into() -} - -/// Generate `TupleFrom` and `TupleInto` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_tuple_from(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_from::impl_tuple_from()); - item.into() -} - -/// Generate `Row` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_row(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_row::impl_row()); - item.into() -} - -/// Generate `RowMut` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_row_mut(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_row_mut::impl_row_mut()); - item.into() -} - -/// Generate `FirstTupleRow` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_first_tuple_row(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_first_tuple_row::impl_first_tuple_row()); - item.into() -} - -/// Generate `LastTupleRow` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_last_tuple_row(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_last_tuple_row::impl_last_tuple_row()); - item.into() -} - -/// Generate `NestTuple` trait implementations for all tuple sizes. -#[proc_macro_attribute] -pub fn impl_nest_tuple(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut item = proc_macro2::TokenStream::from(item); - item.extend(tuplities_nest_tuple::impl_nest_tuple()); - item.into() -} diff --git a/tuplities-derive/src/tuple_size.rs b/tuplities-derive/src/tuple_size.rs deleted file mode 100644 index 15ff9a8..0000000 --- a/tuplities-derive/src/tuple_size.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! Core tuple generation utilities for procedural macros. -//! -//! This module provides shared functionality for generating trait -//! implementations across tuples of varying sizes (1-32 elements). - -use proc_macro2::{Ident, Span, TokenStream}; -use syn::Index; - -#[cfg(not(any( - feature = "size-16", - feature = "size-32", - feature = "size-48", - feature = "size-64", - feature = "size-96", - feature = "size-128" -)))] -/// Maximum number of elements supported in tuple implementations. -pub const MAX_TUPLE_SIZE: usize = 8; -#[cfg(all( - feature = "size-16", - not(any( - feature = "size-32", - feature = "size-48", - feature = "size-64", - feature = "size-96", - feature = "size-128" - )) -))] -/// Maximum number of elements supported in tuple implementations. -pub const MAX_TUPLE_SIZE: usize = 16; -#[cfg(all( - feature = "size-32", - not(any( - feature = "size-48", - feature = "size-64", - feature = "size-96", - feature = "size-128" - )) -))] -/// Maximum number of elements supported in tuple implementations. -pub const MAX_TUPLE_SIZE: usize = 32; -#[cfg(all( - feature = "size-48", - not(any(feature = "size-64", feature = "size-96", feature = "size-128")) -))] -/// Maximum number of elements supported in tuple implementations. -pub const MAX_TUPLE_SIZE: usize = 48; -#[cfg(all( - feature = "size-64", - not(feature = "size-96"), - not(feature = "size-128") -))] -/// Maximum number of elements supported in tuple implementations. -pub const MAX_TUPLE_SIZE: usize = 64; -#[cfg(all(feature = "size-96", not(feature = "size-128")))] -/// Maximum number of elements supported in tuple implementations. -pub const MAX_TUPLE_SIZE: usize = 96; -#[cfg(feature = "size-128")] -/// Maximum number of elements supported in tuple implementations. -pub const MAX_TUPLE_SIZE: usize = 128; - -/// Generate a list of type parameter identifiers (T1, T2, ..., TN) -/// -/// # Arguments -/// -/// * `count` - The number of type parameters to generate. -pub(crate) fn type_params(count: usize) -> Vec { - type_params_with_prefix(count, "T") -} - -pub(crate) fn type_params_with_prefix(count: usize, prefix: &str) -> Vec { - (1..=count) - .map(|i| Ident::new(&format!("{prefix}{i}"), Span::call_site())) - .collect() -} - -/// Generate a list of indices (0, 1, ..., N-1) -pub(crate) fn indices(count: usize) -> Vec { - (0..count).map(Index::from).collect() -} - -/// Generate all tuple implementations from size 0 (unit) to MAX_TUPLE_SIZE -pub(crate) fn generate_all_sizes(impl_fn: F) -> TokenStream -where - F: Fn(usize) -> TokenStream, -{ - (0..=MAX_TUPLE_SIZE).map(impl_fn).collect() -} - -/// Generate all tuple implementations from size 0 (unit) to MAX_TUPLE_SIZE -pub(crate) fn generate_non_empty(impl_fn: F) -> TokenStream -where - F: Fn(usize) -> TokenStream, -{ - (1..=MAX_TUPLE_SIZE).map(impl_fn).collect() -} - -mod tests { - #[test] - fn test_type_params() { - let params = super::type_params(3); - assert_eq!(params.len(), 3); - assert_eq!(params[0].to_string(), "T1"); - assert_eq!(params[1].to_string(), "T2"); - assert_eq!(params[2].to_string(), "T3"); - } - - #[test] - fn test_generate_all_sizes() { - let _generated = super::generate_all_sizes(|size| { - let struct_ident = - syn::Ident::new(&format!("TupleSize{size}"), proc_macro2::Span::call_site()); - quote::quote! { - struct #struct_ident; - } - }); - } -} diff --git a/tuplities-derive/src/tuplities_as_ref.rs b/tuplities-derive/src/tuplities_as_ref.rs deleted file mode 100644 index f3ff195..0000000 --- a/tuplities-derive/src/tuplities_as_ref.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Submodule providing the derive macro for the `TupleAsRef` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params, type_params_with_prefix}; - -/// Generate `TupleAsRef` trait implementations for all tuple sizes. -pub fn impl_tuple_as_ref() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let ref_target_params = type_params_with_prefix(size, "R"); - let indices = indices(size); - - quote! { - impl<'a, #(#ref_target_params: 'a + ?Sized,)* #(#type_params: AsRef<#ref_target_params>,)*> TupleAsRef<'a, (#(&'a #ref_target_params,)*)> for (#(#type_params,)*) - where Self: 'a - { - #[inline] - fn as_tuple_ref(&'a self) -> (#(&'a #ref_target_params,)*) { - (#(self.#indices.as_ref(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_clone.rs b/tuplities-derive/src/tuplities_clone.rs deleted file mode 100644 index 3335af5..0000000 --- a/tuplities-derive/src/tuplities_clone.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Submodule providing the derive macro for the `TupleClone` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TableIndex` trait marker implementations for all tuple sizes. -pub fn impl_tuple_clone() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: Clone,)*> TupleClone for (#(#type_params,)*) - { - #[inline] - - fn tuple_clone(&self) -> Self { - (#(self.#indices.clone(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_copy.rs b/tuplities-derive/src/tuplities_copy.rs deleted file mode 100644 index e59eff7..0000000 --- a/tuplities-derive/src/tuplities_copy.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Submodule providing the derive macro for the `TupleCopy` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleCopy` trait implementations for all tuple sizes. -pub fn impl_tuple_copy() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: Copy,)*> TupleCopy for (#(#type_params,)*) - { - #[inline] - fn tuple_copy(&self) -> Self { - ( #(self.#indices,)* ) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_debug.rs b/tuplities-derive/src/tuplities_debug.rs deleted file mode 100644 index 00dd5ba..0000000 --- a/tuplities-derive/src/tuplities_debug.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Submodule providing the derive macro for the `TupleDebug` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleDebug` trait implementations for all tuple sizes. -pub fn impl_tuple_debug() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: core::fmt::Debug,)*> TupleDebug for (#(#type_params,)*) - { - #[inline] - fn tuple_debug(&self) -> alloc::string::String { - let parts: alloc::vec::Vec = alloc::vec![ - #( - alloc::format!("{:?}", self.#indices), - )* - ]; - alloc::format!( - "({})", - parts.join(", ") - ) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_default.rs b/tuplities-derive/src/tuplities_default.rs deleted file mode 100644 index 5c6ad66..0000000 --- a/tuplities-derive/src/tuplities_default.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Submodule providing the derive macro for the `TupleDefault` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, type_params}; - -/// Generate `TupleDefault` trait implementations for all tuple sizes. -pub fn impl_tuple_default() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - - quote! { - impl<#(#type_params: Default,)*> TupleDefault for (#(#type_params,)*) - { - #[inline] - fn tuple_default() -> Self { - ( #(<#type_params as Default>::default(),)* ) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_eq.rs b/tuplities-derive/src/tuplities_eq.rs deleted file mode 100644 index 10949e9..0000000 --- a/tuplities-derive/src/tuplities_eq.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Submodule providing the derive macro for the `TupleEq` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleEq` trait implementations for all tuple sizes. -pub fn impl_tuple_eq() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - let body = if size == 0 { - quote! { true } - } else { - quote! { #(self.#indices == other.#indices)&&* } - }; - - quote! { - impl<#(#type_params: Eq,)*> TupleEq for (#(#type_params,)*) - { - #[inline] - fn tuple_eq(&self, other: &Self) -> bool { - #body - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_first_tuple_row.rs b/tuplities-derive/src/tuplities_first_tuple_row.rs deleted file mode 100644 index f275020..0000000 --- a/tuplities-derive/src/tuplities_first_tuple_row.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Submodule providing the derive macro for the `FirstTupleRow` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `FirstTupleRow` trait implementations for all tuple sizes. -pub fn impl_first_tuple_row() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: tuplities_pop_front::TupleRefFront,)*> FirstTupleRow for (#(#type_params,)*) - { - type FirstRowType = (#(< #type_params as tuplities_pop_front::TuplePopFront >::Front,)*); - - fn first_tuple_row(&self) -> ::Ref<'_> { - (#(self.#indices.ref_front(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_from.rs b/tuplities-derive/src/tuplities_from.rs deleted file mode 100644 index cde0297..0000000 --- a/tuplities-derive/src/tuplities_from.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Submodule providing the derive macro for the `TupleFrom` and `TupleInto` traits. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params, type_params_with_prefix}; - -/// Generate `TupleFrom` trait implementations for all tuple sizes. -pub fn impl_tuple_from() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let source_type_params = type_params(size); - let target_type_params = type_params_with_prefix(size, "B"); - let indices = indices(size); - - if size == 0 { - return quote! { - impl TupleFrom<()> for () { - fn tuple_from(_value: ()) -> Self {} - } - }; - } - - let source_tuple = quote! { (#(#source_type_params,)*) }; - - quote! { - impl<#(#source_type_params,)* #(#target_type_params: From<#source_type_params>,)*> TupleFrom<#source_tuple> for (#(#target_type_params,)*) - { - fn tuple_from(value: #source_tuple) -> Self { - (#(From::from(value.#indices),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_hash.rs b/tuplities-derive/src/tuplities_hash.rs deleted file mode 100644 index 2db9fc5..0000000 --- a/tuplities-derive/src/tuplities_hash.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Submodule providing the derive macro for the `TupleHash` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleHash` trait implementations for all tuple sizes. -pub fn impl_tuple_hash() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: core::hash::Hash + Eq,)*> TupleHash for (#(#type_params,)*) - { - #[inline] - fn tuple_hash(&self, state: &mut H) { - #( - self.#indices.hash(state); - )* - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_index.rs b/tuplities-derive/src/tuplities_index.rs deleted file mode 100644 index 95f3362..0000000 --- a/tuplities-derive/src/tuplities_index.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Submodule providing the derive macro for the `TupleIndex` trait. - -use quote::quote; - -use crate::tuple_size::{generate_non_empty, type_params}; - -/// Generate `TupleIndex` trait implementations for all tuple sizes and indices. -pub fn impl_tuple_index() -> proc_macro2::TokenStream { - generate_non_empty(|size| { - let type_params = type_params(size); - (0..size) - .map(|u_idx| { - let indexed_type = &type_params[u_idx]; - let indexed_index = syn::Index::from(u_idx); - let typenum_ident = - syn::Ident::new(&format!("U{u_idx}"), proc_macro2::Span::call_site()); - let typenum: syn::Path = syn::parse_quote!(typenum::#typenum_ident); - quote! { - impl<#(#type_params,)*> TupleIndex<#typenum> for (#(#type_params,)*) - { - type Element = #indexed_type; - - #[inline] - fn tuple_index(&self) -> &Self::Element { - &self.#indexed_index - } - } - impl<#(#type_params,)*> TupleIndexMut<#typenum> for (#(#type_params,)*) - { - #[inline] - fn tuple_index_mut(&mut self) -> &mut Self::Element { - &mut self.#indexed_index - } - } - } - }) - .collect() - }) -} diff --git a/tuplities-derive/src/tuplities_insert.rs b/tuplities-derive/src/tuplities_insert.rs deleted file mode 100644 index f38da2d..0000000 --- a/tuplities-derive/src/tuplities_insert.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Submodule providing the derive macro for the `TupleInsert` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleInsert` trait implementations for all tuple sizes and indices. -pub fn impl_insert() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - (0..=size) - .map(|u_idx| { - let before = &type_params[..u_idx]; - let after = &type_params[u_idx..]; - let before_indices = &indices[..u_idx]; - let after_indices = &indices[u_idx..]; - let typenum_ident = - syn::Ident::new(&format!("U{u_idx}"), proc_macro2::Span::call_site()); - let typenum: syn::Path = syn::parse_quote!(typenum::#typenum_ident); - quote! { - impl TupleInsert<#typenum, T> for (#(#type_params,)*) - { - type Output = (#(#before,)* T, #(#after,)*); - - #[inline] - fn insert(self, value: T) -> Self::Output { - (#(self.#before_indices,)* value, #(self.#after_indices,)*) - } - } - } - }) - .collect() - }) -} diff --git a/tuplities-derive/src/tuplities_last_tuple_row.rs b/tuplities-derive/src/tuplities_last_tuple_row.rs deleted file mode 100644 index 5a70e57..0000000 --- a/tuplities-derive/src/tuplities_last_tuple_row.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Submodule providing the derive macro for the `LastTupleRow` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `LastTupleRow` trait implementations for all tuple sizes. -pub fn impl_last_tuple_row() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: tuplities_pop_back::TupleRefBack,)*> LastTupleRow for (#(#type_params,)*) - { - type LastRowType = (#(< #type_params as tuplities_pop_back::TuplePopBack >::Back,)*); - - fn last_tuple_row(&self) -> ::Ref<'_> { - (#(self.#indices.ref_back(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_len.rs b/tuplities-derive/src/tuplities_len.rs deleted file mode 100644 index 3c91f0e..0000000 --- a/tuplities-derive/src/tuplities_len.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Submodule providing the derive macro for the `TupleLen` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, type_params}; - -/// Generate `TupleLen` trait implementations for all tuple sizes. -pub fn impl_len() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let typenum_ident = syn::Ident::new(&format!("U{size}"), proc_macro2::Span::call_site()); - let typenum: syn::Path = syn::parse_quote!(typenum::#typenum_ident); - quote! { - impl<#(#type_params,)*> TupleLen for (#(#type_params,)*) { - type Len = #typenum; - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_mut.rs b/tuplities-derive/src/tuplities_mut.rs deleted file mode 100644 index 5c02246..0000000 --- a/tuplities-derive/src/tuplities_mut.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Submodule providing the derive macro for the `TupleMut` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleMut` trait implementations for all tuple sizes. -pub fn impl_tuple_mut() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - let mut_tuple = if size == 0 { - quote! { () } - } else { - let mut_refs = (0..size).map(|_| quote! { &'a mut }); - quote! { (#(#mut_refs #type_params,)*) } - }; - - quote! { - impl<#(#type_params,)*> TupleMut for (#(#type_params,)*) - { - type Mut<'a> = #mut_tuple where Self: 'a; - - #[inline] - fn tuple_mut(&mut self) -> Self::Mut<'_> { - (#(&mut self.#indices,)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_mut_map.rs b/tuplities-derive/src/tuplities_mut_map.rs deleted file mode 100644 index 68a9271..0000000 --- a/tuplities-derive/src/tuplities_mut_map.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Submodule providing the derive macro for the `TupleMutMap` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleMutMap` trait implementations for all tuple sizes. -pub fn impl_tuple_mut_map() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: TupleMut,)*> TupleMutMap for (#(#type_params,)*) - { - type MutMap<'a> = (#(< #type_params as TupleMut >::Mut<'a>,)*) where Self: 'a; - - #[inline] - fn tuple_mut_map(&mut self) -> Self::MutMap<'_> { - (#(self.#indices.tuple_mut(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_nest_tuple.rs b/tuplities-derive/src/tuplities_nest_tuple.rs deleted file mode 100644 index 6d542d4..0000000 --- a/tuplities-derive/src/tuplities_nest_tuple.rs +++ /dev/null @@ -1,157 +0,0 @@ -//! Submodule providing the derive macro for the `NestTuple` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, type_params}; - -/// Generate `NestTuple` trait implementations for all tuple sizes. -pub fn impl_nest_tuple() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - - // Generate the flat input type - let flat_input_type = quote! { (#(#type_params,)*) }; - - // Generate the nested output type - let nested_output_type = generate_nested_output_type(&type_params); - let nested_ref_output_type = generate_nested_ref_output_type(&type_params); - let nested_mut_output_type = generate_nested_mut_output_type(&type_params); - - // Generate the nest implementation - let nest_impl = generate_nest_impl(size); - let nest_ref_impl = generate_nest_ref_impl(size); - let nest_mut_impl = generate_nest_mut_impl(size); - - quote! { - impl<#(#type_params,)*> NestTuple for #flat_input_type { - type Nested = #nested_output_type; - - #[inline] - fn nest(self) -> Self::Nested { - #nest_impl - } - } - - impl<#(#type_params,)*> NestTupleRef for #flat_input_type { - type NestedRef<'a> = #nested_ref_output_type where Self: 'a; - - #[inline] - fn nest_ref(&self) -> Self::NestedRef<'_> { - #nest_ref_impl - } - } - - impl<#(#type_params,)*> NestTupleMut for #flat_input_type { - type NestedMut<'a> = #nested_mut_output_type where Self: 'a; - - #[inline] - fn nest_mut(&mut self) -> Self::NestedMut<'_> { - #nest_mut_impl - } - } - } - }) -} - -/// Generate the nested output type for NestTuple. -/// For size N with types A, B, C, ..., N, generates (A, (B, (C, (...(N,))))) -fn generate_nested_output_type(type_params: &[proc_macro2::Ident]) -> proc_macro2::TokenStream { - match type_params { - [] => quote! { () }, - [single] => quote! { (#single,) }, - _ => { - // Build nested structure: (T0, (T1, (T2, (...(T{N-1},)))) - // Start with innermost (T{N-1},) and wrap outwards - let last_ty = &type_params[type_params.len() - 1]; - let mut result = quote! { (#last_ty,) }; - for ty in type_params.iter().rev().skip(1) { - result = quote! { (#ty, #result) }; - } - result - } - } -} - -fn generate_nested_ref_output_type(type_params: &[proc_macro2::Ident]) -> proc_macro2::TokenStream { - match type_params { - [] => quote! { () }, - [single] => quote! { (&'a #single,) }, - _ => { - let last_ty = &type_params[type_params.len() - 1]; - let mut result = quote! { (&'a #last_ty,) }; - for ty in type_params.iter().rev().skip(1) { - result = quote! { (&'a #ty, #result) }; - } - result - } - } -} - -fn generate_nested_mut_output_type(type_params: &[proc_macro2::Ident]) -> proc_macro2::TokenStream { - match type_params { - [] => quote! { () }, - [single] => quote! { (&'a mut #single,) }, - _ => { - let last_ty = &type_params[type_params.len() - 1]; - let mut result = quote! { (&'a mut #last_ty,) }; - for ty in type_params.iter().rev().skip(1) { - result = quote! { (&'a mut #ty, #result) }; - } - result - } - } -} - -/// Generate the nest implementation that builds nested structure from flat tuple -fn generate_nest_impl(size: usize) -> proc_macro2::TokenStream { - match size { - 0 => quote! { () }, - 1 => quote! { self }, - _ => { - // Build nested structure: (self.0, (self.1, (self.2, (...(self.N-1,))))) - // Start with innermost tuple (self.{N-1},) and build outwards - let last_index = syn::Index::from(size - 1); - (0..size) - .rev() - .skip(1) - .fold(quote! { (self.#last_index,) }, |acc, i| { - let index = syn::Index::from(i); - quote! { (self.#index, #acc) } - }) - } - } -} - -fn generate_nest_ref_impl(size: usize) -> proc_macro2::TokenStream { - match size { - 0 => quote! { () }, - 1 => quote! { (&self.0,) }, - _ => { - let last_index = syn::Index::from(size - 1); - (0..size) - .rev() - .skip(1) - .fold(quote! { (&self.#last_index,) }, |acc, i| { - let index = syn::Index::from(i); - quote! { (&self.#index, #acc) } - }) - } - } -} - -fn generate_nest_mut_impl(size: usize) -> proc_macro2::TokenStream { - match size { - 0 => quote! { () }, - 1 => quote! { (&mut self.0,) }, - _ => { - let last_index = syn::Index::from(size - 1); - (0..size) - .rev() - .skip(1) - .fold(quote! { (&mut self.#last_index,) }, |acc, i| { - let index = syn::Index::from(i); - quote! { (&mut self.#index, #acc) } - }) - } - } -} diff --git a/tuplities-derive/src/tuplities_option.rs b/tuplities-derive/src/tuplities_option.rs deleted file mode 100644 index 69aac39..0000000 --- a/tuplities-derive/src/tuplities_option.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Submodule providing the derive macro for the `TupleOption` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleOption` trait implementations for all tuple sizes. -pub fn impl_tuple_option() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params,)*> TupleOption for (#(Option<#type_params>,)*) - { - type Transposed = (#(#type_params,)* ); - - #[inline] - fn transpose(self) -> Option { - Some((#(self.#indices?,)*)) - } - } - } - }) -} - -/// Generate `IntoTupleOption` trait implementations for all tuple sizes. -pub fn impl_into_tuple_option() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params,)*> IntoTupleOption for (#(#type_params,)*) - { - type IntoOptions = (#(Option<#type_params>,)*); - - #[inline] - fn into_options(self) -> Self::IntoOptions { - ( #(Some(self.#indices),)* ) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_ord.rs b/tuplities-derive/src/tuplities_ord.rs deleted file mode 100644 index da20f20..0000000 --- a/tuplities-derive/src/tuplities_ord.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Submodule providing the derive macro for the `TupleOrd` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleOrd` trait implementations for all tuple sizes. -pub fn impl_tuple_ord() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: Ord,)*> TupleOrd for (#(#type_params,)*) - { - #[inline] - fn tuple_cmp(&self, other: &Self) -> core::cmp::Ordering { - #( - match self.#indices.cmp(&other.#indices) { - core::cmp::Ordering::Equal => {}, - non_eq => return non_eq, - } - )* - core::cmp::Ordering::Equal - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_partial_eq.rs b/tuplities-derive/src/tuplities_partial_eq.rs deleted file mode 100644 index 2fdc623..0000000 --- a/tuplities-derive/src/tuplities_partial_eq.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Submodule providing the derive macro for the `TuplePartialEq` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TuplePartialEq` trait implementations for all tuple sizes. -pub fn impl_tuple_partial_eq() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - let body = if size == 0 { - quote! { true } - } else { - quote! { #(self.#indices == other.#indices)&&* } - }; - - quote! { - impl<#(#type_params: PartialEq,)*> TuplePartialEq for (#(#type_params,)*) - { - #[inline] - fn tuple_eq(&self, other: &Self) -> bool { - #body - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_partial_ord.rs b/tuplities-derive/src/tuplities_partial_ord.rs deleted file mode 100644 index 6bd1acd..0000000 --- a/tuplities-derive/src/tuplities_partial_ord.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Submodule providing the derive macro for the `TuplePartialOrd` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TuplePartialOrd` trait implementations for all tuple sizes. -pub fn impl_tuple_partial_ord() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: PartialOrd,)*> TuplePartialOrd for (#(#type_params,)*) - { - #[inline] - fn tuple_partial_cmp(&self, other: &Self) -> Option { - #( - match self.#indices.partial_cmp(&other.#indices) { - Some(core::cmp::Ordering::Equal) => {}, - other => return other - } - )* - Some(core::cmp::Ordering::Equal) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_pop_back.rs b/tuplities-derive/src/tuplities_pop_back.rs deleted file mode 100644 index f3696a4..0000000 --- a/tuplities-derive/src/tuplities_pop_back.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Submodule providing the derive macro for the `TuplePopBack` trait. - -use quote::quote; - -use crate::tuple_size::{generate_non_empty, indices, type_params}; - -/// Generate `TuplePopBack` trait implementations for all tuple sizes starting from 1. -pub fn impl_pop_back() -> proc_macro2::TokenStream { - generate_non_empty(|size| { - let type_params = type_params(size); - let indices = indices(size); - let (last, others) = type_params.split_last().unwrap(); - let (last_index, other_indices) = indices.split_last().unwrap(); - - quote! { - impl<#(#type_params,)*> TuplePopBack for (#(#type_params,)*) - { - type Init = (#(#others,)*); - type Back = #last; - - #[inline] - fn pop_back(self) -> (Self::Init, Self::Back) { - ((#(self.#other_indices,)*), self.#last_index) - } - } - - impl<#(#type_params,)*> TupleRefBack for (#(#type_params,)*) - { - #[inline] - fn ref_back(&self) -> &Self::Back { - &self.#last_index - } - } - - impl<#(#type_params,)*> TupleMutBack for (#(#type_params,)*) - { - #[inline] - fn mut_back(&mut self) -> &mut Self::Back { - &mut self.#last_index - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_pop_front.rs b/tuplities-derive/src/tuplities_pop_front.rs deleted file mode 100644 index f45c52c..0000000 --- a/tuplities-derive/src/tuplities_pop_front.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! Submodule providing the derive macro for the `TuplePopFront` trait. - -use quote::quote; - -use crate::tuple_size::{generate_non_empty, indices, type_params}; - -/// Generate `TuplePopFront` trait implementations for all tuple sizes starting from 1. -pub fn impl_pop_front() -> proc_macro2::TokenStream { - generate_non_empty(|size| { - let type_params = type_params(size); - let indices = indices(size); - let (first, others) = type_params.split_first().unwrap(); - let (first_index, other_indices) = indices.split_first().unwrap(); - - quote! { - impl<#(#type_params,)*> TuplePopFront for (#(#type_params,)*) - { - type Front = #first; - type Tail = (#(#others,)*); - - #[inline] - fn pop_front(self) -> (Self::Front, Self::Tail) { - (self.#first_index, (#(self.#other_indices,)*)) - } - } - - impl<#(#type_params,)*> TupleRefFront for (#(#type_params,)*) - { - #[inline] - fn ref_front(&self) -> &Self::Front { - &self.#first_index - } - } - - impl<#(#type_params,)*> TupleMutFront for (#(#type_params,)*) - { - #[inline] - fn mut_front(&mut self) -> &mut Self::Front { - &mut self.#first_index - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_push_back.rs b/tuplities-derive/src/tuplities_push_back.rs deleted file mode 100644 index b587a1f..0000000 --- a/tuplities-derive/src/tuplities_push_back.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Submodule providing the derive macro for the `TuplePushBack` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TuplePushBack` trait implementations for all tuple sizes. -pub fn impl_push_back() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl TuplePushBack for (#(#type_params,)*) - { - type Output = (#(#type_params,)* T,); - - fn push_back(self, value: T) -> Self::Output { - (#(self.#indices,)* value,) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_push_front.rs b/tuplities-derive/src/tuplities_push_front.rs deleted file mode 100644 index 9eac61a..0000000 --- a/tuplities-derive/src/tuplities_push_front.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Submodule providing the derive macro for the `TuplePushFront` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TuplePushFront` trait implementations for all tuple sizes. -pub fn impl_push_front() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl TuplePushFront for (#(#type_params,)*) - { - type Output = (T, #(#type_params,)*); - - #[inline] - fn push_front(self, value: T) -> Self::Output { - (value, #(self.#indices,)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_ref.rs b/tuplities-derive/src/tuplities_ref.rs deleted file mode 100644 index 8e84443..0000000 --- a/tuplities-derive/src/tuplities_ref.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Submodule providing the derive macro for the `TupleRef` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleRef` trait implementations for all tuple sizes. -pub fn impl_tuple_ref() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params,)*> TupleRef for (#(#type_params,)*) - { - type Ref<'a> = (#(&'a #type_params,)*) where Self: 'a; - - #[inline] - fn tuple_ref(&self) -> Self::Ref<'_> { - (#(&self.#indices,)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_ref_map.rs b/tuplities-derive/src/tuplities_ref_map.rs deleted file mode 100644 index 1dcd23a..0000000 --- a/tuplities-derive/src/tuplities_ref_map.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Submodule providing the derive macro for the `TupleRefMap` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleRefMap` trait implementations for all tuple sizes. -pub fn impl_tuple_ref_map() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl<#(#type_params: TupleRef,)*> TupleRefMap for (#(#type_params,)*) - { - type RefMap<'a> = (#(< #type_params as TupleRef >::Ref<'a>,)*) where Self: 'a; - - #[inline] - fn tuple_ref_map(&self) -> Self::RefMap<'_> { - (#(self.#indices.tuple_ref(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_remove.rs b/tuplities-derive/src/tuplities_remove.rs deleted file mode 100644 index 38361c7..0000000 --- a/tuplities-derive/src/tuplities_remove.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Submodule providing the derive macro for the `TupleRemove` trait. - -use quote::quote; - -use crate::tuple_size::{generate_non_empty, type_params}; - -/// Generate `TupleRemove` trait implementations for all tuple sizes and indices. -pub fn impl_remove() -> proc_macro2::TokenStream { - generate_non_empty(|size| { - let type_params = type_params(size); - (0..size) - .map(|u_idx| { - let removed_type = &type_params[u_idx]; - let others = type_params - .iter() - .enumerate() - .filter_map(|(i, t)| if i == u_idx { None } else { Some(t) }) - .collect::>(); - let removed_index = syn::Index::from(u_idx); - let other_indices = (0..size) - .filter_map(|i| { - if i == u_idx { - None - } else { - Some(syn::Index::from(i)) - } - }) - .collect::>(); - let typenum_ident = - syn::Ident::new(&format!("U{u_idx}"), proc_macro2::Span::call_site()); - let typenum: syn::Path = syn::parse_quote!(typenum::#typenum_ident); - quote! { - impl<#(#type_params,)*> TupleRemove<#typenum> for (#(#type_params,)*) - { - type Type = #removed_type; - type Remainder = (#(#others,)*); - - #[inline] - fn remove(self) -> (Self::Type, Self::Remainder) { - (self.#removed_index, (#(self.#other_indices,)*)) - } - } - } - }) - .collect() - }) -} diff --git a/tuplities-derive/src/tuplities_replicate.rs b/tuplities-derive/src/tuplities_replicate.rs deleted file mode 100644 index 866a08c..0000000 --- a/tuplities-derive/src/tuplities_replicate.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Submodule providing the derive macro for the `TupleReplicate` trait. - -use quote::quote; - -use crate::tuple_size::generate_all_sizes; - -/// Generate `TupleReplicate` trait implementations for all tuple sizes. -pub fn impl_tuple_replicate() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - if size == 0 { - // Empty tuple: no Clone bound needed - return quote! { - impl TupleReplicate for () { - #[inline] - fn tuple_replicate(_value: T) -> Self { - () - } - } - }; - } - - if size == 1 { - // Single element: no Clone bound needed, just move the value - return quote! { - impl TupleReplicate for (T,) { - #[inline] - fn tuple_replicate(value: T) -> Self { - (value,) - } - } - }; - } - - let tuple_elements = (0..size).map(|_| quote! { T }).collect::>(); - - // Multiple elements: Clone bound needed, clone for all but last, move for last - let mut replicated_values = Vec::new(); - for i in 0..size { - if i == size - 1 { - replicated_values.push(quote! { value }); - } else { - replicated_values.push(quote! { value.clone() }); - } - } - - quote! { - impl<'a, 'b, T: Clone> TupleReplicate for (#(#tuple_elements,)*) - where - T: 'a, - Self: 'b, - 'a: 'b, - { - fn tuple_replicate(value: T) -> Self { - (#(#replicated_values,)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_reverse.rs b/tuplities-derive/src/tuplities_reverse.rs deleted file mode 100644 index 13b95d8..0000000 --- a/tuplities-derive/src/tuplities_reverse.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Submodule providing the derive macro for the `TupleReverse` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleReverse` trait implementations for all tuple sizes. -pub fn impl_reverse() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - let reversed_indices: Vec<_> = indices.iter().rev().collect(); - let reversed_type_params: Vec<_> = type_params.iter().rev().collect(); - - quote! { - impl<#(#type_params,)*> TupleReverse for (#(#type_params,)*) - { - type Output = (#(#reversed_type_params,)*); - - #[inline] - fn reverse(self) -> Self::Output { - (#(self.#reversed_indices,)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_row.rs b/tuplities-derive/src/tuplities_row.rs deleted file mode 100644 index 9cedbb6..0000000 --- a/tuplities-derive/src/tuplities_row.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Submodule providing the derive macro for the `TupleRow` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleRow` trait implementations for all tuple sizes. -pub fn impl_row() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl,)*> TupleRow for (#(#type_params,)*) - { - type RowType = (#(#type_params::Element,)*); - - fn tuple_row(&self) -> ::Ref<'_> { - (#(self.#indices.tuple_index(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_row_mut.rs b/tuplities-derive/src/tuplities_row_mut.rs deleted file mode 100644 index f039534..0000000 --- a/tuplities-derive/src/tuplities_row_mut.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Submodule providing the derive macro for the `TupleRowMut` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleRowMut` trait implementations for all tuple sizes. -pub fn impl_row_mut() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let type_params = type_params(size); - let indices = indices(size); - - quote! { - impl,)*> TupleRowMut for (#(#type_params,)*) - { - fn tuple_row_mut(&mut self) -> ::Mut<'_> { - (#(self.#indices.tuple_index_mut(),)*) - } - } - } - }) -} diff --git a/tuplities-derive/src/tuplities_split.rs b/tuplities-derive/src/tuplities_split.rs deleted file mode 100644 index 0adf7cb..0000000 --- a/tuplities-derive/src/tuplities_split.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Submodule providing the derive macro for the `TupleSplit` trait. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params}; - -/// Generate `TupleSplit` trait implementations for all tuple sizes and indices. -pub fn impl_split() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - (0..=size) - .map(|u_idx| { - let type_params = type_params(size); - let indices = indices(size); - let left_types = &type_params[..u_idx]; - let right_types = &type_params[u_idx..]; - let left_indices = &indices[..u_idx]; - let right_indices = &indices[u_idx..]; - let typenum_ident = - syn::Ident::new(&format!("U{u_idx}"), proc_macro2::Span::call_site()); - let typenum: syn::Path = syn::parse_quote!(typenum::#typenum_ident); - quote! { - impl<#(#type_params,)*> TupleSplit<#typenum> for (#(#type_params,)*) - { - type Left = (#(#left_types,)*); - type Right = (#(#right_types,)*); - - #[inline] - fn split(self) -> (Self::Left, Self::Right) { - ((#(self.#left_indices,)*), (#(self.#right_indices,)*)) - } - } - } - }) - .collect() - }) -} diff --git a/tuplities-derive/src/tuplities_try_from.rs b/tuplities-derive/src/tuplities_try_from.rs deleted file mode 100644 index 2eed50d..0000000 --- a/tuplities-derive/src/tuplities_try_from.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Submodule providing the derive macro for the `TupleTryFrom` and `TupleTryInto` traits. - -use quote::quote; - -use crate::tuple_size::{generate_all_sizes, indices, type_params, type_params_with_prefix}; - -/// Generate `TupleTryFrom` trait implementations for all tuple sizes. -pub fn impl_tuple_try_from() -> proc_macro2::TokenStream { - generate_all_sizes(|size| { - let source_type_params = type_params(size); - let target_type_params = type_params_with_prefix(size, "B"); - let indices = indices(size); - - if size == 0 { - return quote! { - impl TupleTryFrom<(), E> for () { - fn tuple_try_from(_value: ()) -> Result { - Ok(()) - } - } - }; - } - - let source_tuple = quote! { (#(#source_type_params,)*) }; - - quote! { - impl<#(#source_type_params,)* #(#target_type_params,)* E> TupleTryFrom<#source_tuple, E> for (#(#target_type_params,)*) - where - #(#target_type_params: core::convert::TryFrom<#source_type_params>,)* - E: #(From<<#target_type_params as core::convert::TryFrom<#source_type_params>>::Error>)+* - { - fn tuple_try_from(value: #source_tuple) -> Result { - Ok((#(#target_type_params::try_from(value.#indices)?,)*)) - } - } - } - }) -} diff --git a/tuplities-eq/Cargo.toml b/tuplities-eq/Cargo.toml deleted file mode 100644 index 6881f6f..0000000 --- a/tuplities-eq/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-eq" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for comparing tuples for equality" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - -[dependencies] -tuplities-derive.workspace = true -tuplities-partial-eq.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16", "tuplities-partial-eq/size-16"] -size-32 = ["tuplities-derive/size-32", "tuplities-partial-eq/size-32"] -size-48 = ["tuplities-derive/size-48", "tuplities-partial-eq/size-48"] -size-64 = ["tuplities-derive/size-64", "tuplities-partial-eq/size-64"] -size-96 = ["tuplities-derive/size-96", "tuplities-partial-eq/size-96"] -size-128 = ["tuplities-derive/size-128", "tuplities-partial-eq/size-128"] diff --git a/tuplities-eq/src/lib.rs b/tuplities-eq/src/lib.rs deleted file mode 100644 index a87517f..0000000 --- a/tuplities-eq/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleEq` trait. - -use tuplities_partial_eq::TuplePartialEq; - -#[tuplities_derive::impl_tuple_eq] -/// A trait for comparing tuples for total equality. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleEq: TuplePartialEq { - /// Returns `true` if `self` and `other` are equal. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_eq::TupleEq; - /// - /// let tuple1 = (1, "hello"); - /// let tuple2 = (1, "hello"); - /// let tuple3 = (2, "world"); - /// - /// assert!(tuple1.tuple_eq(&tuple2)); - /// assert!(!tuple1.tuple_eq(&tuple3)); - /// ``` - fn tuple_eq(&self, other: &Self) -> bool; -} diff --git a/tuplities-flatten-nest/Cargo.toml b/tuplities-flatten-nest/Cargo.toml deleted file mode 100644 index 8d0570b..0000000 --- a/tuplities-flatten-nest/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "tuplities-flatten-nest" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "Traits for flattening nested tuples and nesting flat tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true -tuplities-push-front.workspace = true -typenum.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-flatten-nest/src/lib.rs b/tuplities-flatten-nest/src/lib.rs deleted file mode 100644 index 249d6ef..0000000 --- a/tuplities-flatten-nest/src/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing traits for flattening and nesting tuples. - -extern crate alloc; - -mod flatten_nested; -mod matrix; -mod nest; -mod nested_chain; -mod nested_index; -mod nested_into_vec; -mod nested_option; -mod nested_option_try_from; -mod nested_push_pop; -mod nested_ref; -mod nested_replicate; -mod nested_row; -mod nested_starts_with; -mod nested_try_from; - -// Re-export all public traits and types -pub use flatten_nested::FlattenNestedTuple; -pub use matrix::{ - FlattenMatrixElements, FlattenNestedTupleMatrix, NestMatrixElements, NestTupleMatrix, -}; -pub use nest::{NestTuple, NestTupleMut, NestTupleRef}; -pub use nested_chain::NestedTupleChain; -pub use nested_index::{NestedTupleIndex, NestedTupleIndexMut}; -pub use nested_into_vec::NestedTupleIntoVec; -pub use nested_option::{ - IntoNestedTupleOption, NestedTupleFlattenOption, NestedTupleOption, NestedTupleOptionWith, -}; -pub use nested_option_try_from::{ - NestedTupleOptionFrom, NestedTupleOptionInto, NestedTupleOptionTryFrom, - NestedTupleOptionTryInto, -}; -pub use nested_push_pop::{ - NestedTuplePopBack, NestedTuplePopFront, NestedTuplePushBack, NestedTuplePushFront, -}; -pub use nested_ref::{NestedTupleMut, NestedTupleRef}; -pub use nested_replicate::NestedTupleReplicate; -pub use nested_row::{NestedTupleRow, NestedTupleRowMut}; -pub use nested_starts_with::NestedTupleStartsWith; -pub use nested_try_from::{NestedTupleFrom, NestedTupleInto}; -pub use nested_try_from::{NestedTupleTryFrom, NestedTupleTryInto}; diff --git a/tuplities-from/Cargo.toml b/tuplities-from/Cargo.toml deleted file mode 100644 index 13300c7..0000000 --- a/tuplities-from/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "tuplities-from" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "Traits for converting values into tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - -[dependencies] -tuplities-derive.workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-from/src/lib.rs b/tuplities-from/src/lib.rs deleted file mode 100644 index e048093..0000000 --- a/tuplities-from/src/lib.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleFrom` and `TupleInto` traits. - -#[tuplities_derive::impl_tuple_from] -/// A trait for infallibly converting from one tuple type to another. -/// -/// This trait allows converting between tuples where each element can be converted -/// using the standard `From` trait. Unlike `TupleTryFrom`, this trait guarantees -/// that the conversion will succeed. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleFrom { - /// Converts from `T` into `Self`. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_from::TupleFrom; - /// - /// let source = (1u8, 2u8); - /// let target: (u32, u32) = TupleFrom::tuple_from(source); - /// assert_eq!(target, (1, 2)); - /// ``` - fn tuple_from(value: T) -> Self; -} - -/// A trait for infallibly converting a tuple into another tuple type. -/// -/// This trait allows converting tuples into other tuple types where each element can be converted -/// using the standard `From` trait. Unlike `TupleTryInto`, this trait guarantees -/// that the conversion will succeed. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleInto { - /// Converts `self` into `T`. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_from::TupleInto; - /// - /// let source = (1u8, 2u8); - /// let target: (u32, u32) = TupleInto::tuple_into(source); - /// assert_eq!(target, (1, 2)); - /// ``` - fn tuple_into(self) -> T; -} - -// Blanket implementation of TupleInto based on TupleFrom -impl TupleInto for U -where - T: TupleFrom, -{ - fn tuple_into(self) -> T { - T::tuple_from(self) - } -} diff --git a/tuplities-hash/Cargo.toml b/tuplities-hash/Cargo.toml deleted file mode 100644 index 9725b7d..0000000 --- a/tuplities-hash/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "tuplities-hash" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for hashing tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true -tuplities-eq.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16", "tuplities-eq/size-16"] -size-32 = ["tuplities-derive/size-32", "tuplities-eq/size-32"] -size-48 = ["tuplities-derive/size-48", "tuplities-eq/size-48"] -size-64 = ["tuplities-derive/size-64", "tuplities-eq/size-64"] -size-96 = ["tuplities-derive/size-96", "tuplities-eq/size-96"] -size-128 = ["tuplities-derive/size-128", "tuplities-eq/size-128"] diff --git a/tuplities-hash/src/lib.rs b/tuplities-hash/src/lib.rs deleted file mode 100644 index 34f8a40..0000000 --- a/tuplities-hash/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleHash` trait. - -use tuplities_eq::TupleEq; - -#[tuplities_derive::impl_tuple_hash] -/// A trait for hashing tuples with a generic hasher. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleHash: TupleEq { - /// Hashes the tuple into the given hasher. - fn tuple_hash(&self, state: &mut H); -} diff --git a/tuplities-index/Cargo.toml b/tuplities-index/Cargo.toml deleted file mode 100644 index d340eb8..0000000 --- a/tuplities-index/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "tuplities-index" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "Traits for compile-time indexing into tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -typenum = { workspace = true } -tuplities-derive = { workspace = true } -tuplities-len = { workspace = true } - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] - -[lints] -workspace = true diff --git a/tuplities-index/src/lib.rs b/tuplities-index/src/lib.rs deleted file mode 100644 index 461c918..0000000 --- a/tuplities-index/src/lib.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! A trait for indexing into tuples at compile-time known positions. -//! -//! This crate provides the `TupleIndex` trait, which allows accessing -//! elements at compile-time known indices from tuples using `typenum::Unsigned` types. - -#![no_std] - -use tuplities_len::TupleLen; - -/// A trait for indexing into tuples at compile-time known positions. -/// -/// This trait allows accessing elements at specific indices `Idx` -/// from tuples, where `Idx` is a compile-time constant from `typenum`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_index::TupleIndex; -/// use typenum::U1; -/// -/// let tuple = (1, "hello", 3.14); -/// let element = TupleIndex::::tuple_index(&tuple); -/// assert_eq!(*element, "hello"); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_tuple_index] -pub trait TupleIndex: TupleLen { - /// The type of the element at index `Idx`. - type Element; - - /// Returns a reference to the element at index `Idx`. - fn tuple_index(&self) -> &Self::Element; -} - -/// A trait for mutable indexing into tuples at compile-time known positions. -/// -/// This trait allows mutable access to elements at specific indices `Idx` -/// from tuples, where `Idx` is a compile-time constant from `typenum`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_index::TupleIndexMut; -/// use typenum::U1; -/// -/// let mut tuple = (1, "hello", 3.14); -/// let element = TupleIndexMut::::tuple_index_mut(&mut tuple); -/// *element = "world"; -/// assert_eq!(tuple.1, "world"); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleIndexMut: TupleIndex { - /// Returns a mutable reference to the element at index `Idx`. - fn tuple_index_mut(&mut self) -> &mut Self::Element; -} - -/// A convenience trait for accessing the first element (index 0) in tuples. -/// -/// This trait is automatically implemented for any tuple that implements `TupleIndex`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_index::FirstTupleIndex; -/// -/// let tuple = (1, "hello", 3.14); -/// let first = tuple.first_tuple_index(); -/// assert_eq!(*first, 1); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait FirstTupleIndex: TupleIndex { - /// Returns a reference to the first element in the tuple. - fn first_tuple_index(&self) -> &Self::Element { - self.tuple_index() - } -} - -impl> FirstTupleIndex for T {} - -/// A convenience trait for accessing the last element in tuples. -/// -/// This trait is automatically implemented for any tuple that implements `TupleIndex` -/// where `LastIndex` is calculated as `TupleLen::Len - 1`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_index::LastTupleIndex; -/// -/// let tuple = (1, "hello", 3.14); -/// let last = tuple.last_tuple_index(); -/// assert_eq!(*last, 3.14); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait LastTupleIndex: - TupleIndex< - <::Len as core::ops::Sub>::Output, - Len: core::ops::Sub, - > -{ - /// Returns a reference to the last element in the tuple. - fn last_tuple_index(&self) -> &Self::Element; -} - -impl LastTupleIndex for T -where - T: TupleIndex< - <::Len as core::ops::Sub>::Output, - Len: core::ops::Sub, - >, -{ - fn last_tuple_index(&self) -> &Self::Element { - self.tuple_index() - } -} diff --git a/tuplities-insert/Cargo.toml b/tuplities-insert/Cargo.toml deleted file mode 100644 index df166e3..0000000 --- a/tuplities-insert/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "tuplities-insert" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for inserting elements into tuples at compile-time indices" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -typenum = { workspace = true } -tuplities-derive = { workspace = true } - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] - -[lints] -workspace = true diff --git a/tuplities-insert/src/lib.rs b/tuplities-insert/src/lib.rs deleted file mode 100644 index 3608ba3..0000000 --- a/tuplities-insert/src/lib.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! A trait for inserting elements at specific indices into tuples. -//! -//! This crate provides the `TupleInsert` trait, which allows inserting an element -//! at a compile-time known index into a tuple, returning the tuple with the element inserted. - -#![no_std] - -/// A trait for inserting an element at a specific index into a tuple. -/// -/// This trait allows inserting an element at compile-time known index `Idx` -/// into a tuple, returning the tuple with the element inserted. -/// -/// # Examples -/// -/// ``` -/// use tuplities_insert::TupleInsert; -/// use typenum::U1; -/// -/// let tuple = (1, 3.14); -/// let inserted = TupleInsert::::insert(tuple, "hello"); -/// assert_eq!(inserted, (1, "hello", 3.14)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_insert] -pub trait TupleInsert { - /// The type of the tuple after inserting the element. - type Output; - - /// Inserts the element at index `Idx` into the tuple. - /// - /// Returns the tuple with the element inserted at the specified index. - fn insert(self, value: T) -> Self::Output; -} - -#[cfg(test)] -mod tests { - use super::TupleInsert; - use typenum::{U0, U1, U2}; - - #[test] - fn test_insert_zero_elements() { - let tuple = (); - let result = TupleInsert::::insert(tuple, 42); - // () insert at U0 -> (i32,) - let expected: (i32,) = (42,); - assert_eq!(result, expected); - } - - #[test] - fn test_insert_single_element() { - let tuple = (1,); - // Insert at U0 - let result0 = TupleInsert::::insert(tuple, 42); - let expected0: (i32, i32) = (42, 1); - assert_eq!(result0, expected0); - - // Insert at U1 - let tuple = (1,); - let result1 = TupleInsert::::insert(tuple, 42); - let expected1: (i32, i32) = (1, 42); - assert_eq!(result1, expected1); - } - - #[test] - fn test_insert_two_elements() { - let tuple = (1, 2); - // Insert at U0 - let result0 = TupleInsert::::insert(tuple, 42); - let expected0: (i32, i32, i32) = (42, 1, 2); - assert_eq!(result0, expected0); - - // Insert at U1 - let tuple = (1, 2); - let result1 = TupleInsert::::insert(tuple, 42); - let expected1: (i32, i32, i32) = (1, 42, 2); - assert_eq!(result1, expected1); - - // Insert at U2 - let tuple = (1, 2); - let result2 = TupleInsert::::insert(tuple, 42); - let expected2: (i32, i32, i32) = (1, 2, 42); - assert_eq!(result2, expected2); - } -} diff --git a/tuplities-len/Cargo.toml b/tuplities-len/Cargo.toml deleted file mode 100644 index a451ecc..0000000 --- a/tuplities-len/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "tuplities-len" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for getting the compile-time length of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -typenum = { workspace = true } -tuplities-derive = { workspace = true } - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] - -[lints] -workspace = true diff --git a/tuplities-len/src/lib.rs b/tuplities-len/src/lib.rs deleted file mode 100644 index 14960c7..0000000 --- a/tuplities-len/src/lib.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! A trait for getting the length of tuples at compile time. -//! -//! This crate provides the `TupleLen` trait, which allows getting the length -//! of a tuple as a compile-time `typenum::Unsigned` type. - -#![no_std] - -/// A trait for getting the compile-time length of a tuple. -/// -/// This trait provides the length of a tuple as an associated type `Len` -/// that implements `typenum::Unsigned`. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_len] -pub trait TupleLen { - /// The length of the tuple as a `typenum::Unsigned` type. - type Len: typenum::Unsigned; -} - -/// A marker trait for empty tuples (size 0). -/// -/// This trait is implemented for the unit type `()` and can be used -/// for type-level programming to identify empty tuples. -/// -/// # Examples -/// -/// ``` -/// use tuplities_len::{UnitTuple, TupleLen}; -/// use typenum::U0; -/// -/// fn is_empty(_tuple: T) { -/// // This function only accepts empty tuples -/// } -/// -/// is_empty(()); // This works -/// // is_empty((1,)); // This would not compile -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait UnitTuple: TupleLen {} - -impl UnitTuple for () {} - -/// A marker trait for single-element tuples (size 1). -/// -/// This trait is implemented for single-element tuples `(T,)` and can be used -/// for type-level programming to identify single-element tuples. -/// -/// # Examples -/// -/// ``` -/// use tuplities_len::{SingletonTuple, TupleLen}; -/// use typenum::U1; -/// -/// fn is_single(_tuple: T) { -/// // This function only accepts single-element tuples -/// } -/// -/// is_single((42,)); // This works -/// // is_single((1, 2)); // This would not compile -/// // is_single(()); // This would not compile -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait SingletonTuple: TupleLen {} - -impl SingletonTuple for (T,) {} - -/// A marker trait for two-element tuples (size 2). -/// -/// This trait is implemented for two-element tuples `(T1, T2)` and can be used -/// for type-level programming to identify two-element tuples. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_len::{PairTuple, TupleLen}; -/// use typenum::U2; -/// fn is_pair(_tuple: T) { -/// // This function only accepts two-element tuples -/// } -/// is_pair((1, 2)); // This works -/// // is_pair((42,)); // This would not compile -/// // is_pair(()); // This would not compile -/// ``` -/// -pub trait PairTuple: TupleLen {} - -impl PairTuple for (T1, T2) {} diff --git a/tuplities-mut/Cargo.toml b/tuplities-mut/Cargo.toml deleted file mode 100644 index 6ef74e6..0000000 --- a/tuplities-mut/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-mut" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for getting tuples of mutable references from tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-mut/src/lib.rs b/tuplities-mut/src/lib.rs deleted file mode 100644 index e0edeeb..0000000 --- a/tuplities-mut/src/lib.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleMut` trait. - -#[tuplities_derive::impl_tuple_mut] -/// A trait for tuples that provides a method to get a tuple of mutable references. -/// -/// This trait provides both an associated type `Mut<'a>` that represents a tuple -/// of mutable references to the elements, and a method `tuple_mut` that returns such a tuple. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_mut::TupleMut; -/// -/// let mut tuple = (1, "hello".to_string(), vec![1, 2, 3]); -/// let mut_refs = tuple.tuple_mut(); -/// *mut_refs.0 = 42; -/// mut_refs.1.push_str(" world"); -/// mut_refs.2.push(4); -/// assert_eq!(tuple, (42, "hello world".to_string(), vec![1, 2, 3, 4])); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleMut { - /// The type of a tuple containing mutable references to each element. - type Mut<'a> - where - Self: 'a; - - /// Returns a tuple of mutable references to each element. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_mut::TupleMut; - /// - /// let mut tuple = (42, "world".to_string()); - /// let mut_refs = tuple.tuple_mut(); - /// *mut_refs.0 = 24; - /// mut_refs.1.make_ascii_uppercase(); - /// assert_eq!(tuple, (24, "WORLD".to_string())); - /// ``` - fn tuple_mut(&mut self) -> Self::Mut<'_>; -} - -#[tuplities_derive::impl_tuple_mut_map] -/// A trait for applying `TupleMut` to each element of a tuple. -/// -/// This trait takes a mutable reference to a tuple where each element implements `TupleMut` and returns -/// a tuple where each element is the result of calling `tuple_mut()` on the original elements. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_mut::TupleMutMap; -/// -/// let mut matrix = ((1, 2), (3, 4), (5, 6)); -/// let mut_ref_matrix = matrix.tuple_mut_map(); -/// assert_eq!(mut_ref_matrix, ((&mut 1, &mut 2), (&mut 3, &mut 4), (&mut 5, &mut 6))); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleMutMap { - /// The type of a tuple containing tuples of mutable references to each inner element. - type MutMap<'a> - where - Self: 'a; - - /// Returns a tuple where each element is a tuple of mutable references to the inner elements. - fn tuple_mut_map(&mut self) -> Self::MutMap<'_>; -} diff --git a/tuplities-option/Cargo.toml b/tuplities-option/Cargo.toml deleted file mode 100644 index 67c7ee5..0000000 --- a/tuplities-option/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-option" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "Traits for working with tuples of Options" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - -[dependencies] -tuplities-derive.workspace = true -tuplities-default.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16", "tuplities-default/size-16"] -size-32 = ["tuplities-derive/size-32", "tuplities-default/size-32"] -size-48 = ["tuplities-derive/size-48", "tuplities-default/size-48"] -size-64 = ["tuplities-derive/size-64", "tuplities-default/size-64"] -size-96 = ["tuplities-derive/size-96", "tuplities-default/size-96"] -size-128 = ["tuplities-derive/size-128", "tuplities-default/size-128"] diff --git a/tuplities-option/src/lib.rs b/tuplities-option/src/lib.rs deleted file mode 100644 index e73ebc3..0000000 --- a/tuplities-option/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleOption` and `IntoTupleOption` traits. - -use tuplities_default::TupleDefault; - -#[tuplities_derive::impl_tuple_option] -/// A trait for transposing a tuple of options into an option of a tuple. -pub trait TupleOption: TupleDefault { - /// The transposed type: an option of the tuple of the inner types. - type Transposed: IntoTupleOption; - - /// Transposes the tuple of options into an option of the tuple. - /// - /// Returns `Some((a, b, ...))` if all elements are `Some`, otherwise `None`. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_option::TupleOption; - /// - /// let tuple = (Some(1), Some(2)); - /// let transposed: Option<(i32, i32)> = tuple.transpose(); - /// assert_eq!(transposed, Some((1, 2))); - /// - /// let tuple = (Some(1), None); - /// let transposed: Option<(i32, i32)> = tuple.transpose(); - /// assert_eq!(transposed, None); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn transpose(self) -> Option; -} - -/// A trait for converting a tuple into a tuple of options. -pub trait IntoTupleOption { - /// The tuple of options type. - type IntoOptions: TupleOption + TupleDefault; - - /// Converts the tuple into a tuple of `Some` values. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_option::IntoTupleOption; - /// - /// let tuple = (1, 2); - /// let into_options: (Option, Option) = tuple.into_options(); - /// assert_eq!(into_options, (Some(1), Some(2))); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn into_options(self) -> Self::IntoOptions; -} diff --git a/tuplities-ord/Cargo.toml b/tuplities-ord/Cargo.toml deleted file mode 100644 index c79d627..0000000 --- a/tuplities-ord/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "tuplities-ord" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for total ordering comparison of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true -tuplities-eq.workspace = true -tuplities-partial-ord.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = [ - "tuplities-derive/size-16", - "tuplities-eq/size-16", - "tuplities-partial-ord/size-16", -] -size-32 = [ - "tuplities-derive/size-32", - "tuplities-eq/size-32", - "tuplities-partial-ord/size-32", -] -size-48 = [ - "tuplities-derive/size-48", - "tuplities-eq/size-48", - "tuplities-partial-ord/size-48", -] -size-64 = [ - "tuplities-derive/size-64", - "tuplities-eq/size-64", - "tuplities-partial-ord/size-64", -] -size-96 = [ - "tuplities-derive/size-96", - "tuplities-eq/size-96", - "tuplities-partial-ord/size-96", -] -size-128 = [ - "tuplities-derive/size-128", - "tuplities-eq/size-128", - "tuplities-partial-ord/size-128", -] diff --git a/tuplities-ord/src/lib.rs b/tuplities-ord/src/lib.rs deleted file mode 100644 index f647c50..0000000 --- a/tuplities-ord/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleOrd` trait. - -use tuplities_eq::TupleEq; -use tuplities_partial_ord::TuplePartialOrd; - -#[tuplities_derive::impl_tuple_ord] -/// A trait for comparing tuples for total ordering. -pub trait TupleOrd: TuplePartialOrd + TupleEq { - /// Returns the total ordering of `self` and `other`. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_ord::TupleOrd; - /// use core::cmp::Ordering; - /// - /// let tuple1 = (1, 2); - /// let tuple2 = (1, 3); - /// let tuple3 = (2, 1); - /// - /// assert_eq!(tuple1.tuple_cmp(&tuple2), Ordering::Less); - /// assert_eq!(tuple1.tuple_cmp(&tuple3), Ordering::Less); - /// assert_eq!(tuple1.tuple_cmp(&tuple1), Ordering::Equal); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn tuple_cmp(&self, other: &Self) -> core::cmp::Ordering; -} diff --git a/tuplities-partial-eq/Cargo.toml b/tuplities-partial-eq/Cargo.toml deleted file mode 100644 index e00e1f5..0000000 --- a/tuplities-partial-eq/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-partial-eq" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for partial equality comparison of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-partial-eq/src/lib.rs b/tuplities-partial-eq/src/lib.rs deleted file mode 100644 index 36b4deb..0000000 --- a/tuplities-partial-eq/src/lib.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TuplePartialEq` trait. - -#[tuplities_derive::impl_tuple_partial_eq] -/// A trait for comparing tuples for partial equality. -pub trait TuplePartialEq { - /// Returns `true` if `self` and `other` are equal. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_partial_eq::TuplePartialEq; - /// - /// let tuple1 = (1, "hello"); - /// let tuple2 = (1, "hello"); - /// let tuple3 = (2, "world"); - /// - /// assert!(tuple1.tuple_eq(&tuple2)); - /// assert!(!tuple1.tuple_eq(&tuple3)); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn tuple_eq(&self, other: &Self) -> bool; -} diff --git a/tuplities-partial-ord/Cargo.toml b/tuplities-partial-ord/Cargo.toml deleted file mode 100644 index f2f779d..0000000 --- a/tuplities-partial-ord/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "tuplities-partial-ord" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for partial ordering comparison of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true -tuplities-partial-eq.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16", "tuplities-partial-eq/size-16"] -size-32 = ["tuplities-derive/size-32", "tuplities-partial-eq/size-32"] -size-48 = ["tuplities-derive/size-48", "tuplities-partial-eq/size-48"] -size-64 = ["tuplities-derive/size-64", "tuplities-partial-eq/size-64"] -size-96 = ["tuplities-derive/size-96", "tuplities-partial-eq/size-96"] -size-128 = ["tuplities-derive/size-128", "tuplities-partial-eq/size-128"] diff --git a/tuplities-partial-ord/src/lib.rs b/tuplities-partial-ord/src/lib.rs deleted file mode 100644 index ce69922..0000000 --- a/tuplities-partial-ord/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TuplePartialOrd` trait. - -use tuplities_partial_eq::TuplePartialEq; - -#[tuplities_derive::impl_tuple_partial_ord] -/// A trait for comparing tuples for partial ordering. -pub trait TuplePartialOrd: TuplePartialEq { - /// Returns the partial ordering of `self` and `other`. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_partial_ord::TuplePartialOrd; - /// use core::cmp::Ordering; - /// - /// let tuple1 = (1, 2); - /// let tuple2 = (1, 3); - /// let tuple3 = (2, 1); - /// - /// assert_eq!(tuple1.tuple_partial_cmp(&tuple2), Some(Ordering::Less)); - /// assert_eq!(tuple1.tuple_partial_cmp(&tuple3), Some(Ordering::Less)); - /// assert_eq!(tuple1.tuple_partial_cmp(&tuple1), Some(Ordering::Equal)); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn tuple_partial_cmp(&self, other: &Self) -> Option; -} diff --git a/tuplities-pop-back/Cargo.toml b/tuplities-pop-back/Cargo.toml deleted file mode 100644 index b9e264d..0000000 --- a/tuplities-pop-back/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-pop-back" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for popping elements from the back of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-pop-back/src/lib.rs b/tuplities-pop-back/src/lib.rs deleted file mode 100644 index 119fd72..0000000 --- a/tuplities-pop-back/src/lib.rs +++ /dev/null @@ -1,95 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TuplePopBack` trait. - -#[tuplities_derive::impl_pop_back] -/// A trait for tuples that defines the `Init` and `Back` types, and provides a method to pop the back element. -pub trait TuplePopBack { - /// The type of the tuple without the last element. - type Init; - - /// The type of the last element. - type Back; - - /// Consumes the tuple and returns the initial part and the last element. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_pop_back::TuplePopBack; - /// - /// let tuple = (1, 2, 3); - /// let (front, back) = tuple.pop_back(); - /// assert_eq!(front, (1, 2)); - /// assert_eq!(back, 3); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn pop_back(self) -> (Self::Init, Self::Back); -} - -/// A trait for accessing a reference to the last element of a tuple. -/// -/// This trait provides a method to get a reference to the last element without consuming the tuple. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_pop_back::TupleRefBack; -/// -/// let tuple = (1, 2, 3); -/// let last = tuple.ref_back(); -/// assert_eq!(*last, 3); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleRefBack: TuplePopBack { - /// Returns a reference to the last element of the tuple. - fn ref_back(&self) -> &Self::Back; -} - -/// A trait for accessing a mutable reference to the last element of a tuple. -/// -/// This trait provides a method to get a mutable reference to the last element without consuming the tuple. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_pop_back::TupleMutBack; -/// -/// let mut tuple = (1, 2, 3); -/// let last = tuple.mut_back(); -/// *last = 42; -/// assert_eq!(tuple, (1, 2, 42)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleMutBack: TupleRefBack { - /// Returns a mutable reference to the last element of the tuple. - fn mut_back(&mut self) -> &mut Self::Back; -} - -#[cfg(test)] -mod tests { - use super::TuplePopBack; - - #[test] - fn test_pop_back_single_element_tuple() { - let tuple = (42,); - let (_init, back): ((), i32) = tuple.pop_back(); - // Check that the types are correct: (T,) -> Init = (), Back = T - let expected_back: i32 = 42; - assert_eq!(back, expected_back); - } - - #[test] - fn test_pop_back_two_element_tuple() { - let tuple = (1, 2); - let (init, back) = tuple.pop_back(); - // Check that the types are correct: (T1, T2) -> Init = (T1,), Back = T2 - let expected_init: (i32,) = (1,); - let expected_back: i32 = 2; - assert_eq!(init, expected_init); - assert_eq!(back, expected_back); - } -} diff --git a/tuplities-pop-front/Cargo.toml b/tuplities-pop-front/Cargo.toml deleted file mode 100644 index 01097cc..0000000 --- a/tuplities-pop-front/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-pop-front" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for popping elements from the front of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - -[dependencies] -tuplities-derive.workspace = true -tuplities-push-front.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-pop-front/src/lib.rs b/tuplities-pop-front/src/lib.rs deleted file mode 100644 index 9a28297..0000000 --- a/tuplities-pop-front/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TuplePopFront` trait. -use tuplities_push_front::TuplePushFront; - -#[tuplities_derive::impl_pop_front] -/// A trait for tuples that defines the `Front` and `Tail` types, and provides a method to pop the front element. -pub trait TuplePopFront { - /// The type of the first element. - type Front; - - /// The type of the tuple after removing the first element. - type Tail: TuplePushFront; - - /// Consumes the tuple and returns the first element and the remaining tuple. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_pop_front::TuplePopFront; - /// - /// let tuple = (1, 2, 3); - /// let (first, rest) = tuple.pop_front(); - /// assert_eq!(first, 1); - /// assert_eq!(rest, (2, 3)); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn pop_front(self) -> (Self::Front, Self::Tail); -} - -/// A trait for accessing a reference to the first element of a tuple. -/// -/// This trait provides a method to get a reference to the first element without consuming the tuple. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_pop_front::TupleRefFront; -/// -/// let tuple = (1, 2, 3); -/// let first = tuple.ref_front(); -/// assert_eq!(*first, 1); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleRefFront: TuplePopFront { - /// Returns a reference to the first element of the tuple. - fn ref_front(&self) -> &Self::Front; -} - -/// A trait for accessing a mutable reference to the first element of a tuple. -/// -/// This trait provides a method to get a mutable reference to the first element without consuming the tuple. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_pop_front::TupleMutFront; -/// -/// let mut tuple = (1, 2, 3); -/// let first = tuple.mut_front(); -/// *first = 42; -/// assert_eq!(tuple, (42, 2, 3)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleMutFront: TupleRefFront { - /// Returns a mutable reference to the first element of the tuple. - fn mut_front(&mut self) -> &mut Self::Front; -} - -#[cfg(test)] -mod tests { - use super::TuplePopFront; - - #[test] - fn test_pop_front_single_element_tuple() { - let tuple = (42,); - let (front, _tail): (i32, ()) = tuple.pop_front(); - // Check that the types are correct: (T,) -> Front = T, Tail = () - let expected_front: i32 = 42; - assert_eq!(front, expected_front); - } - - #[test] - fn test_pop_front_two_element_tuple() { - let tuple = (1, 2); - let (front, tail) = tuple.pop_front(); - // Check that the types are correct: (T1, T2) -> Front = T1, Tail = (T2,) - let expected_front: i32 = 1; - let expected_tail: (i32,) = (2,); - assert_eq!(front, expected_front); - assert_eq!(tail, expected_tail); - } -} diff --git a/tuplities-push-back/Cargo.toml b/tuplities-push-back/Cargo.toml deleted file mode 100644 index 37898f9..0000000 --- a/tuplities-push-back/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-push-back" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for pushing elements to the back of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-push-back/src/lib.rs b/tuplities-push-back/src/lib.rs deleted file mode 100644 index 43d26db..0000000 --- a/tuplities-push-back/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TuplePushBack` trait. - -#[tuplities_derive::impl_push_back] -/// A trait for tuples that allows pushing an element to the back. -pub trait TuplePushBack { - /// The type of the tuple after adding `T` to the back. - type Output; - - /// Consumes the tuple and appends the given value, returning the new tuple. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_push_back::TuplePushBack; - /// - /// let tuple = ("hello",); - /// let new_tuple = tuple.push_back("world"); - /// assert_eq!(new_tuple, ("hello", "world")); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn push_back(self, value: T) -> Self::Output; -} - -#[cfg(test)] -mod tests { - use super::TuplePushBack; - - #[test] - fn test_push_back_zero_sized_tuple() { - let tuple = (); - let result = tuple.push_back(42); - // Check that the type is correct: () + i32 = (i32,) - let expected: (i32,) = (42,); - assert_eq!(result, expected); - } -} diff --git a/tuplities-push-front/Cargo.toml b/tuplities-push-front/Cargo.toml deleted file mode 100644 index b14367c..0000000 --- a/tuplities-push-front/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "tuplities-push-front" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for pushing elements to the front of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-push-front/src/lib.rs b/tuplities-push-front/src/lib.rs deleted file mode 100644 index 68a0986..0000000 --- a/tuplities-push-front/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TuplePushFront` trait. - -#[tuplities_derive::impl_push_front] -/// A trait for tuples that allows pushing an element to the front. -pub trait TuplePushFront { - /// The type of the tuple after adding `T` to the front. - type Output; - - /// Consumes the tuple and prepends the given value, returning the new tuple. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_push_front::TuplePushFront; - /// - /// let tuple = ("world",); - /// let new_tuple = tuple.push_front("hello"); - /// assert_eq!(new_tuple, ("hello", "world")); - /// ``` - /// - /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. - fn push_front(self, value: T) -> Self::Output; -} - -#[cfg(test)] -mod tests { - use super::TuplePushFront; - - #[test] - fn test_push_front_zero_sized_tuple() { - let tuple: () = (); - let result: (i32,) = tuple.push_front(42); - // Check that the type is correct: i32 + () = (i32,) - let expected: (i32,) = (42,); - assert_eq!(result, expected); - } -} diff --git a/tuplities-ref/Cargo.toml b/tuplities-ref/Cargo.toml deleted file mode 100644 index b85ddfd..0000000 --- a/tuplities-ref/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-ref" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for getting tuples of references from tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-ref/src/lib.rs b/tuplities-ref/src/lib.rs deleted file mode 100644 index 755ee11..0000000 --- a/tuplities-ref/src/lib.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleRef` trait. - -#[tuplities_derive::impl_tuple_ref] -/// A trait for tuples that provides a method to get a tuple of references. -/// -/// This trait provides both an associated type `Ref<'a>` that represents a tuple -/// of references to the elements, and a method `tuple_ref` that returns such a tuple. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_ref::TupleRef; -/// -/// let tuple = (1, "hello".to_string(), vec![1, 2, 3]); -/// let refs = tuple.tuple_ref(); -/// assert_eq!(refs, (&1, &"hello".to_string(), &vec![1, 2, 3])); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleRef { - /// The type of a tuple containing references to each element. - type Ref<'a> - where - Self: 'a; - - /// Returns a tuple of references to each element. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_ref::TupleRef; - /// - /// let tuple = (42, "world"); - /// let refs = tuple.tuple_ref(); - /// assert_eq!(refs, (&42, &"world")); - /// ``` - fn tuple_ref(&self) -> Self::Ref<'_>; -} - -#[tuplities_derive::impl_tuple_ref_map] - -/// A trait for applying `TupleRef` to each element of a tuple. -/// -/// This trait takes a tuple where each element implements `TupleRef` and returns -/// a tuple where each element is the result of calling `tuple_ref()` on the original elements. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_ref::TupleRefMap; -/// -/// let matrix = ((1, 2), (3, 4), (5, 6)); -/// let ref_matrix = matrix.tuple_ref_map(); -/// assert_eq!(ref_matrix, ((&1, &2), (&3, &4), (&5, &6))); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleRefMap { - /// The type of a tuple containing tuples of references to each inner element. - type RefMap<'a> - where - Self: 'a; - - /// Returns a tuple where each element is a tuple of references to the inner elements. - fn tuple_ref_map(&self) -> Self::RefMap<'_>; -} diff --git a/tuplities-remove/Cargo.toml b/tuplities-remove/Cargo.toml deleted file mode 100644 index de9db40..0000000 --- a/tuplities-remove/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "tuplities-remove" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for removing elements from tuples at compile-time indices" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -typenum = { workspace = true } -tuplities-derive = { workspace = true } - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] - -[lints] -workspace = true diff --git a/tuplities-remove/src/lib.rs b/tuplities-remove/src/lib.rs deleted file mode 100644 index 3ce7d30..0000000 --- a/tuplities-remove/src/lib.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! A trait for removing elements at specific indices from tuples. -//! -//! This crate provides the `TupleRemove` trait, which allows removing an element -//! at a compile-time known index from a tuple, returning the element and the -//! remaining tuple. - -#![no_std] - -/// A trait for removing an element at a specific index from a tuple. -/// -/// This trait allows removing an element at compile-time known index `Idx` -/// from a tuple, returning the element and the remaining tuple. -/// -/// # Examples -/// -/// ``` -/// use tuplities_remove::TupleRemove; -/// use typenum::U1; -/// -/// let tuple = (1, "hello", 3.14); -/// let (removed, remainder) = TupleRemove::::remove(tuple); -/// assert_eq!(removed, "hello"); -/// assert_eq!(remainder, (1, 3.14)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_remove] -pub trait TupleRemove { - /// The type of the element being removed. - type Type; - - /// The type of the remaining tuple after removing. - type Remainder; - - /// Removes the element at index `Idx` from the tuple. - /// - /// Returns a tuple containing the removed element and the remaining tuple. - fn remove(self) -> (Self::Type, Self::Remainder); -} - -#[cfg(test)] -mod tests { - use super::TupleRemove; - use typenum::{U0, U1}; - - #[test] - fn test_remove_single_element_tuple() { - let tuple = (42,); - let (removed, _remainder): (i32, ()) = TupleRemove::::remove(tuple); - // Check types: (i32,) remove U0 -> Type = i32, Remainder = () - let expected_removed: i32 = 42; - assert_eq!(removed, expected_removed); - } - - #[test] - fn test_remove_two_element_tuple() { - // Remove at U0 - let tuple = (1, 2); - let (removed0, remainder0) = TupleRemove::::remove(tuple); - let expected_removed0: i32 = 1; - let expected_remainder0: (i32,) = (2,); - assert_eq!(removed0, expected_removed0); - assert_eq!(remainder0, expected_remainder0); - - // Remove at U1 - let tuple = (1, 2); - let (removed1, remainder1) = TupleRemove::::remove(tuple); - let expected_removed1: i32 = 2; - let expected_remainder1: (i32,) = (1,); - assert_eq!(removed1, expected_removed1); - assert_eq!(remainder1, expected_remainder1); - } -} diff --git a/tuplities-replicate/Cargo.toml b/tuplities-replicate/Cargo.toml deleted file mode 100644 index 82c451e..0000000 --- a/tuplities-replicate/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-replicate" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for replicating values into tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-replicate/src/lib.rs b/tuplities-replicate/src/lib.rs deleted file mode 100644 index 30da8ae..0000000 --- a/tuplities-replicate/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleReplicate` trait. - -#[tuplities_derive::impl_tuple_replicate] -/// A trait for replicating a value into a tuple. -/// -/// This trait allows creating a tuple where all elements are the same value. -/// The implementation is optimized to avoid unnecessary cloning: for empty tuples -/// and single-element tuples, no `Clone` bound is required. For tuples with 2+ -/// elements, `Clone` is required but the original value is moved to the last -/// position to minimize clones. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleReplicate { - /// Creates a tuple where all elements are the provided value. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_replicate::TupleReplicate; - /// - /// let tuple: (i32, i32, i32) = TupleReplicate::tuple_replicate(42); - /// assert_eq!(tuple, (42, 42, 42)); - /// let _tuple_empty: () = TupleReplicate::tuple_replicate(42); - /// let tuple_single: (i32,) = TupleReplicate::tuple_replicate(42); - /// assert_eq!(tuple_single, (42,)); - /// let tuple_two: (i32, i32) = TupleReplicate::tuple_replicate(42); - /// assert_eq!(tuple_two, (42, 42)); - /// - /// let tuple_refs: (&str, &str, &str) = TupleReplicate::tuple_replicate("hello"); - /// assert_eq!(tuple_refs, ("hello", "hello", "hello")); - /// - /// let tuple_strings: (String, String) = TupleReplicate::tuple_replicate(String::from("world")); - /// assert_eq!(tuple_strings, (String::from("world"), String::from("world"))); - /// - /// let tuple_refs2: (&i32, &i32) = TupleReplicate::tuple_replicate(&100); - /// assert_eq!(tuple_refs2, (&100, &100)); - /// ``` - fn tuple_replicate(value: T) -> Self; -} diff --git a/tuplities-reverse/Cargo.toml b/tuplities-reverse/Cargo.toml deleted file mode 100644 index 55f159a..0000000 --- a/tuplities-reverse/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tuplities-reverse" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for reversing the order of tuple elements" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-reverse/src/lib.rs b/tuplities-reverse/src/lib.rs deleted file mode 100644 index a6dfb38..0000000 --- a/tuplities-reverse/src/lib.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleReverse` trait. - -#[tuplities_derive::impl_reverse] -/// A trait for reversing the elements of a tuple. -/// -/// This trait provides a method to reverse the order of elements in a tuple. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_reverse::TupleReverse; -/// -/// let tuple = (1, "hello", 3.14); -/// let reversed = tuple.reverse(); -/// assert_eq!(reversed, (3.14, "hello", 1)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleReverse { - /// The type of the tuple with elements in reverse order. - type Output; - - /// Consumes the tuple and returns a new tuple with elements in reverse order. - fn reverse(self) -> Self::Output; -} - -#[cfg(test)] -mod tests { - use super::TupleReverse; - - #[test] - fn test_reverse_empty_tuple() { - let tuple = (); - let _reversed: () = tuple.reverse(); - } - - #[test] - fn test_reverse_single_element() { - let tuple = (42,); - let reversed = tuple.reverse(); - assert_eq!(reversed, (42,)); - } - - #[test] - fn test_reverse_two_elements() { - let tuple = (1, 2); - let reversed = tuple.reverse(); - assert_eq!(reversed, (2, 1)); - } - - #[test] - fn test_reverse_three_elements() { - let tuple = (1, 2, 3); - let reversed = tuple.reverse(); - assert_eq!(reversed, (3, 2, 1)); - } -} diff --git a/tuplities-row/Cargo.toml b/tuplities-row/Cargo.toml deleted file mode 100644 index c38d949..0000000 --- a/tuplities-row/Cargo.toml +++ /dev/null @@ -1,70 +0,0 @@ -[package] -name = "tuplities-row" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for indexing rows in tuples of tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - -[dependencies] -tuplities-derive.workspace = true -tuplities-index.workspace = true -tuplities-ref.workspace = true -tuplities-mut.workspace = true -tuplities-len.workspace = true -tuplities-pop-front.workspace = true -tuplities-pop-back.workspace = true -typenum.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = [ - "tuplities-derive/size-16", - "tuplities-index/size-16", - "tuplities-ref/size-16", - "tuplities-mut/size-16", - "tuplities-len/size-16", -] -size-32 = [ - "tuplities-derive/size-32", - "tuplities-index/size-32", - "tuplities-ref/size-32", - "tuplities-mut/size-32", - "tuplities-len/size-32", -] -size-48 = [ - "tuplities-derive/size-48", - "tuplities-index/size-48", - "tuplities-ref/size-48", - "tuplities-mut/size-48", - "tuplities-len/size-48", -] -size-64 = [ - "tuplities-derive/size-64", - "tuplities-index/size-64", - "tuplities-ref/size-64", - "tuplities-mut/size-64", - "tuplities-len/size-64", -] -size-96 = [ - "tuplities-derive/size-96", - "tuplities-index/size-96", - "tuplities-ref/size-96", - "tuplities-mut/size-96", - "tuplities-len/size-96", -] -size-128 = [ - "tuplities-derive/size-128", - "tuplities-index/size-128", - "tuplities-ref/size-128", - "tuplities-mut/size-128", - "tuplities-len/size-128", -] diff --git a/tuplities-row/src/lib.rs b/tuplities-row/src/lib.rs deleted file mode 100644 index f37ecf9..0000000 --- a/tuplities-row/src/lib.rs +++ /dev/null @@ -1,113 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleRow` and `TupleRowMut` traits. - -use tuplities_len::TupleLen; -use tuplities_mut::TupleMut; -use tuplities_ref::TupleRef; - -/// A trait for indexing rows in tuples of tuples. -/// -/// This trait allows accessing elements at a specific index across all tuples in a tuple of tuples. -/// For a tuple of tuples like `((A, B), (C, D))`, `TupleRow` would return `(&A, &C)` and `TupleRow` would return `(&B, &D)`. -/// -/// Each inner tuple must implement `TupleIndex`, and the returned row tuple implements `TupleRef`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_row::TupleRow; -/// use typenum::U0; -/// -/// let matrix = ((1, 2), (3, 4), (5, 6)); -/// let first_row = TupleRow::::tuple_row(&matrix); -/// assert_eq!(first_row, (&1, &3, &5)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_row] -pub trait TupleRow: TupleLen { - /// The type of the row tuple containing elements at index `Idx`. - type RowType: TupleRef + TupleLen::Len>; - - /// Returns a tuple of references to the elements at index `Idx` in each inner tuple. - fn tuple_row(&self) -> ::Ref<'_>; -} - -/// A trait for mutable indexing rows in tuples of tuples. -/// -/// This trait allows mutable access to elements at a specific index across all tuples in a tuple of tuples. -/// For a tuple of tuples like `((A, B), (C, D))`, `TupleRowMut` would return `(&mut A, &mut C)` and `TupleRowMut` would return `(&mut B, &mut D)`. -/// -/// Each inner tuple must implement `TupleIndexMut`, and the returned row tuple implements `TupleMut`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_row::TupleRowMut; -/// use typenum::U0; -/// -/// let mut matrix = ((1, 2), (3, 4), (5, 6)); -/// let first_row = TupleRowMut::::tuple_row_mut(&mut matrix); -/// *first_row.0 = 10; -/// *first_row.1 = 30; -/// *first_row.2 = 50; -/// assert_eq!(matrix, ((10, 2), (30, 4), (50, 6))); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_row_mut] -pub trait TupleRowMut: TupleRow { - /// Returns a tuple of mutable references to the elements at index `Idx` in each inner tuple. - fn tuple_row_mut(&mut self) -> ::Mut<'_>; -} - -/// A convenience trait for accessing the first row (index 0) in tuples of tuples. -/// -/// This trait is automatically implemented for any tuple of tuples where each inner tuple implements `TupleRefFront`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_row::FirstTupleRow; -/// -/// let matrix = ((1, 2), (3, 4), (5, 6)); -/// let first_row = matrix.first_tuple_row(); -/// assert_eq!(first_row, (&1, &3, &5)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_first_tuple_row] -pub trait FirstTupleRow: TupleLen { - /// The type of the row tuple containing references to the first elements. - type FirstRowType: TupleRef + TupleLen::Len>; - - /// Returns a tuple of references to the first element in each inner tuple. - fn first_tuple_row(&self) -> ::Ref<'_>; -} - -/// A convenience trait for accessing the last row in tuples of tuples. -/// -/// This trait is automatically implemented for tuples of tuples where the implementation -/// depends on the length of the inner tuples. It provides access to the last element -/// of each inner tuple. -/// -/// # Examples -/// -/// ``` -/// use tuplities_row::LastTupleRow; -/// -/// let matrix = ((1, 2, 3), (4, 5, 6), (7, 8, 9)); -/// let last_row = matrix.last_tuple_row(); -/// assert_eq!(last_row, (&3, &6, &9)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_last_tuple_row] -pub trait LastTupleRow: TupleLen { - /// The type of the row tuple containing references to the last elements. - type LastRowType: TupleRef + TupleLen::Len>; - - /// Returns a tuple of references to the last element in each inner tuple. - fn last_tuple_row(&self) -> ::Ref<'_>; -} diff --git a/tuplities-split/Cargo.toml b/tuplities-split/Cargo.toml deleted file mode 100644 index a679832..0000000 --- a/tuplities-split/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "tuplities-split" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "A trait for splitting tuples at compile-time indices" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - - -[dependencies] -tuplities-derive.workspace = true -typenum.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-split/src/lib.rs b/tuplities-split/src/lib.rs deleted file mode 100644 index 92ef853..0000000 --- a/tuplities-split/src/lib.rs +++ /dev/null @@ -1,111 +0,0 @@ -#![no_std] - -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleSplit` trait. - -/// A trait for splitting a tuple at a compile-time known index. -/// -/// This trait allows splitting a tuple at a specific compile-time known index `Idx`, -/// returning two tuples: the elements before the index and the elements at and after the index. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_split::TupleSplit; -/// use typenum::U2; -/// -/// let tuple = (1, 2, 3, 4); -/// let (left, right) = TupleSplit::::split(tuple); -/// assert_eq!(left, (1, 2)); -/// assert_eq!(right, (3, 4)); -/// ``` -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -#[tuplities_derive::impl_split] -pub trait TupleSplit { - /// The type of the tuple containing elements before the split index. - type Left; - - /// The type of the tuple containing elements at and after the split index. - type Right; - - /// Splits the tuple at index `Idx`, returning two tuples. - fn split(self) -> (Self::Left, Self::Right); -} - -#[cfg(test)] -mod tests { - use super::TupleSplit; - use typenum::{U0, U1, U2, U3}; - - #[test] - fn test_split_at_zero() { - let tuple = (1, 2, 3); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, ()); - assert_eq!(right, (1, 2, 3)); - } - - #[test] - fn test_split_at_middle() { - let tuple = (1, 2, 3, 4); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, (1, 2)); - assert_eq!(right, (3, 4)); - } - - #[test] - fn test_split_at_end() { - let tuple = (1, 2, 3); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, (1, 2, 3)); - assert_eq!(right, ()); - } - - #[test] - fn test_split_empty_tuple() { - let tuple = (); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, ()); - assert_eq!(right, ()); - } - - #[test] - fn test_split_single_element_at_zero() { - let tuple = (42,); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, ()); - assert_eq!(right, (42,)); - } - - #[test] - fn test_split_single_element_at_one() { - let tuple = (42,); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, (42,)); - assert_eq!(right, ()); - } - - #[test] - fn test_split_two_elements_at_zero() { - let tuple = (1, 2); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, ()); - assert_eq!(right, (1, 2)); - } - - #[test] - fn test_split_two_elements_at_one() { - let tuple = (1, 2); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, (1,)); - assert_eq!(right, (2,)); - } - - #[test] - fn test_split_two_elements_at_two() { - let tuple = (1, 2); - let (left, right) = TupleSplit::::split(tuple); - assert_eq!(left, (1, 2)); - assert_eq!(right, ()); - } -} diff --git a/tuplities-try-from/Cargo.toml b/tuplities-try-from/Cargo.toml deleted file mode 100644 index 7e32b0f..0000000 --- a/tuplities-try-from/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "tuplities-try-from" -version.workspace = true -edition.workspace = true -authors.workspace = true -description = "Traits for fallible conversion of values into tuples" -readme.workspace = true -license-file.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -homepage.workspace = true - -[dependencies] -tuplities-derive.workspace = true - -[lints] -workspace = true - -[features] -default = [] -size-16 = ["tuplities-derive/size-16"] -size-32 = ["tuplities-derive/size-32"] -size-48 = ["tuplities-derive/size-48"] -size-64 = ["tuplities-derive/size-64"] -size-96 = ["tuplities-derive/size-96"] -size-128 = ["tuplities-derive/size-128"] diff --git a/tuplities-try-from/src/lib.rs b/tuplities-try-from/src/lib.rs deleted file mode 100644 index 38424a4..0000000 --- a/tuplities-try-from/src/lib.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! [tuplities](https://github.com/lucacappelletti94/tuplities) suite crate providing the `TupleTryFrom` and `TupleTryInto` traits. - -#[tuplities_derive::impl_tuple_try_from] -/// A trait for fallibly converting from one tuple type to another. -/// -/// This trait allows converting between tuples where each element can be converted -/// using the standard `TryFrom` trait. The error type `E` must implement `From` for -/// each individual `TryFrom` error in the tuple, allowing error accumulation. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleTryFrom { - /// Attempts to convert from `T` into `Self`. - /// - /// # Errors - /// - /// Returns an error of type `E` if any element conversion fails. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_try_from::TupleTryFrom; - /// - /// let source = (1u32, 2u32); - /// let target: Result<(u8, u8), _> = TupleTryFrom::<_, std::num::TryFromIntError>::tuple_try_from(source); - /// assert_eq!(target, Ok((1, 2))); - /// - /// let invalid = (300u32, 2u32); // 300 is too big for u8 - /// let result: Result<(u8, u8), _> = TupleTryFrom::<_, std::num::TryFromIntError>::tuple_try_from(invalid); - /// assert!(result.is_err()); - /// ``` - fn tuple_try_from(value: T) -> Result - where - Self: Sized; -} - -/// A trait for fallibly converting a tuple into another tuple type. -/// -/// This trait allows converting tuples into other tuple types where each element can be converted -/// using the standard `TryFrom` trait. The error type `E` must implement `From` for -/// each individual `TryFrom` error in the tuple, allowing error accumulation. -/// -/// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait TupleTryInto { - /// Attempts to convert `self` into `T`. - /// - /// # Errors - /// - /// Returns an error of type `E` if any element conversion fails. - /// - /// # Examples - /// - /// ```rust - /// use tuplities_try_from::TupleTryInto; - /// - /// let source = (1u32, 2u32); - /// let target: Result<(u8, u8), _> = TupleTryInto::<(u8, u8), std::num::TryFromIntError>::tuple_try_into(source); - /// assert_eq!(target, Ok((1, 2))); - /// - /// let invalid = (300u32, 2u32); // 300 is too big for u8 - /// let result: Result<(u8, u8), _> = TupleTryInto::<(u8, u8), std::num::TryFromIntError>::tuple_try_into(invalid); - /// assert!(result.is_err()); - /// ``` - fn tuple_try_into(self) -> Result; -} - -// Blanket implementation of TupleTryInto based on TupleTryFrom -impl TupleTryInto for U -where - T: TupleTryFrom, -{ - fn tuple_try_into(self) -> Result { - T::tuple_try_from(self) - } -} diff --git a/tuplities/Cargo.toml b/tuplities/Cargo.toml index a280333..d523922 100644 --- a/tuplities/Cargo.toml +++ b/tuplities/Cargo.toml @@ -4,274 +4,34 @@ version.workspace = true edition.workspace = true authors.workspace = true description.workspace = true -readme.workspace = true -license-file.workspace = true +readme = "README.md" +license.workspace = true repository.workspace = true keywords.workspace = true categories.workspace = true -homepage.workspace = true - +rust-version.workspace = true [dependencies] -tuplities-clone = { workspace = true, optional = true } -tuplities-copy = { workspace = true, optional = true } -tuplities-debug = { workspace = true, optional = true } -tuplities-default = { workspace = true, optional = true } -tuplities-eq = { workspace = true, optional = true } -tuplities-flatten-nest = { workspace = true, optional = true } -tuplities-from = { workspace = true, optional = true } -tuplities-hash = { workspace = true, optional = true } -tuplities-mut = { workspace = true, optional = true } -tuplities-option = { workspace = true, optional = true } -tuplities-ord = { workspace = true, optional = true } -tuplities-partial-eq = { workspace = true, optional = true } -tuplities-partial-ord = { workspace = true, optional = true } -tuplities-remove = { workspace = true, optional = true } -tuplities-insert = { workspace = true, optional = true } -tuplities-len = { workspace = true, optional = true } -tuplities-index = { workspace = true, optional = true } -tuplities-pop-front = { workspace = true, optional = true } -tuplities-pop-back = { workspace = true, optional = true } -tuplities-push-front = { workspace = true, optional = true } -tuplities-push-back = { workspace = true, optional = true } -tuplities-ref = { workspace = true, optional = true } -tuplities-replicate = { workspace = true, optional = true } -tuplities-reverse = { workspace = true, optional = true } -tuplities-row = { workspace = true, optional = true } -tuplities-split = { workspace = true, optional = true } -tuplities-try-from = { workspace = true, optional = true } +typenum.workspace = true [lints] workspace = true [features] -default = [ - "clone", - "copy", - "debug", - "tuple-default", - "eq", - "flatten-nest", - "from", - "hash", - "mut", - "option", - "ord", - "partial-eq", - "partial-ord", - "remove", - "insert", - "len", - "index", - "pop-front", - "pop-back", - "push-front", - "push-back", - "ref", - "replicate", - "reverse", - "row", - "split", - "try-from", -] -clone = ["tuplities-clone"] -copy = ["tuplities-copy"] -debug = ["tuplities-debug"] -tuple-default = ["tuplities-default"] -eq = ["tuplities-eq"] -flatten-nest = ["tuplities-flatten-nest"] -from = ["tuplities-from"] -hash = ["tuplities-hash"] -mut = ["tuplities-mut"] -option = ["tuplities-option"] -ord = ["tuplities-ord"] -partial-eq = ["tuplities-partial-eq"] -partial-ord = ["tuplities-partial-ord"] -remove = ["tuplities-remove"] -insert = ["tuplities-insert"] -len = ["tuplities-len"] -index = ["tuplities-index"] -pop-front = ["tuplities-pop-front"] -pop-back = ["tuplities-pop-back"] -push-front = ["tuplities-push-front"] -push-back = ["tuplities-push-back"] -ref = ["tuplities-ref"] -replicate = ["tuplities-replicate"] -reverse = ["tuplities-reverse"] -row = ["tuplities-row"] -split = ["tuplities-split"] -try-from = ["tuplities-try-from"] -size-16 = [ - "tuplities-clone/size-16", - "tuplities-copy/size-16", - "tuplities-debug/size-16", - "tuplities-default/size-16", - "tuplities-eq/size-16", - "tuplities-flatten-nest/size-16", - "tuplities-from/size-16", - "tuplities-hash/size-16", - "tuplities-mut/size-16", - "tuplities-option/size-16", - "tuplities-ord/size-16", - "tuplities-partial-eq/size-16", - "tuplities-partial-ord/size-16", - "tuplities-remove/size-16", - "tuplities-insert/size-16", - "tuplities-len/size-16", - "tuplities-index/size-16", - "tuplities-pop-front/size-16", - "tuplities-pop-back/size-16", - "tuplities-push-front/size-16", - "tuplities-push-back/size-16", - "tuplities-ref/size-16", - "tuplities-replicate/size-16", - "tuplities-reverse/size-16", - "tuplities-row/size-16", - "tuplities-split/size-16", - "tuplities-try-from/size-16", -] -size-32 = [ - "tuplities-clone/size-32", - "tuplities-copy/size-32", - "tuplities-debug/size-32", - "tuplities-default/size-32", - "tuplities-eq/size-32", - "tuplities-flatten-nest/size-32", - "tuplities-from/size-32", - "tuplities-hash/size-32", - "tuplities-mut/size-32", - "tuplities-option/size-32", - "tuplities-ord/size-32", - "tuplities-partial-eq/size-32", - "tuplities-partial-ord/size-32", - "tuplities-remove/size-32", - "tuplities-insert/size-32", - "tuplities-len/size-32", - "tuplities-index/size-32", - "tuplities-pop-front/size-32", - "tuplities-pop-back/size-32", - "tuplities-push-front/size-32", - "tuplities-push-back/size-32", - "tuplities-ref/size-32", - "tuplities-replicate/size-32", - "tuplities-reverse/size-32", - "tuplities-row/size-32", - "tuplities-split/size-32", - "tuplities-try-from/size-32", -] -size-48 = [ - "tuplities-clone/size-48", - "tuplities-copy/size-48", - "tuplities-debug/size-48", - "tuplities-default/size-48", - "tuplities-eq/size-48", - "tuplities-flatten-nest/size-48", - "tuplities-from/size-48", - "tuplities-hash/size-48", - "tuplities-mut/size-48", - "tuplities-option/size-48", - "tuplities-ord/size-48", - "tuplities-partial-eq/size-48", - "tuplities-partial-ord/size-48", - "tuplities-remove/size-48", - "tuplities-insert/size-48", - "tuplities-len/size-48", - "tuplities-index/size-48", - "tuplities-pop-front/size-48", - "tuplities-pop-back/size-48", - "tuplities-push-front/size-48", - "tuplities-push-back/size-48", - "tuplities-ref/size-48", - "tuplities-replicate/size-48", - "tuplities-reverse/size-48", - "tuplities-row/size-48", - "tuplities-split/size-48", - "tuplities-try-from/size-48", -] -size-64 = [ - "tuplities-clone/size-64", - "tuplities-copy/size-64", - "tuplities-debug/size-64", - "tuplities-default/size-64", - "tuplities-eq/size-64", - "tuplities-flatten-nest/size-64", - "tuplities-from/size-64", - "tuplities-hash/size-64", - "tuplities-mut/size-64", - "tuplities-option/size-64", - "tuplities-ord/size-64", - "tuplities-partial-eq/size-64", - "tuplities-partial-ord/size-64", - "tuplities-remove/size-64", - "tuplities-insert/size-64", - "tuplities-len/size-64", - "tuplities-index/size-64", - "tuplities-pop-front/size-64", - "tuplities-pop-back/size-64", - "tuplities-push-front/size-64", - "tuplities-push-back/size-64", - "tuplities-ref/size-64", - "tuplities-replicate/size-64", - "tuplities-reverse/size-64", - "tuplities-row/size-64", - "tuplities-split/size-64", - "tuplities-try-from/size-64", -] -size-96 = [ - "tuplities-clone/size-96", - "tuplities-copy/size-96", - "tuplities-debug/size-96", - "tuplities-default/size-96", - "tuplities-eq/size-96", - "tuplities-flatten-nest/size-96", - "tuplities-from/size-96", - "tuplities-hash/size-96", - "tuplities-mut/size-96", - "tuplities-option/size-96", - "tuplities-ord/size-96", - "tuplities-partial-eq/size-96", - "tuplities-partial-ord/size-96", - "tuplities-remove/size-96", - "tuplities-insert/size-96", - "tuplities-len/size-96", - "tuplities-index/size-96", - "tuplities-pop-front/size-96", - "tuplities-pop-back/size-96", - "tuplities-push-front/size-96", - "tuplities-push-back/size-96", - "tuplities-ref/size-96", - "tuplities-replicate/size-96", - "tuplities-reverse/size-96", - "tuplities-row/size-96", - "tuplities-split/size-96", - "tuplities-try-from/size-96", -] -size-128 = [ - "tuplities-clone/size-128", - "tuplities-copy/size-128", - "tuplities-debug/size-128", - "tuplities-default/size-128", - "tuplities-eq/size-128", - "tuplities-flatten-nest/size-128", - "tuplities-from/size-128", - "tuplities-hash/size-128", - "tuplities-mut/size-128", - "tuplities-option/size-128", - "tuplities-ord/size-128", - "tuplities-partial-eq/size-128", - "tuplities-partial-ord/size-128", - "tuplities-remove/size-128", - "tuplities-insert/size-128", - "tuplities-len/size-128", - "tuplities-index/size-128", - "tuplities-pop-front/size-128", - "tuplities-pop-back/size-128", - "tuplities-push-front/size-128", - "tuplities-push-back/size-128", - "tuplities-ref/size-128", - "tuplities-replicate/size-128", - "tuplities-reverse/size-128", - "tuplities-row/size-128", - "tuplities-split/size-128", - "tuplities-try-from/size-128", -] +default = ["flatten-nest"] +alloc = [] +flatten-nest = ["alloc"] +size-16 = [] +size-32 = [] +size-48 = [] +size-64 = [] +size-96 = [] +size-128 = [] + +[[test]] +name = "flat_bridge_contracts" +required-features = ["flatten-nest"] + +[[test]] +name = "flat_bridge_sizes" +required-features = ["flatten-nest"] diff --git a/tuplities/LICENSE b/tuplities/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/tuplities/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/tuplities/src/flat_bridge.rs b/tuplities/src/flat_bridge.rs new file mode 100644 index 0000000..fff8c6d --- /dev/null +++ b/tuplities/src/flat_bridge.rs @@ -0,0 +1,134 @@ +//! Flat tuple conversions up to the selected arity. + +use crate::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + +macro_rules! nested_type { + ($head:ty) => { ($head,) }; + ($head:ty, $($tail:ty),+) => { ($head, nested_type!($($tail),+)) }; +} + +macro_rules! nested_value { + ($head:expr) => { ($head,) }; + ($head:expr, $($tail:expr),+) => { ($head, nested_value!($($tail),+)) }; +} + +macro_rules! nested_pattern { + ($head:ident) => { ($head,) }; + ($head:ident, $($tail:ident),+) => { ($head, nested_pattern!($($tail),+)) }; +} + +macro_rules! flat_bridge { + ($($ty:ident $value:ident $index:tt),+) => { + impl<$($ty),+> NestTuple for ($($ty,)+) { + type Nested = nested_type!($($ty),+); + + #[inline] + fn nest(self) -> Self::Nested { + nested_value!($(self.$index),+) + } + } + + impl<$($ty),+> NestTupleRef for ($($ty,)+) { + type NestedRef<'a> = nested_type!($(&'a $ty),+) where Self: 'a; + + #[inline] + fn nest_ref(&self) -> Self::NestedRef<'_> { + nested_value!($(&self.$index),+) + } + } + + impl<$($ty),+> NestTupleMut for ($($ty,)+) { + type NestedMut<'a> = nested_type!($(&'a mut $ty),+) where Self: 'a; + + #[inline] + fn nest_mut(&mut self) -> Self::NestedMut<'_> { + nested_value!($(&mut self.$index),+) + } + } + + impl<$($ty),+> FlattenNestedTuple for nested_type!($($ty),+) { + type Flattened = ($($ty,)+); + + #[inline] + fn flatten(self) -> Self::Flattened { + let nested_pattern!($($value),+) = self; + ($($value,)+) + } + } + }; +} + +macro_rules! bridge_prefixes { + (($($ty:ident $value:ident $index:tt),*);) => {}; + (($($ty:ident $value:ident $index:tt),*); + $next_ty:ident $next_value:ident $next_index:tt + $(, $rest_ty:ident $rest_value:ident $rest_index:tt)*) => { + flat_bridge!($($ty $value $index,)* $next_ty $next_value $next_index); + bridge_prefixes!( + ($($ty $value $index,)* $next_ty $next_value $next_index); + $($rest_ty $rest_value $rest_index),* + ); + }; +} + +bridge_prefixes!((T0 v0 0); T1 v1 1, T2 v2 2, T3 v3 3, T4 v4 4, T5 v5 5, T6 v6 6, T7 v7 7); + +#[cfg(any( + feature = "size-16", + feature = "size-32", + feature = "size-48", + feature = "size-64", + feature = "size-96", + feature = "size-128" +))] +mod width_16 { + use super::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + + bridge_prefixes!((T0 v0 0, T1 v1 1, T2 v2 2, T3 v3 3, T4 v4 4, T5 v5 5, T6 v6 6, T7 v7 7); T8 v8 8, T9 v9 9, T10 v10 10, T11 v11 11, T12 v12 12, T13 v13 13, T14 v14 14, T15 v15 15); +} + +#[cfg(any( + feature = "size-32", + feature = "size-48", + feature = "size-64", + feature = "size-96", + feature = "size-128" +))] +mod width_32 { + use super::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + + bridge_prefixes!((T0 v0 0, T1 v1 1, T2 v2 2, T3 v3 3, T4 v4 4, T5 v5 5, T6 v6 6, T7 v7 7, T8 v8 8, T9 v9 9, T10 v10 10, T11 v11 11, T12 v12 12, T13 v13 13, T14 v14 14, T15 v15 15); T16 v16 16, T17 v17 17, T18 v18 18, T19 v19 19, T20 v20 20, T21 v21 21, T22 v22 22, T23 v23 23, T24 v24 24, T25 v25 25, T26 v26 26, T27 v27 27, T28 v28 28, T29 v29 29, T30 v30 30, T31 v31 31); +} + +#[cfg(any( + feature = "size-48", + feature = "size-64", + feature = "size-96", + feature = "size-128" +))] +mod width_48 { + use super::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + + bridge_prefixes!((T0 v0 0, T1 v1 1, T2 v2 2, T3 v3 3, T4 v4 4, T5 v5 5, T6 v6 6, T7 v7 7, T8 v8 8, T9 v9 9, T10 v10 10, T11 v11 11, T12 v12 12, T13 v13 13, T14 v14 14, T15 v15 15, T16 v16 16, T17 v17 17, T18 v18 18, T19 v19 19, T20 v20 20, T21 v21 21, T22 v22 22, T23 v23 23, T24 v24 24, T25 v25 25, T26 v26 26, T27 v27 27, T28 v28 28, T29 v29 29, T30 v30 30, T31 v31 31); T32 v32 32, T33 v33 33, T34 v34 34, T35 v35 35, T36 v36 36, T37 v37 37, T38 v38 38, T39 v39 39, T40 v40 40, T41 v41 41, T42 v42 42, T43 v43 43, T44 v44 44, T45 v45 45, T46 v46 46, T47 v47 47); +} + +#[cfg(any(feature = "size-64", feature = "size-96", feature = "size-128"))] +mod width_64 { + use super::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + + bridge_prefixes!((T0 v0 0, T1 v1 1, T2 v2 2, T3 v3 3, T4 v4 4, T5 v5 5, T6 v6 6, T7 v7 7, T8 v8 8, T9 v9 9, T10 v10 10, T11 v11 11, T12 v12 12, T13 v13 13, T14 v14 14, T15 v15 15, T16 v16 16, T17 v17 17, T18 v18 18, T19 v19 19, T20 v20 20, T21 v21 21, T22 v22 22, T23 v23 23, T24 v24 24, T25 v25 25, T26 v26 26, T27 v27 27, T28 v28 28, T29 v29 29, T30 v30 30, T31 v31 31, T32 v32 32, T33 v33 33, T34 v34 34, T35 v35 35, T36 v36 36, T37 v37 37, T38 v38 38, T39 v39 39, T40 v40 40, T41 v41 41, T42 v42 42, T43 v43 43, T44 v44 44, T45 v45 45, T46 v46 46, T47 v47 47); T48 v48 48, T49 v49 49, T50 v50 50, T51 v51 51, T52 v52 52, T53 v53 53, T54 v54 54, T55 v55 55, T56 v56 56, T57 v57 57, T58 v58 58, T59 v59 59, T60 v60 60, T61 v61 61, T62 v62 62, T63 v63 63); +} + +#[cfg(any(feature = "size-96", feature = "size-128"))] +mod width_96 { + use super::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + + bridge_prefixes!((T0 v0 0, T1 v1 1, T2 v2 2, T3 v3 3, T4 v4 4, T5 v5 5, T6 v6 6, T7 v7 7, T8 v8 8, T9 v9 9, T10 v10 10, T11 v11 11, T12 v12 12, T13 v13 13, T14 v14 14, T15 v15 15, T16 v16 16, T17 v17 17, T18 v18 18, T19 v19 19, T20 v20 20, T21 v21 21, T22 v22 22, T23 v23 23, T24 v24 24, T25 v25 25, T26 v26 26, T27 v27 27, T28 v28 28, T29 v29 29, T30 v30 30, T31 v31 31, T32 v32 32, T33 v33 33, T34 v34 34, T35 v35 35, T36 v36 36, T37 v37 37, T38 v38 38, T39 v39 39, T40 v40 40, T41 v41 41, T42 v42 42, T43 v43 43, T44 v44 44, T45 v45 45, T46 v46 46, T47 v47 47, T48 v48 48, T49 v49 49, T50 v50 50, T51 v51 51, T52 v52 52, T53 v53 53, T54 v54 54, T55 v55 55, T56 v56 56, T57 v57 57, T58 v58 58, T59 v59 59, T60 v60 60, T61 v61 61, T62 v62 62, T63 v63 63); T64 v64 64, T65 v65 65, T66 v66 66, T67 v67 67, T68 v68 68, T69 v69 69, T70 v70 70, T71 v71 71, T72 v72 72, T73 v73 73, T74 v74 74, T75 v75 75, T76 v76 76, T77 v77 77, T78 v78 78, T79 v79 79, T80 v80 80, T81 v81 81, T82 v82 82, T83 v83 83, T84 v84 84, T85 v85 85, T86 v86 86, T87 v87 87, T88 v88 88, T89 v89 89, T90 v90 90, T91 v91 91, T92 v92 92, T93 v93 93, T94 v94 94, T95 v95 95); +} + +#[cfg(feature = "size-128")] +mod width_128 { + use super::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + + bridge_prefixes!((T0 v0 0, T1 v1 1, T2 v2 2, T3 v3 3, T4 v4 4, T5 v5 5, T6 v6 6, T7 v7 7, T8 v8 8, T9 v9 9, T10 v10 10, T11 v11 11, T12 v12 12, T13 v13 13, T14 v14 14, T15 v15 15, T16 v16 16, T17 v17 17, T18 v18 18, T19 v19 19, T20 v20 20, T21 v21 21, T22 v22 22, T23 v23 23, T24 v24 24, T25 v25 25, T26 v26 26, T27 v27 27, T28 v28 28, T29 v29 29, T30 v30 30, T31 v31 31, T32 v32 32, T33 v33 33, T34 v34 34, T35 v35 35, T36 v36 36, T37 v37 37, T38 v38 38, T39 v39 39, T40 v40 40, T41 v41 41, T42 v42 42, T43 v43 43, T44 v44 44, T45 v45 45, T46 v46 46, T47 v47 47, T48 v48 48, T49 v49 49, T50 v50 50, T51 v51 51, T52 v52 52, T53 v53 53, T54 v54 54, T55 v55 55, T56 v56 56, T57 v57 57, T58 v58 58, T59 v59 59, T60 v60 60, T61 v61 61, T62 v62 62, T63 v63 63, T64 v64 64, T65 v65 65, T66 v66 66, T67 v67 67, T68 v68 68, T69 v69 69, T70 v70 70, T71 v71 71, T72 v72 72, T73 v73 73, T74 v74 74, T75 v75 75, T76 v76 76, T77 v77 77, T78 v78 78, T79 v79 79, T80 v80 80, T81 v81 81, T82 v82 82, T83 v83 83, T84 v84 84, T85 v85 85, T86 v86 86, T87 v87 87, T88 v88 88, T89 v89 89, T90 v90 90, T91 v91 91, T92 v92 92, T93 v93 93, T94 v94 94, T95 v95 95); T96 v96 96, T97 v97 97, T98 v98 98, T99 v99 99, T100 v100 100, T101 v101 101, T102 v102 102, T103 v103 103, T104 v104 104, T105 v105 105, T106 v106 106, T107 v107 107, T108 v108 108, T109 v109 109, T110 v110 110, T111 v111 111, T112 v112 112, T113 v113 113, T114 v114 114, T115 v115 115, T116 v116 116, T117 v117 117, T118 v118 118, T119 v119 119, T120 v120 120, T121 v121 121, T122 v122 122, T123 v123 123, T124 v124 124, T125 v125 125, T126 v126 126, T127 v127 127); +} diff --git a/tuplities-flatten-nest/src/flatten_nested.rs b/tuplities/src/flatten_nested.rs similarity index 70% rename from tuplities-flatten-nest/src/flatten_nested.rs rename to tuplities/src/flatten_nested.rs index 4f49927..f56c4cc 100644 --- a/tuplities-flatten-nest/src/flatten_nested.rs +++ b/tuplities/src/flatten_nested.rs @@ -1,8 +1,6 @@ //! Module providing the `FlattenNestedTuple` trait for flattening nested tuples. -use tuplities_push_front::TuplePushFront; - -use crate::NestTuple; +use crate::nest::NestTuple; /// A trait for flattening nested tuples into flat tuples. /// @@ -15,6 +13,19 @@ pub trait FlattenNestedTuple { type Flattened: NestTuple; /// Flattens the nested tuple into a flat tuple. + /// + /// # Examples + /// + /// ``` + /// use tuplities::FlattenNestedTuple; + /// + /// assert_eq!((7_u8,).flatten(), (7_u8,)); + /// + /// # #[cfg(feature = "flatten-nest")] { + /// let nested = (1, (2, (3,))); + /// assert_eq!(nested.flatten(), (1, 2, 3)); + /// # } + /// ``` fn flatten(self) -> Self::Flattened; } @@ -35,20 +46,7 @@ impl FlattenNestedTuple for (N1,) { } } -impl FlattenNestedTuple for (Head, Tail) -where - Tail: FlattenNestedTuple>>, -{ - type Flattened = >::Output; - - #[inline] - fn flatten(self) -> Self::Flattened { - let (head, tail) = self; - tail.flatten().push_front(head) - } -} - -#[cfg(test)] +#[cfg(all(test, feature = "flatten-nest"))] mod tests { use super::*; diff --git a/tuplities/src/lib.rs b/tuplities/src/lib.rs index 2612eba..787b99c 100644 --- a/tuplities/src/lib.rs +++ b/tuplities/src/lib.rs @@ -1,74 +1,80 @@ #![no_std] +#![recursion_limit = "256"] #![doc = include_str!("../README.md")] -/// Re-exports of commonly used traits and types. +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "flatten-nest")] +mod flat_bridge; +mod flatten_nested; +#[cfg(feature = "flatten-nest")] +mod matrix; +mod nest; +mod nested_chain; +mod nested_index; +#[cfg(feature = "alloc")] +mod nested_into_vec; +mod nested_option; +mod nested_option_try_from; +mod nested_push_pop; +mod nested_ref; +mod nested_replicate; +mod nested_reverse; +mod nested_row; +mod nested_starts_with; +mod nested_structure; +mod nested_try_from; +mod nested_tuple; + +pub use flatten_nested::FlattenNestedTuple; +#[cfg(feature = "flatten-nest")] +pub use matrix::{ + FlattenMatrixElements, FlattenNestedTupleMatrix, NestMatrixElements, NestTupleMatrix, +}; +pub use nest::{NestTuple, NestTupleMut, NestTupleRef}; +pub use nested_chain::NestedTupleChain; +pub use nested_index::{NestedTupleIndex, NestedTupleIndexMut}; +#[cfg(feature = "alloc")] +pub use nested_into_vec::NestedTupleIntoVec; +pub use nested_option::{ + IntoNestedTupleOption, NestedTupleFlattenOption, NestedTupleOption, NestedTupleOptionWith, +}; +pub use nested_option_try_from::{ + NestedTupleOptionFrom, NestedTupleOptionInto, NestedTupleOptionTryFrom, + NestedTupleOptionTryInto, +}; +pub use nested_push_pop::{ + NestedTuplePopBack, NestedTuplePopFront, NestedTuplePushBack, NestedTuplePushFront, +}; +pub use nested_ref::{NestedTupleMut, NestedTupleRef}; +pub use nested_replicate::NestedTupleReplicate; +pub use nested_reverse::NestedTupleReverse; +pub use nested_row::{NestedTupleRow, NestedTupleRowMut}; +pub use nested_starts_with::NestedTupleStartsWith; +pub use nested_structure::{NestedTupleInsert, NestedTupleRemove, NestedTupleSplit}; +pub use nested_try_from::{ + NestedTupleFrom, NestedTupleInto, NestedTupleTryFrom, NestedTupleTryInto, +}; +pub use nested_tuple::NestedTuple; + +/// Traits and construction macros for recursive tuples and optional flat-tuple conversions. pub mod prelude { - #[cfg(feature = "clone")] - pub use tuplities_clone::TupleClone; - #[cfg(feature = "copy")] - pub use tuplities_copy::TupleCopy; - #[cfg(feature = "debug")] - pub use tuplities_debug::TupleDebug; - #[cfg(feature = "tuple-default")] - pub use tuplities_default::TupleDefault; - #[cfg(feature = "eq")] - pub use tuplities_eq::TupleEq; + #[cfg(feature = "alloc")] + pub use crate::NestedTupleIntoVec; #[cfg(feature = "flatten-nest")] - pub use tuplities_flatten_nest::{ - FlattenMatrixElements, FlattenNestedTuple, FlattenNestedTupleMatrix, IntoNestedTupleOption, - NestMatrixElements, NestTuple, NestTupleMatrix, NestTupleMut, NestTupleRef, - NestedTupleChain, NestedTupleFlattenOption, NestedTupleFrom, NestedTupleIndex, - NestedTupleIndexMut, NestedTupleInto, NestedTupleIntoVec, NestedTupleMut, - NestedTupleOption, NestedTupleOptionFrom, NestedTupleOptionInto, NestedTupleOptionTryFrom, + pub use crate::{ + FlattenMatrixElements, FlattenNestedTupleMatrix, NestMatrixElements, NestTupleMatrix, + }; + pub use crate::{ + FlattenNestedTuple, IntoNestedTupleOption, NestTuple, NestTupleMut, NestTupleRef, + NestedTuple, NestedTupleChain, NestedTupleFlattenOption, NestedTupleFrom, NestedTupleIndex, + NestedTupleIndexMut, NestedTupleInsert, NestedTupleInto, NestedTupleMut, NestedTupleOption, + NestedTupleOptionFrom, NestedTupleOptionInto, NestedTupleOptionTryFrom, NestedTupleOptionTryInto, NestedTupleOptionWith, NestedTuplePopBack, NestedTuplePopFront, - NestedTuplePushBack, NestedTuplePushFront, NestedTupleRef, NestedTupleReplicate, - NestedTupleRow, NestedTupleRowMut, NestedTupleStartsWith, NestedTupleTryFrom, - NestedTupleTryInto, + NestedTuplePushBack, NestedTuplePushFront, NestedTupleRef, NestedTupleRemove, + NestedTupleReplicate, NestedTupleReverse, NestedTupleRow, NestedTupleRowMut, + NestedTupleSplit, NestedTupleStartsWith, NestedTupleTryFrom, NestedTupleTryInto, neple, + neplety, }; - #[cfg(feature = "from")] - pub use tuplities_from::{TupleFrom, TupleInto}; - #[cfg(feature = "hash")] - pub use tuplities_hash::TupleHash; - #[cfg(feature = "index")] - pub use tuplities_index::{FirstTupleIndex, LastTupleIndex, TupleIndex, TupleIndexMut}; - #[cfg(feature = "insert")] - pub use tuplities_insert::TupleInsert; - #[cfg(feature = "len")] - pub use tuplities_len::{PairTuple, SingletonTuple, TupleLen, UnitTuple}; - #[cfg(feature = "mut")] - pub use tuplities_mut::TupleMut; - #[cfg(feature = "mut")] - pub use tuplities_mut::TupleMutMap; - #[cfg(feature = "option")] - pub use tuplities_option::{IntoTupleOption, TupleOption}; - #[cfg(feature = "ord")] - pub use tuplities_ord::TupleOrd; - #[cfg(feature = "partial-eq")] - pub use tuplities_partial_eq::TuplePartialEq; - #[cfg(feature = "partial-ord")] - pub use tuplities_partial_ord::TuplePartialOrd; - #[cfg(feature = "pop-back")] - pub use tuplities_pop_back::{TupleMutBack, TuplePopBack, TupleRefBack}; - #[cfg(feature = "pop-front")] - pub use tuplities_pop_front::{TupleMutFront, TuplePopFront, TupleRefFront}; - #[cfg(feature = "push-back")] - pub use tuplities_push_back::TuplePushBack; - #[cfg(feature = "push-front")] - pub use tuplities_push_front::TuplePushFront; - #[cfg(feature = "ref")] - pub use tuplities_ref::TupleRef; - #[cfg(feature = "ref")] - pub use tuplities_ref::TupleRefMap; - #[cfg(feature = "remove")] - pub use tuplities_remove::TupleRemove; - #[cfg(feature = "replicate")] - pub use tuplities_replicate::TupleReplicate; - #[cfg(feature = "reverse")] - pub use tuplities_reverse::TupleReverse; - #[cfg(feature = "row")] - pub use tuplities_row::{FirstTupleRow, LastTupleRow, TupleRow, TupleRowMut}; - #[cfg(feature = "split")] - pub use tuplities_split::TupleSplit; - #[cfg(feature = "try-from")] - pub use tuplities_try_from::{TupleTryFrom, TupleTryInto}; } diff --git a/tuplities-flatten-nest/src/matrix.rs b/tuplities/src/matrix.rs similarity index 88% rename from tuplities-flatten-nest/src/matrix.rs rename to tuplities/src/matrix.rs index 1115c06..1faa802 100644 --- a/tuplities-flatten-nest/src/matrix.rs +++ b/tuplities/src/matrix.rs @@ -8,22 +8,22 @@ use crate::{flatten_nested::FlattenNestedTuple, nest::NestTuple}; /// and converts it into a nested tuple where each element is also nested /// (like `((A, (B,)), ((C, (D,)),))`). Both the outer and inner tuples are nested. /// -/// # Examples -/// -/// ``` -/// use tuplities_flatten_nest::NestTupleMatrix; -/// -/// let flat_matrix = ((1, 2), (3, 4)); -/// let nested_matrix = flat_matrix.nest_matrix(); -/// assert_eq!(nested_matrix, ((1, (2,)), ((3, (4,)),))); -/// ``` -/// /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestTupleMatrix { /// The nested matrix type. type NestedMatrix; /// Converts a flat tuple of flat tuples into a nested tuple of nested tuples. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestTupleMatrix; + /// + /// let flat_matrix = ((1, 2), (3, 4)); + /// let nested_matrix = flat_matrix.nest_matrix(); + /// assert_eq!(nested_matrix, ((1, (2,)), ((3, (4,)),))); + /// ``` fn nest_matrix(self) -> Self::NestedMatrix; } @@ -33,22 +33,22 @@ pub trait NestTupleMatrix { /// (like `((A, (B,)), ((C, (D,)),))`) and converts it into a flat tuple of flat tuples /// (like `((A, B), (C, D))`). Both the outer and inner tuples are flattened. /// -/// # Examples -/// -/// ``` -/// use tuplities_flatten_nest::FlattenNestedTupleMatrix; -/// -/// let nested_matrix = ((1, (2,)), ((3, (4,)),)); -/// let flat_matrix = nested_matrix.flatten_matrix(); -/// assert_eq!(flat_matrix, ((1, 2), (3, 4))); -/// ``` -/// /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait FlattenNestedTupleMatrix { /// The flattened matrix type. type FlattenedMatrix; /// Converts a nested tuple of nested tuples into a flat tuple of flat tuples. + /// + /// # Examples + /// + /// ``` + /// use tuplities::FlattenNestedTupleMatrix; + /// + /// let nested_matrix = ((1, (2,)), ((3, (4,)),)); + /// let flat_matrix = nested_matrix.flatten_matrix(); + /// assert_eq!(flat_matrix, ((1, 2), (3, 4))); + /// ``` fn flatten_matrix(self) -> Self::FlattenedMatrix; } @@ -62,6 +62,14 @@ pub trait NestMatrixElements { type Output: FlattenMatrixElements; /// Nest all elements in the structure + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestMatrixElements; + /// + /// assert_eq!(((1, 2),).nest_elements(), ((1, (2,)),)); + /// ``` fn nest_elements(self) -> Self::Output; } @@ -122,6 +130,14 @@ pub trait FlattenMatrixElements { type Output; /// Flatten all elements in the structure + /// + /// # Examples + /// + /// ``` + /// use tuplities::FlattenMatrixElements; + /// + /// assert_eq!(((1, (2,)),).flatten_elements(), ((1, 2),)); + /// ``` fn flatten_elements(self) -> Self::Output; } @@ -180,18 +196,6 @@ where mod tests { use super::*; - #[test] - fn test_nest_matrix_empty() { - let flat_matrix = (); - let _nested_matrix: () = flat_matrix.nest_matrix(); - } - - #[test] - fn test_flatten_matrix_empty() { - let nested_matrix = (); - let _flat_matrix: () = nested_matrix.flatten_matrix(); - } - #[test] fn test_nest_matrix_single() { let flat_matrix = ((1, 2, 3),); @@ -281,7 +285,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested matrix shape." + )] fn test_nested_matrix_structure() { let flat_matrix = ((1, 2), (3, 4)); let nested_matrix: ((i32, (i32,)), ((i32, (i32,)),)) = flat_matrix.nest_matrix(); diff --git a/tuplities-flatten-nest/src/nest.rs b/tuplities/src/nest.rs similarity index 60% rename from tuplities-flatten-nest/src/nest.rs rename to tuplities/src/nest.rs index 5a8c8d0..f190756 100644 --- a/tuplities-flatten-nest/src/nest.rs +++ b/tuplities/src/nest.rs @@ -1,8 +1,7 @@ //! Module providing the `NestTuple` trait for nesting flat tuples. -use crate::FlattenNestedTuple; +use crate::flatten_nested::FlattenNestedTuple; -#[tuplities_derive::impl_nest_tuple] /// A trait for nesting flat tuples into nested tuples. /// /// This trait takes a flat tuple like `(A, B, C)` and converts it @@ -14,9 +13,81 @@ pub trait NestTuple { type Nested: FlattenNestedTuple; /// Nests the flat tuple into a nested tuple. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestTuple; + /// + /// assert_eq!((7_u8,).nest(), (7_u8,)); + /// + /// # #[cfg(feature = "flatten-nest")] { + /// let flat = (1, 2, 3); + /// assert_eq!(flat.nest(), (1, (2, (3,)))); + /// # } + /// ``` fn nest(self) -> Self::Nested; } +/// A trait for nesting flat tuples into nested tuples of references. +/// +/// This trait takes a flat tuple like `(A, B, C)` and converts it +/// to a nested tuple of references like `(&A, (&B, (&C,)))`. +pub trait NestTupleRef { + /// The nested tuple type containing references. + type NestedRef<'a>: FlattenNestedTuple + where + Self: 'a; + + /// Nests the flat tuple into a nested tuple of references. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestTupleRef; + /// + /// let flat = (7,); + /// assert_eq!(flat.nest_ref(), (&7,)); + /// + /// # #[cfg(feature = "flatten-nest")] { + /// let flat = (1, 2, 3); + /// assert_eq!(flat.nest_ref(), (&1, (&2, (&3,)))); + /// # } + /// ``` + fn nest_ref(&self) -> Self::NestedRef<'_>; +} + +/// A trait for nesting flat tuples into nested tuples of mutable references. +/// +/// This trait takes a flat tuple like `(A, B, C)` and converts it +/// to a nested tuple of mutable references like `(&mut A, (&mut B, (&mut C,)))`. +pub trait NestTupleMut { + /// The nested tuple type containing mutable references. + type NestedMut<'a>: FlattenNestedTuple + where + Self: 'a; + + /// Nests the flat tuple into a nested tuple of mutable references. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestTupleMut; + /// + /// let mut single = (7,); + /// *single.nest_mut().0 = 9; + /// assert_eq!(single, (9,)); + /// + /// # #[cfg(feature = "flatten-nest")] { + /// let mut flat = (1, 2); + /// let nested = flat.nest_mut(); + /// *nested.1.0 = 20; + /// assert_eq!(flat, (1, 20)); + /// # } + /// ``` + fn nest_mut(&mut self) -> Self::NestedMut<'_>; +} + impl<'a, T> NestTuple for &'a T where T: NestTupleRef, @@ -41,35 +112,67 @@ where } } -/// A trait for nesting flat tuples into nested tuples of references. -/// -/// This trait takes a flat tuple like `(A, B, C)` and converts it -/// to a nested tuple of references like `(&A, (&B, (&C,)))`. -pub trait NestTupleRef { - /// The nested tuple type containing references. - type NestedRef<'a>: FlattenNestedTuple +impl NestTuple for () { + type Nested = (); + + #[inline] + fn nest(self) -> Self::Nested {} +} + +impl NestTupleRef for () { + type NestedRef<'a> + = () where Self: 'a; - /// Nests the flat tuple into a nested tuple of references. - fn nest_ref(&self) -> Self::NestedRef<'_>; + #[inline] + fn nest_ref(&self) -> Self::NestedRef<'_> {} } -/// A trait for nesting flat tuples into nested tuples of mutable references. -/// -/// This trait takes a flat tuple like `(A, B, C)` and converts it -/// to a nested tuple of mutable references like `(&mut A, (&mut B, (&mut C,)))`. -pub trait NestTupleMut { - /// The nested tuple type containing mutable references. - type NestedMut<'a>: FlattenNestedTuple +impl NestTupleMut for () { + type NestedMut<'a> + = () where Self: 'a; - /// Nests the flat tuple into a nested tuple of mutable references. - fn nest_mut(&mut self) -> Self::NestedMut<'_>; + #[inline] + fn nest_mut(&mut self) -> Self::NestedMut<'_> {} } -#[cfg(test)] +impl NestTuple for (N1,) { + type Nested = (N1,); + + #[inline] + fn nest(self) -> Self::Nested { + self + } +} + +impl NestTupleRef for (N1,) { + type NestedRef<'a> + = (&'a N1,) + where + Self: 'a; + + #[inline] + fn nest_ref(&self) -> Self::NestedRef<'_> { + (&self.0,) + } +} + +impl NestTupleMut for (N1,) { + type NestedMut<'a> + = (&'a mut N1,) + where + Self: 'a; + + #[inline] + fn nest_mut(&mut self) -> Self::NestedMut<'_> { + (&mut self.0,) + } +} + +#[cfg(all(test, feature = "flatten-nest"))] mod tests { use super::*; @@ -105,12 +208,6 @@ mod tests { assert_eq!(nested, (99,)); } - #[test] - fn test_nest_empty() { - let flat: () = (); - let _nested: () = flat.nest(); - } - #[test] fn test_nest_ref() { let flat = (1, 2, 3); diff --git a/tuplities-flatten-nest/src/nested_chain.rs b/tuplities/src/nested_chain.rs similarity index 81% rename from tuplities-flatten-nest/src/nested_chain.rs rename to tuplities/src/nested_chain.rs index 5b636f7..b5d4166 100644 --- a/tuplities-flatten-nest/src/nested_chain.rs +++ b/tuplities/src/nested_chain.rs @@ -4,29 +4,29 @@ /// /// This trait allows joining two nested tuples into a single nested tuple. /// It effectively appends the `other` nested tuple to `self`. -/// -/// # Examples -/// -/// ```rust -/// use tuplities_flatten_nest::NestedTupleChain; -/// -/// // Chaining (1, (2,)) and (3, (4,)) results in (1, (2, (3, (4,)))) -/// let t1 = (1, (2,)); -/// let t2 = (3, (4,)); -/// let chained = t1.chain(t2); -/// assert_eq!(chained, (1, (2, (3, (4,))))); -/// -/// // Chaining (1, (2, ())) and (3, (4, ())) results in (1, (2, (3, (4, ())))) -/// let t3 = (1, (2, ())); -/// let t4 = (3, (4, ())); -/// let chained2 = t3.chain(t4); -/// assert_eq!(chained2, (1, (2, (3, (4, ()))))); -/// ``` pub trait NestedTupleChain { /// The resulting chained nested tuple type. type Chained; /// Chains `other` to the end of `self`. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleChain; + /// + /// // Chaining (1, (2,)) and (3, (4,)) results in (1, (2, (3, (4,)))) + /// let t1 = (1, (2,)); + /// let t2 = (3, (4,)); + /// let chained = t1.chain(t2); + /// assert_eq!(chained, (1, (2, (3, (4,))))); + /// + /// // Chaining (1, (2, ())) and (3, (4, ())) results in (1, (2, (3, (4, ())))) + /// let t3 = (1, (2, ())); + /// let t4 = (3, (4, ())); + /// let chained2 = t3.chain(t4); + /// assert_eq!(chained2, (1, (2, (3, (4, ()))))); + /// ``` fn chain(self, other: Other) -> Self::Chained; } diff --git a/tuplities-flatten-nest/src/nested_index.rs b/tuplities/src/nested_index.rs similarity index 62% rename from tuplities-flatten-nest/src/nested_index.rs rename to tuplities/src/nested_index.rs index 914315c..ff92b59 100644 --- a/tuplities-flatten-nest/src/nested_index.rs +++ b/tuplities/src/nested_index.rs @@ -1,54 +1,71 @@ //! Module providing indexing traits for nested tuples. -use crate::flatten_nested::FlattenNestedTuple; +use crate::NestedTuple; /// A trait for indexing into nested tuples at compile-time known positions. /// -/// This trait allows accessing elements at specific flat indices `Idx` -/// from nested tuples, where `Idx` is a compile-time constant from `typenum`. -/// The index corresponds to the position in the flattened tuple. -/// -/// # Examples -/// -/// ``` -/// use tuplities_flatten_nest::NestedTupleIndex; -/// use typenum::U1; -/// -/// let nested = (1, (2, (3,))); -/// let element = NestedTupleIndex::::nested_index(&nested); -/// assert_eq!(*element, 2); -/// ``` +/// The `typenum` index counts heads from zero. A tuple-valued head occupies one position. /// /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. -pub trait NestedTupleIndex: FlattenNestedTuple { - /// The type of the element at flat index `Idx`. +pub trait NestedTupleIndex: NestedTuple { + /// The element type selected by `Idx`. type Element; /// Returns a reference to the element at flat index `Idx`. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTupleIndex; + /// use typenum::U1; + /// + /// let nested = (1, (2, (3,))); + /// let element = NestedTupleIndex::::nested_index(&nested); + /// assert_eq!(*element, 2); + /// ``` + /// + /// Indices outside the list have no implementation. + /// + /// ```compile_fail + /// use tuplities::NestedTupleIndex; + /// use typenum::U2; + /// + /// let values = (1_u8, (2_u16, ())); + /// let _ = NestedTupleIndex::::nested_index(&values); + /// ``` fn nested_index(&self) -> &Self::Element; } /// A trait for mutable indexing into nested tuples at compile-time known positions. /// -/// This trait allows mutable access to elements at specific flat indices `Idx` -/// from nested tuples, where `Idx` is a compile-time constant from `typenum`. -/// The index corresponds to the position in the flattened tuple. -/// -/// # Examples -/// -/// ``` -/// use tuplities_flatten_nest::NestedTupleIndexMut; -/// use typenum::U1; -/// -/// let mut nested = (1, (2, (3,))); -/// let element = NestedTupleIndexMut::::nested_index_mut(&mut nested); -/// *element = 20; -/// assert_eq!(nested, (1, (20, (3,)))); -/// ``` +/// The `typenum` index counts heads from zero. A tuple-valued head occupies one position. /// /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleIndexMut: NestedTupleIndex { /// Returns a mutable reference to the element at flat index `Idx`. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTupleIndexMut; + /// use typenum::U1; + /// + /// let mut nested = (1, (2, (3,))); + /// let element = NestedTupleIndexMut::::nested_index_mut(&mut nested); + /// *element = 20; + /// assert_eq!(nested, (1, (20, (3,)))); + /// ``` + /// + /// Shared tails cannot provide mutable access. + /// + /// ```compile_fail + /// use tuplities::NestedTupleIndexMut; + /// use typenum::U1; + /// + /// let tail = (1_u8,); + /// let mut values = (0_u8, &tail); + /// let _ = NestedTupleIndexMut::::nested_index_mut(&mut values); + /// ``` fn nested_index_mut(&mut self) -> &mut Self::Element; } @@ -62,7 +79,7 @@ impl NestedTupleIndex for (Head,) { impl NestedTupleIndex for (Head, Tail) where - (Head, Tail): FlattenNestedTuple, + Tail: NestedTuple, { type Element = Head; @@ -73,7 +90,6 @@ where impl NestedTupleIndex> for (Head, Tail) where - (Head, Tail): FlattenNestedTuple, typenum::UInt: core::ops::Sub, Tail: NestedTupleIndex>>, { @@ -92,7 +108,7 @@ impl NestedTupleIndexMut for (Head,) { impl NestedTupleIndexMut for (Head, Tail) where - (Head, Tail): FlattenNestedTuple, + Tail: NestedTuple, { fn nested_index_mut(&mut self) -> &mut Self::Element { &mut self.0 @@ -101,7 +117,6 @@ where impl NestedTupleIndexMut> for (Head, Tail) where - (Head, Tail): FlattenNestedTuple, typenum::UInt: core::ops::Sub, Tail: NestedTupleIndexMut>>, { @@ -110,6 +125,28 @@ where } } +impl + ?Sized> NestedTupleIndex for &T { + type Element = T::Element; + + fn nested_index(&self) -> &Self::Element { + T::nested_index(*self) + } +} + +impl + ?Sized> NestedTupleIndex for &mut T { + type Element = T::Element; + + fn nested_index(&self) -> &Self::Element { + T::nested_index(*self) + } +} + +impl + ?Sized> NestedTupleIndexMut for &mut T { + fn nested_index_mut(&mut self) -> &mut Self::Element { + T::nested_index_mut(*self) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/tuplities-flatten-nest/src/nested_into_vec.rs b/tuplities/src/nested_into_vec.rs similarity index 85% rename from tuplities-flatten-nest/src/nested_into_vec.rs rename to tuplities/src/nested_into_vec.rs index 96030a8..8124715 100644 --- a/tuplities-flatten-nest/src/nested_into_vec.rs +++ b/tuplities/src/nested_into_vec.rs @@ -15,17 +15,31 @@ pub trait NestedTupleIntoVec { /// # Examples /// /// ```rust - /// use tuplities_flatten_nest::NestedTupleIntoVec; + /// # if cfg!(feature = "alloc") { + /// use tuplities::NestedTupleIntoVec; /// /// let nested = (1, (2, (3,))); /// let vec: Vec = nested.into_vec(); /// assert_eq!(vec, vec![1, 2, 3]); + /// # } /// ``` fn into_vec(self) -> Vec; /// Appends the elements of the nested tuple to an existing vector. /// /// This is used internally by `into_vec` for efficiency but can also be used directly. + /// + /// # Examples + /// + /// ```rust + /// # if cfg!(feature = "alloc") { + /// use tuplities::NestedTupleIntoVec; + /// + /// let mut buf = vec![1, 2]; + /// (3, (4, (5,))).append_to_vec(&mut buf); + /// assert_eq!(buf, vec![1, 2, 3, 4, 5]); + /// # } + /// ``` fn append_to_vec(self, buf: &mut Vec); } diff --git a/tuplities-flatten-nest/src/nested_option.rs b/tuplities/src/nested_option.rs similarity index 78% rename from tuplities-flatten-nest/src/nested_option.rs rename to tuplities/src/nested_option.rs index 68943bf..b5ddc2d 100644 --- a/tuplities-flatten-nest/src/nested_option.rs +++ b/tuplities/src/nested_option.rs @@ -1,24 +1,6 @@ //! Module providing option transposition traits for nested tuples. -/// A trait for transposing nested tuples of options into options of nested tuples. -/// -/// This trait takes a nested tuple where each element is an `Option` and transposes it -/// into an `Option` of the nested tuple with the inner types. Returns `Some(nested_tuple)` -/// if all elements are `Some`, otherwise `None`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_flatten_nest::NestedTupleOption; -/// -/// let nested_options = (Some(1), (Some(2), (Some(3),))); -/// let transposed: Option<(i32, (i32, (i32,)))> = nested_options.transpose(); -/// assert_eq!(transposed, Some((1, (2, (3,))))); -/// -/// let nested_options = (Some(1), (None, (Some(3),))); -/// let transposed: Option<(i32, (i32, (i32,)))> = nested_options.transpose(); -/// assert_eq!(transposed, None); -/// ``` +/// Transposes nested tuples of options into options of nested tuples. /// /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleOption { @@ -28,6 +10,20 @@ pub trait NestedTupleOption { /// Transposes the nested tuple of options into an option of the nested tuple. /// /// Returns `Some(nested_tuple)` if all elements are `Some`, otherwise `None`. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleOption; + /// + /// let nested_options = (Some(1), (Some(2), (Some(3),))); + /// let transposed: Option<(i32, (i32, (i32,)))> = nested_options.transpose(); + /// assert_eq!(transposed, Some((1, (2, (3,))))); + /// + /// let nested_options = (Some(1), (None, (Some(3),))); + /// let transposed: Option<(i32, (i32, (i32,)))> = nested_options.transpose(); + /// assert_eq!(transposed, None); + /// ``` fn transpose(self) -> Option; } @@ -38,9 +34,37 @@ pub trait NestedTupleOptionWith: NestedTupleOption { type SameDepth; /// Returns the first `H` corresponding to the first `None` in `self`. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleOptionWith; + /// + /// let options = (Some(1), (None::, (Some(3),))); + /// let hom = (10, (20, (30,))); + /// assert_eq!(options.first_none_with(hom), Some(20)); + /// + /// let options = (Some(1), (Some(2), (Some(3),))); + /// let hom = (10, (20, (30,))); + /// assert_eq!(options.first_none_with(hom), None); + /// ``` fn first_none_with(self, xs: Self::SameDepth) -> Option; /// Returns the first `H` corresponding to the first `Some` in `self`. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleOptionWith; + /// + /// let options = (None::, (Some(2), (Some(3),))); + /// let hom = (10, (20, (30,))); + /// assert_eq!(options.first_some_with(hom), Some(20)); + /// + /// let options = (None::, (None::, (None::,))); + /// let hom = (10, (20, (30,))); + /// assert_eq!(options.first_some_with(hom), None); + /// ``` fn first_some_with(self, xs: Self::SameDepth) -> Option; /// Like `transpose`, but returns a `Result` with `Ok(Transposed)` when all elements @@ -52,6 +76,20 @@ pub trait NestedTupleOptionWith: NestedTupleOption { /// corresponding element of the parallel homogeneous nested tuple `xs` for the first /// `None` encountered (traversed left-to-right, depth-first in the nested pair /// representation). + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleOptionWith; + /// + /// let options = (Some(1), (Some(2), (Some(3),))); + /// let hom = (10, (20, (30,))); + /// assert_eq!(options.transpose_or(hom), Ok((1, (2, (3,))))); + /// + /// let options = (Some(1), (None::, (Some(3),))); + /// let hom = (10, (20, (30,))); + /// assert_eq!(options.transpose_or(hom), Err(20)); + /// ``` fn transpose_or(self, xs: Self::SameDepth) -> Result; } @@ -68,7 +106,7 @@ pub trait IntoNestedTupleOption { /// # Examples /// /// ```rust - /// use tuplities_flatten_nest::IntoNestedTupleOption; + /// use tuplities::IntoNestedTupleOption; /// /// let nested = (1, (2, (3,))); /// let into_options: (Option, (Option, (Option,))) = nested.into_options(); @@ -238,20 +276,7 @@ where } } -/// A trait for flattening nested tuples of double options into nested tuples of options. -/// -/// This trait takes a nested tuple where each element is an `Option>` and flattens it -/// into a nested tuple where each element is an `Option`. -/// -/// # Examples -/// -/// ``` -/// use tuplities_flatten_nest::NestedTupleFlattenOption; -/// -/// let nested_double_options = (Some(Some(1)), (Some(None), (None,))); -/// let flattened: (Option, (Option, (Option,))) = nested_double_options.flatten_options(); -/// assert_eq!(flattened, (Some(1), (None, (None,)))); -/// ``` +/// Flattens nested tuples of double options into nested tuples of options. /// /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleFlattenOption { @@ -259,6 +284,17 @@ pub trait NestedTupleFlattenOption { type FlattenedOptions: IntoNestedTupleOption; /// Flattens the nested tuple of double options into a nested tuple of options. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleFlattenOption; + /// + /// let nested_double_options = (Some(Some(1)), (Some(None), (None,))); + /// let flattened: (Option, (Option, (Option,))) = + /// nested_double_options.flatten_options(); + /// assert_eq!(flattened, (Some(1), (None, (None,)))); + /// ``` fn flatten_options(self) -> Self::FlattenedOptions; } @@ -347,7 +383,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested three-level `Option` shape." + )] fn test_into_options_three() { let nested = (1, (2, (3,))); let into_options: (Option, (Option, (Option,))) = nested.into_options(); @@ -445,10 +484,33 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested three-level `Option` shape." + )] fn test_flatten_options() { let nested = (Some(Some(1)), (Some(None), (None,))); let flattened: (Option, (Option, (Option,))) = nested.flatten_options(); assert_eq!(flattened, (Some(1), (None, (None,)))); } + + #[test] + fn test_first_none_with_selects_singleton_terminal_label() { + let options = (Some(1), (None::,)); + let labels = (NoCopy(31), (NoCopy(47),)); + assert_eq!(options.first_none_with(labels), Some(NoCopy(47))); + } + + #[test] + fn test_first_some_with_selects_singleton_terminal_label() { + let options = (None::, (Some(1),)); + let labels = (NoCopy(31), (NoCopy(47),)); + assert_eq!(options.first_some_with(labels), Some(NoCopy(47))); + } + + #[test] + fn test_flatten_options_preserves_singleton_terminal_payload() { + let options = (None::>, (Some(Some(NoCopy(47))),)); + assert_eq!(options.flatten_options(), (None, (Some(NoCopy(47)),))); + } } diff --git a/tuplities-flatten-nest/src/nested_option_try_from.rs b/tuplities/src/nested_option_try_from.rs similarity index 78% rename from tuplities-flatten-nest/src/nested_option_try_from.rs rename to tuplities/src/nested_option_try_from.rs index 322e239..60121e0 100644 --- a/tuplities-flatten-nest/src/nested_option_try_from.rs +++ b/tuplities/src/nested_option_try_from.rs @@ -15,6 +15,23 @@ pub trait NestedTupleOptionTryFrom: Sized { /// # Errors /// /// Returns an error of type `E` if any element conversion fails. + /// + /// # Examples + /// + /// ```rust + /// use core::num::TryFromIntError; + /// use tuplities::NestedTupleOptionTryFrom; + /// + /// let source = (Some(1_u16), (None::, (Some(3_u16),))); + /// let result: Result<(Option, (Option, (Option,))), TryFromIntError> = + /// <(Option, (Option, (Option,)))>::nested_tuple_option_try_from(source); + /// assert_eq!(result, Ok((Some(1_u8), (None, (Some(3),))))); + /// + /// let source = (Some(1_u16), (Some(300_u16), (Some(3_u16),))); + /// let result: Result<(Option, (Option, (Option,))), TryFromIntError> = + /// <(Option, (Option, (Option,)))>::nested_tuple_option_try_from(source); + /// assert!(matches!(result, Err(_))); + /// ``` fn nested_tuple_option_try_from(other: T) -> Result; } @@ -29,6 +46,23 @@ pub trait NestedTupleOptionTryInto: Sized { /// # Errors /// /// Returns an error of type `E` if any element conversion fails. + /// + /// # Examples + /// + /// ```rust + /// use core::num::TryFromIntError; + /// use tuplities::NestedTupleOptionTryInto; + /// + /// let source = (Some(1_u16), (None::, (Some(3_u16),))); + /// let result: Result<(Option, (Option, (Option,))), TryFromIntError> = + /// source.nested_tuple_option_try_into(); + /// assert_eq!(result, Ok((Some(1_u8), (None, (Some(3),))))); + /// + /// let source = (Some(1_u16), (Some(300_u16), (Some(3_u16),))); + /// let result: Result<(Option, (Option, (Option,))), TryFromIntError> = + /// source.nested_tuple_option_try_into(); + /// assert!(matches!(result, Err(_))); + /// ``` fn nested_tuple_option_try_into(self) -> Result; } @@ -83,6 +117,17 @@ where /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleOptionFrom: Sized { /// Converts `other` into `Self` by applying `From` element-wise. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleOptionFrom; + /// + /// let source = (Some(1_u8), (None::, (Some(3_u8),))); + /// let result: (Option, (Option, (Option,))) = + /// <(Option, (Option, (Option,)))>::nested_tuple_option_from(source); + /// assert_eq!(result, (Some(1_u16), (None, (Some(3),)))); + /// ``` fn nested_tuple_option_from(other: T) -> Self; } @@ -93,12 +138,23 @@ pub trait NestedTupleOptionFrom: Sized { /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleOptionInto: Sized { /// Converts `self` into `T` by applying `Into` element-wise. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleOptionInto; + /// + /// let source = (Some(1_u8), (None::, (Some(3_u8),))); + /// let result: (Option, (Option, (Option,))) = + /// source.nested_tuple_option_into(); + /// assert_eq!(result, (Some(1_u16), (None, (Some(3),)))); + /// ``` fn nested_tuple_option_into(self) -> T; } impl NestedTupleOptionInto<()> for () { #[inline] - fn nested_tuple_option_into(self) -> () {} + fn nested_tuple_option_into(self) {} } impl NestedTupleOptionInto<(Option,)> for (Option,) @@ -222,7 +278,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested three-level `Option` shape." + )] fn test_nested_tuple_option_try_from_nested() { let source = (Some(1u8), (Some(2u8), (Some(3u8),))); let target: Result<(Option, (Option, (Option,))), MyError> = @@ -246,7 +305,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested three-level `Option` shape." + )] fn test_nested_tuple_option_from_nested() { let source = (Some(1u8), (Some(2u8), (Some(3u8),))); let target: (Option, (Option, (Option,))) = @@ -312,7 +374,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested three-level `Option` shape." + )] fn test_nested_tuple_option_try_from_custom_wrapper_error_nested() { let source = (Some(WrapI16(256)), (Some(WrapI16(1)), (Some(WrapI16(2)),))); let target: Result<(Option, (Option, (Option,))), WrapErr> = @@ -321,7 +386,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested three-level `Option` shape." + )] fn test_nested_tuple_option_from_with_none() { let source = (None::, (Some(2u8), (None::,))); let target: (Option, (Option, (Option,))) = @@ -330,7 +398,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested three-level `Option` shape." + )] fn test_nested_tuple_option_try_from_with_none() { let source = (None::, (Some(2u8), (None::,))); let target: Result<(Option, (Option, (Option,))), MyError> = diff --git a/tuplities-flatten-nest/src/nested_push_pop.rs b/tuplities/src/nested_push_pop.rs similarity index 71% rename from tuplities-flatten-nest/src/nested_push_pop.rs rename to tuplities/src/nested_push_pop.rs index cb6db29..5cb1344 100644 --- a/tuplities-flatten-nest/src/nested_push_pop.rs +++ b/tuplities/src/nested_push_pop.rs @@ -1,5 +1,7 @@ //! Module providing pop/push traits for nested tuples. +use crate::NestedTuple; + /// A trait for popping the front element of a nested tuple. pub trait NestedTuplePopFront { /// The type of the first element. @@ -9,6 +11,22 @@ pub trait NestedTuplePopFront { type Tail; /// Consume the nested tuple and return the first element and the remaining nested tuple. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTuplePopFront; + /// + /// let (front, tail) = (1, (2, (3,))).nested_pop_front(); + /// assert_eq!(front, 1); + /// assert_eq!(tail, (2, (3,))); + /// + /// let shared = (1, (2, (3,))); + /// let (shared_front, shared_tail) = (&shared).nested_pop_front(); + /// assert_eq!(*shared_front, 1); + /// assert_eq!(*shared_tail, (2, (3,))); + /// assert_eq!(shared, (1, (2, (3,)))); + /// ``` fn nested_pop_front(self) -> (Self::Front, Self::Tail); } @@ -21,6 +39,16 @@ pub trait NestedTuplePopBack { type Back; /// Consume the nested tuple and return the remaining nested tuple and the last element. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTuplePopBack; + /// + /// let (init, back) = (1, (2, (3,))).nested_pop_back(); + /// assert_eq!(init, (1, (2,))); + /// assert_eq!(back, 3); + /// ``` fn nested_pop_back(self) -> (Self::Init, Self::Back); } @@ -30,6 +58,18 @@ pub trait NestedTuplePushFront { type Output; /// Push an element to the front. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTuplePushFront; + /// + /// let pushed = ().nested_push_front(1); + /// assert_eq!(pushed, (1,)); + /// + /// let pushed = (2, (3,)).nested_push_front(1); + /// assert_eq!(pushed, (1, (2, (3,)))); + /// ``` fn nested_push_front(self, item: Item) -> Self::Output; } @@ -39,6 +79,18 @@ pub trait NestedTuplePushBack { type Output; /// Push an element to the back. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTuplePushBack; + /// + /// let pushed = ().nested_push_back(1); + /// assert_eq!(pushed, (1,)); + /// + /// let pushed = (1, (2, (3,))).nested_push_back(4); + /// assert_eq!(pushed, (1, (2, (3, (4,))))); + /// ``` fn nested_push_back(self, item: Item) -> Self::Output; } @@ -164,6 +216,60 @@ impl NestedTuplePushFront for (Head, Tail) { } } +impl NestedTuplePushFront for &() { + type Output = (Item,); + + #[inline] + fn nested_push_front(self, item: Item) -> Self::Output { + (item,) + } +} + +impl NestedTuplePushFront for &mut () { + type Output = (Item,); + + #[inline] + fn nested_push_front(self, item: Item) -> Self::Output { + (item,) + } +} + +impl<'a, Item, Head> NestedTuplePushFront for &'a (Head,) { + type Output = (Item, &'a (Head,)); + + #[inline] + fn nested_push_front(self, item: Item) -> Self::Output { + (item, self) + } +} + +impl<'a, Item, Head> NestedTuplePushFront for &'a mut (Head,) { + type Output = (Item, &'a mut (Head,)); + + #[inline] + fn nested_push_front(self, item: Item) -> Self::Output { + (item, self) + } +} + +impl<'a, Item, Head, Tail: NestedTuple> NestedTuplePushFront for &'a (Head, Tail) { + type Output = (Item, &'a (Head, Tail)); + + #[inline] + fn nested_push_front(self, item: Item) -> Self::Output { + (item, self) + } +} + +impl<'a, Item, Head, Tail: NestedTuple> NestedTuplePushFront for &'a mut (Head, Tail) { + type Output = (Item, &'a mut (Head, Tail)); + + #[inline] + fn nested_push_front(self, item: Item) -> Self::Output { + (item, self) + } +} + impl NestedTuplePushBack for () { type Output = (Item,); diff --git a/tuplities-flatten-nest/src/nested_ref.rs b/tuplities/src/nested_ref.rs similarity index 87% rename from tuplities-flatten-nest/src/nested_ref.rs rename to tuplities/src/nested_ref.rs index c47ff57..56c6ff0 100644 --- a/tuplities-flatten-nest/src/nested_ref.rs +++ b/tuplities/src/nested_ref.rs @@ -10,6 +10,15 @@ pub trait NestedTupleRef { Self: 'a; /// Returns a nested tuple containing references to each leaf value. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTupleRef; + /// + /// let nested = (1, (2, (3,))); + /// assert_eq!(nested.nested_tuple_ref(), (&1, (&2, (&3,)))); + /// ``` fn nested_tuple_ref(&self) -> Self::Ref<'_>; } @@ -21,6 +30,17 @@ pub trait NestedTupleMut { Self: 'a; /// Returns a nested tuple containing mutable references to each leaf value. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTupleMut; + /// + /// let mut nested = (1, (2,)); + /// let mut refs = nested.nested_tuple_mut(); + /// *refs.1.0 = 20; + /// assert_eq!(nested, (1, (20,))); + /// ``` fn nested_tuple_mut(&mut self) -> Self::Mut<'_>; } diff --git a/tuplities-flatten-nest/src/nested_replicate.rs b/tuplities/src/nested_replicate.rs similarity index 82% rename from tuplities-flatten-nest/src/nested_replicate.rs rename to tuplities/src/nested_replicate.rs index ce5c6d5..6cf7c84 100644 --- a/tuplities-flatten-nest/src/nested_replicate.rs +++ b/tuplities/src/nested_replicate.rs @@ -2,11 +2,8 @@ /// A trait for replicating a value into a nested tuple. /// -/// This trait allows creating a nested tuple where all elements are the same value. -/// The implementation follows the same optimization as `TupleReplicate`: for empty tuples -/// and single-element tuples, no `Clone` bound is required. For nested tuples with 2+ -/// elements, `Clone` is required but the original value is moved to the last -/// position to minimize clones. +/// The empty and single-element forms take no `Clone` bound; longer forms clone for all but the +/// last position and move the value there. /// /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleReplicate { @@ -15,7 +12,7 @@ pub trait NestedTupleReplicate { /// # Examples /// /// ```rust - /// use tuplities_flatten_nest::NestedTupleReplicate; + /// use tuplities::NestedTupleReplicate; /// /// let nested: (i32, (i32, (i32,))) = NestedTupleReplicate::nested_tuple_replicate(42); /// assert_eq!(nested, (42, (42, (42,)))); diff --git a/tuplities/src/nested_reverse.rs b/tuplities/src/nested_reverse.rs new file mode 100644 index 0000000..1e086b3 --- /dev/null +++ b/tuplities/src/nested_reverse.rs @@ -0,0 +1,134 @@ +//! Module providing the `NestedTupleReverse` trait for reversing nested tuples. + +use crate::NestedTuple; + +/// Consumes owned tuple nodes into singleton-terminated reverse order. +pub trait NestedTupleReverse: NestedTuple { + /// The reversed nested tuple type. + type Output: NestedTuple; + + /// Consumes the list and returns its elements in reverse order. + /// + /// # Examples + /// + /// ``` + /// use tuplities::{neple, neplety, NestedTupleReverse}; + /// + /// let () = ().nested_reverse(); + /// assert_eq!(neple!(7_u8).nested_reverse(), (7,)); + /// assert_eq!((7_u8, ()).nested_reverse(), (7,)); + /// + /// let original = ((1_u8, 2_u16), (3_u32, (false, ()))); + /// let reversed: neplety!(bool, u32, (u8, u16)) = original.nested_reverse(); + /// assert_eq!(reversed, neple!(false, 3, (1, 2))); + /// ``` + /// + /// ```compile_fail + /// use tuplities::{neple, NestedTupleReverse}; + /// + /// let tail = neple!(2_u16, 3_u32); + /// let _ = NestedTupleReverse::nested_reverse((1_u8, &tail)); + /// ``` + fn nested_reverse(self) -> Self::Output; +} + +/// Reverses an owned tail into a nonempty singleton-terminated accumulator. +#[doc(hidden)] +pub trait NestedReverseAccumulator: NestedTuple { + /// The fully reversed nested tuple type. + type Output: NestedTuple; + + /// Consumes the tail and returns its elements reversed ahead of `acc`. + fn nested_reverse_into(self, acc: Acc) -> Self::Output; +} + +impl NestedTupleReverse for () { + type Output = (); + + #[inline] + fn nested_reverse(self) -> Self::Output {} +} + +impl NestedTupleReverse for (Head,) { + type Output = (Head,); + + #[inline] + fn nested_reverse(self) -> Self::Output { + self + } +} + +impl NestedTupleReverse for (Head, Tail) +where + Tail: NestedReverseAccumulator<(Head,)>, +{ + type Output = >::Output; + + #[inline] + fn nested_reverse(self) -> Self::Output { + let (head, tail) = self; + tail.nested_reverse_into((head,)) + } +} + +impl NestedReverseAccumulator for () +where + Acc: NestedTuple, +{ + type Output = Acc; + + #[inline] + fn nested_reverse_into(self, acc: Acc) -> Self::Output { + acc + } +} + +impl NestedReverseAccumulator for (Head,) +where + Acc: NestedTuple, +{ + type Output = (Head, Acc); + + #[inline] + fn nested_reverse_into(self, acc: Acc) -> Self::Output { + (self.0, acc) + } +} + +impl NestedReverseAccumulator for (Head, Tail) +where + Acc: NestedTuple, + Tail: NestedReverseAccumulator<(Head, Acc)>, +{ + type Output = >::Output; + + #[inline] + fn nested_reverse_into(self, acc: Acc) -> Self::Output { + let (head, tail) = self; + tail.nested_reverse_into((head, acc)) + } +} + +impl NestedReverseAccumulator for &() +where + Acc: NestedTuple, +{ + type Output = Acc; + + #[inline] + fn nested_reverse_into(self, acc: Acc) -> Self::Output { + acc + } +} + +impl NestedReverseAccumulator for &mut () +where + Acc: NestedTuple, +{ + type Output = Acc; + + #[inline] + fn nested_reverse_into(self, acc: Acc) -> Self::Output { + acc + } +} diff --git a/tuplities-flatten-nest/src/nested_row.rs b/tuplities/src/nested_row.rs similarity index 69% rename from tuplities-flatten-nest/src/nested_row.rs rename to tuplities/src/nested_row.rs index 4872328..5ae229b 100644 --- a/tuplities-flatten-nest/src/nested_row.rs +++ b/tuplities/src/nested_row.rs @@ -1,13 +1,25 @@ //! Module providing nested row accessors for nested tuple-of-tuples. -use crate::{NestedTupleIndex, NestedTupleIndexMut, NestedTupleMut, NestedTupleRef}; +use crate::{NestedTuple, NestedTupleIndex, NestedTupleIndexMut, NestedTupleMut, NestedTupleRef}; -/// Skeleton trait for nested row retrieval. -pub trait NestedTupleRow { - /// The nested tuple type representing a row across the matrix. - type RowType: NestedTupleRef; +/// Retrieves one index across a recursive tuple of lists. +pub trait NestedTupleRow: NestedTuple { + /// The recursive tuple of selected element types. + type RowType: NestedTuple + NestedTupleRef; /// Return the nested row at the given index. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTupleRow; + /// use typenum::U0; + /// + /// let matrix = ((1, (2,)), ((3, (4,)),)); + /// let row = NestedTupleRow::::nested_tuple_row(&matrix); + /// assert_eq!(*row.0, 1); + /// assert_eq!(*row.1.0, 3); + /// ``` fn nested_tuple_row(&self) -> ::Ref<'_>; } @@ -46,9 +58,22 @@ where } } -/// Skeleton trait for mutable nested row retrieval. +/// Retrieves mutable references at one index across a recursive tuple of lists. pub trait NestedTupleRowMut: NestedTupleRow { /// Returns a nested tuple containing mutable references to the row elements. + /// + /// # Examples + /// + /// ``` + /// use tuplities::NestedTupleRowMut; + /// use typenum::U0; + /// + /// let mut matrix = ((1, (2,)), ((3, (4,)),)); + /// let row = NestedTupleRowMut::::nested_tuple_row_mut(&mut matrix); + /// *row.0 = 10; + /// *row.1.0 = 30; + /// assert_eq!(matrix, ((10, (2,)), ((30, (4,)),))); + /// ``` fn nested_tuple_row_mut(&mut self) -> ::Mut<'_>; } @@ -62,7 +87,7 @@ where impl NestedTupleRowMut for (T1,) where - T1: NestedTupleIndexMut + NestedTupleMut, + T1: NestedTupleIndexMut, { #[inline] fn nested_tuple_row_mut(&mut self) -> ::Mut<'_> { @@ -73,7 +98,7 @@ where impl NestedTupleRowMut for (Head, Tail) where - Head: NestedTupleIndexMut + NestedTupleMut, + Head: NestedTupleIndexMut, Tail: NestedTupleRowMut, Tail::RowType: NestedTupleMut, { @@ -84,17 +109,33 @@ where } } +impl + ?Sized> NestedTupleRow for &T { + type RowType = T::RowType; + + fn nested_tuple_row(&self) -> ::Ref<'_> { + T::nested_tuple_row(*self) + } +} + +impl + ?Sized> NestedTupleRow for &mut T { + type RowType = T::RowType; + + fn nested_tuple_row(&self) -> ::Ref<'_> { + T::nested_tuple_row(*self) + } +} + +impl + ?Sized> NestedTupleRowMut for &mut T { + fn nested_tuple_row_mut(&mut self) -> ::Mut<'_> { + T::nested_tuple_row_mut(*self) + } +} + #[cfg(test)] mod tests { use super::*; use typenum::{U0, U1, U2}; - #[test] - fn test_nested_row_empty() { - let matrix: () = (); - let _row: () = NestedTupleRow::::nested_tuple_row(&matrix); - } - #[test] fn test_nested_row_single_element() { let matrix: ((i32, (i32, (i32,))),) = ((10, (20, (30,))),); @@ -107,7 +148,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested matrix shape." + )] fn test_nested_row_two_outer_elements() { // outer nested pair with two elements: (Head, (Second,)) let matrix: ((i32, (i32,)), ((i32, (i32,)),)) = ((1, (2,)), ((3, (4,)),)); @@ -120,7 +164,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested matrix shape." + )] fn test_nested_row_three_outer_elements() { // outer nested pair with three elements: (A, (B, (C,))) let matrix: ( @@ -145,7 +192,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested matrix shape." + )] fn test_nested_row_mut_modify_two_elements() { let mut matrix: ((i32, (i32,)), ((i32, (i32,)),)) = ((1, (2,)), ((3, (4,)),)); let row0 = NestedTupleRowMut::::nested_tuple_row_mut(&mut matrix); @@ -160,7 +210,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested matrix shape." + )] fn test_nested_row_mut_modify_three_elements() { let mut matrix: ( (i32, (i32, (i32,))), @@ -178,7 +231,10 @@ mod tests { } #[test] - #[allow(clippy::type_complexity)] + #[expect( + clippy::type_complexity, + reason = "The fixture specifies the nested matrix shape." + )] fn test_nested_row_mixed_types_ref() { let matrix: ((i32, (&str,)), ((i32, (&str,)),)) = ((1, ("a",)), ((2, ("b",)),)); let row0 = NestedTupleRow::::nested_tuple_row(&matrix); diff --git a/tuplities-flatten-nest/src/nested_starts_with.rs b/tuplities/src/nested_starts_with.rs similarity index 100% rename from tuplities-flatten-nest/src/nested_starts_with.rs rename to tuplities/src/nested_starts_with.rs diff --git a/tuplities/src/nested_structure.rs b/tuplities/src/nested_structure.rs new file mode 100644 index 0000000..5334955 --- /dev/null +++ b/tuplities/src/nested_structure.rs @@ -0,0 +1,247 @@ +//! Module providing the consuming structural split, insert, and remove traits. + +use crate::{NestedTuple, NestedTuplePushFront}; + +/// Splits at `typenum` indices through `NestedTuple::LEN`, singleton-terminating the prefix and preserving the suffix. +pub trait NestedTupleSplit: NestedTuple { + /// The rebuilt prefix holding the first `Idx` heads, singleton-terminated. + type Prefix: NestedTuple; + + /// The untouched suffix starting at `Idx`, preserving the input representation. + type Suffix: NestedTuple; + + /// Consumes the list, returning the prefix and the suffix. + /// + /// # Examples + /// + /// ``` + /// use tuplities::{neple, NestedTupleSplit}; + /// use typenum::{U0, U2}; + /// + /// assert_eq!(NestedTupleSplit::::nested_split(()), ((), ())); + /// + /// let (prefix, suffix) = NestedTupleSplit::::nested_split(neple!(1_u8, 2_u16, 3_u32)); + /// assert_eq!((prefix, suffix), (neple!(1_u8, 2_u16), neple!(3_u32))); + /// ``` + /// + /// ```compile_fail + /// use tuplities::NestedTupleSplit; + /// use typenum::U3; + /// + /// let _ = NestedTupleSplit::::nested_split((1_u8, (2_u16, ()))); + /// ``` + /// + /// ```compile_fail + /// use tuplities::{neple, NestedTupleSplit}; + /// use typenum::U2; + /// + /// let tail = neple!(1_u8, 2_u16); + /// let _ = NestedTupleSplit::::nested_split((0_u8, &tail)); + /// ``` + fn nested_split(self) -> (Self::Prefix, Self::Suffix); +} + +/// Inserts at `typenum` indices through `NestedTuple::LEN`, using singleton termination at an empty tail. +pub trait NestedTupleInsert: NestedTuple { + /// The list type with `Item` inserted at `Idx`. + type Output: NestedTuple; + + /// Consumes the list, returning the list with `Item` inserted at `Idx`. + /// + /// # Examples + /// + /// ``` + /// use tuplities::{neple, NestedTupleInsert}; + /// use typenum::{U0, U1}; + /// + /// assert_eq!(NestedTupleInsert::::nested_insert((), 7_u8), (7_u8,)); + /// + /// let inserted = NestedTupleInsert::::nested_insert(neple!(1_u8, 2_u16), 3_u32); + /// assert_eq!(inserted, neple!(1_u8, 3_u32, 2_u16)); + /// ``` + /// + /// ```compile_fail + /// use tuplities::NestedTupleInsert; + /// use typenum::U3; + /// + /// let _ = NestedTupleInsert::::nested_insert((1_u8, (2_u16, ())), 3_u32); + /// ``` + /// + /// ```compile_fail + /// use tuplities::{neple, NestedTupleInsert}; + /// use typenum::U2; + /// + /// let tail = neple!(1_u8, 2_u16); + /// let _ = NestedTupleInsert::::nested_insert((0_u8, &tail), 9_u16); + /// ``` + fn nested_insert(self, item: Item) -> Self::Output; +} + +/// Removes at `typenum` indices below `NestedTuple::LEN`, singleton-terminating rebuilt prefixes when the remainder becomes empty. +pub trait NestedTupleRemove: NestedTuple { + /// The type of the removed head. + type Removed; + + /// The rebuilt list holding the remaining heads. + type Remainder: NestedTuple; + + /// Consumes the list, returning the removed head and the remainder. + /// + /// # Examples + /// + /// ``` + /// use tuplities::{neple, NestedTupleRemove}; + /// use typenum::{U0, U2}; + /// + /// assert_eq!(NestedTupleRemove::::nested_remove(neple!(7_u8)), (7_u8, ())); + /// + /// let (removed, remainder) = + /// NestedTupleRemove::::nested_remove(neple!(1_u8, 2_u16, 3_u32)); + /// assert_eq!((removed, remainder), (3_u32, neple!(1_u8, 2_u16))); + /// ``` + /// + /// ```compile_fail + /// use tuplities::NestedTupleRemove; + /// use typenum::U2; + /// + /// let _ = NestedTupleRemove::::nested_remove((1_u8, (2_u16, ()))); + /// ``` + /// + /// ```compile_fail + /// use tuplities::NestedTupleRemove; + /// use typenum::U0; + /// + /// let _ = NestedTupleRemove::::nested_remove(()); + /// ``` + /// + /// ```compile_fail + /// use tuplities::{neple, NestedTupleRemove}; + /// use typenum::U1; + /// + /// let tail = neple!(1_u8, 2_u16); + /// let _ = NestedTupleRemove::::nested_remove((0_u8, &tail)); + /// ``` + fn nested_remove(self) -> (Self::Removed, Self::Remainder); +} + +impl NestedTupleSplit for T { + type Prefix = (); + type Suffix = Self; + + #[inline] + fn nested_split(self) -> (Self::Prefix, Self::Suffix) { + ((), self) + } +} + +impl NestedTupleSplit for (Head,) { + type Prefix = (Head,); + type Suffix = (); + + #[inline] + fn nested_split(self) -> (Self::Prefix, Self::Suffix) { + ((self.0,), ()) + } +} + +impl NestedTupleSplit> for (Head, Tail) +where + typenum::UInt: core::ops::Sub, + Tail: NestedTupleSplit>>, + >>>::Prefix: + NestedTuplePushFront, +{ + type Prefix = <>>>::Prefix + as NestedTuplePushFront>::Output; + type Suffix = >>>::Suffix; + + #[inline] + fn nested_split(self) -> (Self::Prefix, Self::Suffix) { + let (head, tail) = self; + let (prefix, suffix) = + >>>::nested_split(tail); + (prefix.nested_push_front(head), suffix) + } +} + +impl NestedTupleInsert for T +where + T: NestedTuple + NestedTuplePushFront, +{ + type Output = >::Output; + + #[inline] + fn nested_insert(self, item: Item) -> Self::Output { + self.nested_push_front(item) + } +} + +impl NestedTupleInsert for (Head,) { + type Output = (Head, (Item,)); + + #[inline] + fn nested_insert(self, item: Item) -> Self::Output { + (self.0, (item,)) + } +} + +impl NestedTupleInsert, Item> for (Head, Tail) +where + typenum::UInt: core::ops::Sub, + Tail: NestedTupleInsert>, Item>, +{ + type Output = ( + Head, + >, Item>>::Output, + ); + + #[inline] + fn nested_insert(self, item: Item) -> Self::Output { + let (head, tail) = self; + let inserted = + >, Item>>::nested_insert( + tail, item, + ); + (head, inserted) + } +} + +impl NestedTupleRemove for (Head,) { + type Removed = Head; + type Remainder = (); + + #[inline] + fn nested_remove(self) -> (Self::Removed, Self::Remainder) { + (self.0, ()) + } +} + +impl NestedTupleRemove for (Head, Tail) { + type Removed = Head; + type Remainder = Tail; + + #[inline] + fn nested_remove(self) -> (Self::Removed, Self::Remainder) { + (self.0, self.1) + } +} + +impl NestedTupleRemove> for (Head, Tail) +where + typenum::UInt: core::ops::Sub, + Tail: NestedTupleRemove>>, + >>>::Remainder: + NestedTuplePushFront, +{ + type Removed = >>>::Removed; + type Remainder = <>>>::Remainder + as NestedTuplePushFront>::Output; + + #[inline] + fn nested_remove(self) -> (Self::Removed, Self::Remainder) { + let (head, tail) = self; + let (removed, remainder) = + >>>::nested_remove(tail); + (removed, remainder.nested_push_front(head)) + } +} diff --git a/tuplities-flatten-nest/src/nested_try_from.rs b/tuplities/src/nested_try_from.rs similarity index 81% rename from tuplities-flatten-nest/src/nested_try_from.rs rename to tuplities/src/nested_try_from.rs index 7d647d3..7f98db8 100644 --- a/tuplities-flatten-nest/src/nested_try_from.rs +++ b/tuplities/src/nested_try_from.rs @@ -15,6 +15,23 @@ pub trait NestedTupleTryFrom: Sized { /// # Errors /// /// Returns an error of type `E` if any element conversion fails. + /// + /// # Examples + /// + /// ```rust + /// use core::num::TryFromIntError; + /// use tuplities::NestedTupleTryFrom; + /// + /// let source = (1_u8, (2_u8, (3_u8,))); + /// let result: Result<(u16, (u16, (u16,))), TryFromIntError> = + /// <(u16, (u16, (u16,)))>::nested_tuple_try_from(source); + /// assert_eq!(result, Ok((1_u16, (2, (3,))))); + /// + /// let source = (1_u16, (300_u16, (3_u16,))); + /// let result: Result<(u8, (u8, (u8,))), TryFromIntError> = + /// <(u8, (u8, (u8,)))>::nested_tuple_try_from(source); + /// assert!(matches!(result, Err(_))); + /// ``` fn nested_tuple_try_from(other: T) -> Result; } @@ -29,6 +46,23 @@ pub trait NestedTupleTryInto: Sized { /// # Errors /// /// Returns an error of type `E` if any element conversion fails. + /// + /// # Examples + /// + /// ```rust + /// use core::num::TryFromIntError; + /// use tuplities::NestedTupleTryInto; + /// + /// let source = (1_u8, (2_u8, (3_u8,))); + /// let result: Result<(u16, (u16, (u16,))), TryFromIntError> = + /// source.nested_tuple_try_into(); + /// assert_eq!(result, Ok((1_u16, (2, (3,))))); + /// + /// let source = (1_u16, (300_u16, (3_u16,))); + /// let result: Result<(u8, (u8, (u8,))), TryFromIntError> = + /// source.nested_tuple_try_into(); + /// assert!(matches!(result, Err(_))); + /// ``` fn nested_tuple_try_into(self) -> Result; } @@ -49,6 +83,16 @@ where /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleFrom: Sized { /// Converts `other` into `Self` by applying `From` element-wise. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleFrom; + /// + /// let source = (1_u8, (2_u8, (3_u8,))); + /// let result: (u16, (u16, (u16,))) = <(u16, (u16, (u16,)))>::nested_tuple_from(source); + /// assert_eq!(result, (1_u16, (2, (3,)))); + /// ``` fn nested_tuple_from(other: T) -> Self; } @@ -59,12 +103,22 @@ pub trait NestedTupleFrom: Sized { /// Part of the [`tuplities`](https://docs.rs/tuplities/latest/tuplities/) crate. pub trait NestedTupleInto: Sized { /// Converts `self` into `T` by applying `Into` element-wise. + /// + /// # Examples + /// + /// ```rust + /// use tuplities::NestedTupleInto; + /// + /// let source = (1_u8, (2_u8, (3_u8,))); + /// let result: (u16, (u16, (u16,))) = source.nested_tuple_into(); + /// assert_eq!(result, (1_u16, (2, (3,)))); + /// ``` fn nested_tuple_into(self) -> T; } impl NestedTupleInto<()> for () { #[inline] - fn nested_tuple_into(self) -> () {} + fn nested_tuple_into(self) {} } impl NestedTupleInto<(OtherHead,)> for (Head,) diff --git a/tuplities/src/nested_tuple.rs b/tuplities/src/nested_tuple.rs new file mode 100644 index 0000000..465c554 --- /dev/null +++ b/tuplities/src/nested_tuple.rs @@ -0,0 +1,88 @@ +//! Structural membership, length, and construction for recursive tuples. + +/// A recursive list with unit or singleton termination and an element count. +/// +/// ``` +/// use tuplities::NestedTuple; +/// +/// assert_eq!(<()>::LEN, 0); +/// assert_eq!(<(u8, (u16,))>::LEN, 2); +/// assert_eq!(<(u8, (u16, ()))>::LEN, 2); +/// ``` +/// +/// Scalar tails do not form recursive lists. +/// +/// ```compile_fail +/// use tuplities::NestedTuple; +/// +/// fn length(_: T) -> usize { T::LEN } +/// let _ = length((1_u8, 2_u8)); +/// ``` +pub trait NestedTuple { + /// The number of heads in the recursive list. + const LEN: usize; +} + +impl NestedTuple for () { + const LEN: usize = 0; +} + +impl NestedTuple for (Head,) { + const LEN: usize = 1; +} + +impl NestedTuple for (Head, Tail) { + const LEN: usize = 1 + Tail::LEN; +} + +impl NestedTuple for &T { + const LEN: usize = T::LEN; +} + +impl NestedTuple for &mut T { + const LEN: usize = T::LEN; +} + +/// Constructs a singleton-terminated recursive tuple, evaluating each expression once from left to right. +/// +/// ``` +/// use tuplities::neple; +/// +/// let values = neple!(1_u8, "two", (true, 3_u16),); +/// assert_eq!(values, (1, ("two", ((true, 3),)))); +/// ``` +#[macro_export] +macro_rules! neple { + () => { + () + }; + ($head:expr $(,)?) => { + ($head,) + }; + ($head:expr, $($tail:expr),+ $(,)?) => { + ($head, $crate::neple!($($tail),+)) + }; +} + +/// Names the singleton-terminated recursive tuple type for the supplied element types. +/// +/// ``` +/// use tuplities::{neple, neplety, NestedTuple}; +/// +/// type Values = neplety!(u8, &'static str, (bool, u16),); +/// let values: Values = neple!(1, "two", (true, 3)); +/// assert_eq!(Values::LEN, 3); +/// assert_eq!(values, (1, ("two", ((true, 3),)))); +/// ``` +#[macro_export] +macro_rules! neplety { + () => { + () + }; + ($head:ty $(,)?) => { + ($head,) + }; + ($head:ty, $($tail:ty),+ $(,)?) => { + ($head, $crate::neplety!($($tail),+)) + }; +} diff --git a/tuplities/tests/construction_macros.rs b/tuplities/tests/construction_macros.rs new file mode 100644 index 0000000..d5a6a3d --- /dev/null +++ b/tuplities/tests/construction_macros.rs @@ -0,0 +1,53 @@ +//! Construction preserves element boundaries, ownership, and evaluation order. + +use tuplities::{NestedTuple, NestedTupleChain, neple as list, neplety as List}; + +#[derive(Debug, PartialEq)] +struct Owned(u8); + +#[test] +fn empty_and_singleton_inputs_have_canonical_termination() { + type Empty = List!(); + type Singleton = List!(Owned,); + assert_eq!(Empty::LEN, 0); + assert_eq!(Singleton::LEN, 1); + let original = Owned(7); + let values: Singleton = list!().chain(list!(original,)); + assert_eq!(values, (Owned(7),)); + let singleton: List!(Owned) = list!(Owned(8)); + assert_eq!(singleton, (Owned(8),)); +} + +#[test] +fn expressions_are_moved_once_in_left_to_right_order() { + let mut calls = 0; + let mut next = || { + calls += 1; + Owned(calls) + }; + let values = list!(next(), next(), next(),); + assert_eq!(values, (Owned(1), (Owned(2), (Owned(3),)))); + assert_eq!(calls, 3); +} + +#[test] +fn complex_types_and_tuple_heads_keep_element_boundaries() { + type Values = List!((u8, u16), Option>, [u8; 2],); + let values: Values = list!((1, 2), Some(Ok(3)), [4, 5]); + assert_eq!(values, ((1, 2), (Some(Ok(3)), ([4, 5],)))); + assert_eq!(Values::LEN, 3); +} + +#[test] +fn borrowed_heads_preserve_lifetimes_and_mutate_original_storage() { + fn borrow(bytes: &mut [u8; 2]) -> List!(&mut [u8; 2], fn(u8, u8) -> u8) { + list!(bytes, u8::wrapping_add as fn(u8, u8) -> u8) + } + + let mut bytes = [250, 10]; + { + let values = borrow(&mut bytes); + values.0[0] = values.1.0(values.0[0], values.0[1]); + } + assert_eq!(bytes, [4, 10]); +} diff --git a/tuplities/tests/flat_bridge_contracts.rs b/tuplities/tests/flat_bridge_contracts.rs new file mode 100644 index 0000000..4f737df --- /dev/null +++ b/tuplities/tests/flat_bridge_contracts.rs @@ -0,0 +1,44 @@ +//! Flat and nested conversions preserve values and borrows. + +use tuplities::{ + FlattenNestedTuple, FlattenNestedTupleMatrix, NestTuple, NestTupleMatrix, NestTupleMut, + NestTupleRef, +}; + +#[test] +fn owned_round_trip_preserves_tuple_valued_heads() { + let values = (String::from("head"), (3_u8, 5_u16), vec![7_u32, 11]); + let nested = values.nest(); + assert_eq!(nested.0, "head"); + assert_eq!(nested.1.0, (3, 5)); + assert_eq!(nested.1.1.0, vec![7, 11]); + let flat = nested.flatten(); + assert_eq!(flat, (String::from("head"), (3, 5), vec![7, 11])); +} + +#[test] +fn borrowed_bridges_keep_the_original_storage() { + let mut flat = (String::from("head"), vec![2_u8, 3], 5_u16); + let references = flat.nest_ref().flatten(); + assert!(core::ptr::eq(references.0, &raw const flat.0)); + assert!(core::ptr::eq(references.1, &raw const flat.1)); + { + let nested = flat.nest_mut(); + nested.0.push('!'); + nested.1.0.push(7); + *nested.1.1.0 = 11; + } + assert_eq!(flat, (String::from("head!"), vec![2, 3, 7], 11)); +} + +#[test] +fn matrix_round_trip_preserves_rows_and_columns() { + let matrix = ((String::from("a"), 2_u8), (String::from("b"), 3_u8)); + let nested = matrix.nest_matrix(); + assert_eq!(nested.0.0, "a"); + assert_eq!(nested.0.1.0, 2); + assert_eq!(nested.1.0.0, "b"); + assert_eq!(nested.1.0.1.0, 3); + let flat = nested.flatten_matrix(); + assert_eq!(flat, ((String::from("a"), 2), (String::from("b"), 3))); +} diff --git a/tuplities/tests/flat_bridge_sizes.rs b/tuplities/tests/flat_bridge_sizes.rs new file mode 100644 index 0000000..f08663f --- /dev/null +++ b/tuplities/tests/flat_bridge_sizes.rs @@ -0,0 +1,66 @@ +//! Flat bridge boundaries preserve element order and borrowing. +#![recursion_limit = "256"] + +use tuplities::{FlattenNestedTuple, NestTuple, NestTupleMut, NestTupleRef}; + +macro_rules! nested_values { + ($head:expr) => { ($head,) }; + ($head:expr, $($tail:expr),+) => { ($head, nested_values!($($tail),+)) }; +} + +macro_rules! boundary_contract { + ($name:ident; $($index:tt),+) => { + #[test] + fn $name() { + let mut flat = ($($index + 1_000_usize,)+); + { + let references = flat.nest_mut().flatten(); + $(*references.$index += 1_000;)+ + } + let nested = flat.nest(); + assert_eq!(nested, nested_values!($($index + 2_000_usize),+)); + let flat = nested.flatten(); + $(assert_eq!(flat.$index, $index + 2_000);)+ + let references = flat.nest_ref().flatten(); + $(assert!(core::ptr::eq(references.$index, &flat.$index));)+ + } + }; +} + +boundary_contract!(width_8; 0, 1, 2, 3, 4, 5, 6, 7); + +#[cfg(any( + feature = "size-16", + feature = "size-32", + feature = "size-48", + feature = "size-64", + feature = "size-96", + feature = "size-128" +))] +boundary_contract!(width_16; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + +#[cfg(any( + feature = "size-32", + feature = "size-48", + feature = "size-64", + feature = "size-96", + feature = "size-128" +))] +boundary_contract!(width_32; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + +#[cfg(any( + feature = "size-48", + feature = "size-64", + feature = "size-96", + feature = "size-128" +))] +boundary_contract!(width_48; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47); + +#[cfg(any(feature = "size-64", feature = "size-96", feature = "size-128"))] +boundary_contract!(width_64; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63); + +#[cfg(any(feature = "size-96", feature = "size-128"))] +boundary_contract!(width_96; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95); + +#[cfg(feature = "size-128")] +boundary_contract!(width_128; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127); diff --git a/tuplities/tests/recursive_index.rs b/tuplities/tests/recursive_index.rs new file mode 100644 index 0000000..eb7d905 --- /dev/null +++ b/tuplities/tests/recursive_index.rs @@ -0,0 +1,122 @@ +//! Recursive indexing is independent of flat tuple conversion limits. + +use tuplities::{ + NestedTuple, NestedTupleIndex, NestedTupleIndexMut, NestedTupleRow, NestedTupleRowMut, +}; +use typenum::{U0, U1, U2, U4, U8, U9}; + +#[test] +fn recursive_index_exceeds_flat_limit() { + let mut values = (1_u8, (2, (3, (4, (5, (6, (7, (8, (9, (10,)))))))))); + assert_eq!(*NestedTupleIndex::::nested_index(&values), 9); + *NestedTupleIndexMut::::nested_index_mut(&mut values) = 11; + *NestedTupleIndexMut::::nested_index_mut(&mut values) = 55; + *NestedTupleIndexMut::::nested_index_mut(&mut values) = 100; + assert_eq!( + values, + (11, (2, (3, (4, (55, (6, (7, (8, (9, (100,)))))))))) + ); +} + +#[test] +fn length_counts_heads_and_both_termination_forms() { + fn length(_: &T) -> usize { + T::LEN + } + + assert_eq!(length(&()), 0); + assert_eq!(length(&(String::from("singleton"),)), 1); + let mut singleton_terminated = ((1_u8, 2_u16), (String::from("head"), (true,))); + assert_eq!(length(&singleton_terminated), 3); + assert_eq!(length(&&singleton_terminated), 3); + assert_eq!(length(&&mut singleton_terminated), 3); + assert_eq!( + length(&((1_u8, 2_u16), (String::from("head"), (true, ())))), + 3 + ); +} + +#[test] +fn unit_terminated_indices_preserve_unselected_elements() { + let mut values = (String::from("head"), (2_u16, (String::from("tail"), ()))); + assert_eq!(NestedTupleIndex::::nested_index(&values), "head"); + assert_eq!(*NestedTupleIndex::::nested_index(&values), 2); + assert_eq!(NestedTupleIndex::::nested_index(&values), "tail"); + NestedTupleIndexMut::::nested_index_mut(&mut values).push('!'); + assert_eq!( + values, + (String::from("head"), (2, (String::from("tail!"), ()))) + ); +} + +#[test] +fn indexing_borrowed_tails_mutates_original_storage() { + let mut tail = (String::from("middle"), (String::from("tail"), ())); + { + let mut values = (1_u8, &tail); + assert!(core::ptr::eq( + NestedTupleIndex::::nested_index(&values), + &raw const tail.0, + )); + assert_eq!(NestedTupleIndex::::nested_index(&values), "tail"); + *NestedTupleIndexMut::::nested_index_mut(&mut values) = 2; + assert_eq!(values.0, 2); + } + { + let mut values = (1_u8, &mut tail); + NestedTupleIndexMut::::nested_index_mut(&mut values).push('!'); + NestedTupleIndexMut::::nested_index_mut(&mut values).push('?'); + assert_eq!(*NestedTupleIndex::::nested_index(&values), 1); + } + assert_eq!(tail, (String::from("middle!"), (String::from("tail?"), ()))); +} + +#[test] +fn row_access_exceeds_flat_limit_for_both_inner_terminations() { + let first = (1_u8, (2, (3, (4, (5, (6, (7, (8, (9, (10,)))))))))); + let second = ( + 11_u16, + (12, (13, (14, (15, (16, (17, (18, (19, (20, ()))))))))), + ); + let mut matrix = (first, (second, ())); + let row = NestedTupleRow::::nested_tuple_row(&matrix); + assert_eq!(row, (&9, (&19, ()))); + { + let row = NestedTupleRowMut::::nested_tuple_row_mut(&mut matrix); + *row.0 = 99; + *row.1.0 = 199; + } + assert_eq!( + matrix, + ( + (1, (2, (3, (4, (5, (6, (7, (8, (99, (10,)))))))))), + ( + ( + 11, + (12, (13, (14, (15, (16, (17, (18, (199, (20, ()))))))))) + ), + () + ) + ), + ); +} + +#[test] +fn row_access_through_borrowed_outer_tail_updates_original_matrix() { + let mut tail = ((30_u16, (40_u16, ())), ()); + { + let mut matrix = ((10_u8, (20_u8, ())), &mut tail); + let row = NestedTupleRow::::nested_tuple_row(&matrix); + assert_eq!(row, (&20, (&40, ()))); + let row = NestedTupleRowMut::::nested_tuple_row_mut(&mut matrix); + *row.0 = 21; + *row.1.0 = 41; + assert_eq!(matrix.0, (10, (21, ()))); + } + assert_eq!(tail, ((30, (41, ())), ())); + let matrix = ((10_u8, (20_u8, ())), &tail); + assert_eq!( + NestedTupleRow::::nested_tuple_row(&matrix), + (&20, (&41, ())) + ); +} diff --git a/tuplities/tests/recursive_structure.rs b/tuplities/tests/recursive_structure.rs new file mode 100644 index 0000000..00d2bad --- /dev/null +++ b/tuplities/tests/recursive_structure.rs @@ -0,0 +1,216 @@ +//! Consuming operations preserve elements, ownership, and termination contracts. + +use core::cell::Cell; +use tuplities::prelude::*; +use typenum::{U0, U1, U2, U3}; + +#[test] +fn split_preserves_suffixes_and_normalizes_prefixes() { + assert_eq!(NestedTupleSplit::::nested_split(()), ((), ())); + let result: ((), neplety!(u8)) = NestedTupleSplit::::nested_split(neple!(7_u8)); + assert_eq!(result, ((), (7,))); + let result: (neplety!(u8), ()) = NestedTupleSplit::::nested_split(neple!(7_u8)); + assert_eq!(result, ((7,), ())); + let original = (1_u8, (2_u16, (3_u32, ()))); + let (prefix, suffix): (neplety!(u8), (u16, (u32, ()))) = + NestedTupleSplit::::nested_split(original); + assert_eq!((prefix, suffix), ((1,), (2, (3, ())))); + assert_eq!(prefix.chain(suffix), original); + let result: (neplety!(u8, u16), neplety!(u32)) = + NestedTupleSplit::::nested_split(neple!(1_u8, 2_u16, 3_u32)); + assert_eq!(result, ((1, (2,)), (3,))); + let result: (neplety!(u8, u16, u32), ()) = NestedTupleSplit::::nested_split(original); + assert_eq!(result, (neple!(1, 2, 3), ())); +} + +#[test] +fn insert_accepts_every_boundary_and_preserves_untouched_termination() { + assert_eq!(NestedTupleInsert::::nested_insert((), 7_u8), (7,)); + assert_eq!( + NestedTupleInsert::::nested_insert(neple!(2_u16), 1_u8), + neple!(1, 2) + ); + assert_eq!( + NestedTupleInsert::::nested_insert(neple!(1_u8), 2_u16), + neple!(1, 2) + ); + let original = (1_u8, (2_u16, (3_u32, ()))); + assert_eq!( + NestedTupleInsert::::nested_insert(original, false), + (false, original) + ); + assert_eq!( + NestedTupleInsert::::nested_insert(original, (4_u8, 5_u16)), + (1, ((4, 5), (2, (3, ())))) + ); + assert_eq!( + NestedTupleInsert::::nested_insert(original, false), + (1, (2, (false, (3, ())))) + ); + let appended: neplety!(u8, u16, u32, bool) = + NestedTupleInsert::::nested_insert(original, true); + assert_eq!(appended, neple!(1, 2, 3, true)); +} + +#[test] +fn remove_preserves_suffixes_and_normalizes_empty_remainders() { + assert_eq!( + NestedTupleRemove::::nested_remove(neple!(7_u8)), + (7, ()) + ); + assert_eq!(NestedTupleRemove::::nested_remove((7_u8, ())), (7, ())); + let original = (1_u8, (2_u16, (3_u32, ()))); + assert_eq!( + NestedTupleRemove::::nested_remove(original), + (1, (2, (3, ()))) + ); + assert_eq!( + NestedTupleRemove::::nested_remove(original), + (2, (1, (3, ()))) + ); + let result: (u32, neplety!(u8, u16)) = NestedTupleRemove::::nested_remove(original); + assert_eq!(result, (3, neple!(1, 2))); + assert_eq!( + NestedTupleRemove::::nested_remove(neple!((1_u8, 2_u16), true)), + ((1, 2), (true,)) + ); +} + +#[test] +fn reverse_normalizes_both_terminations_without_flattening_heads() { + assert_eq!(NestedTupleReverse::nested_reverse(neple!(7_u8)), (7,)); + assert_eq!(NestedTupleReverse::nested_reverse((7_u8, ())), (7,)); + let original = ((1_u8, 2_u16), (3_u32, (false, ()))); + let reversed: neplety!(bool, u32, (u8, u16)) = NestedTupleReverse::nested_reverse(original); + assert_eq!(reversed, neple!(false, 3, (1, 2))); + assert_eq!(reversed.nested_reverse(), neple!((1, 2), 3, false)); + assert_eq!( + NestedTupleReverse::nested_reverse(neple!(1_u8, 2_u16, 3_u32)), + neple!(3, 2, 1) + ); +} + +#[test] +fn borrowed_suffixes_remain_untouched_at_owned_boundaries() { + let tail = neple!(String::from("tail"), false); + let (prefix, suffix) = NestedTupleSplit::::nested_split((1_u8, &tail)); + assert_eq!(prefix, (1,)); + assert!(core::ptr::eq(suffix, &raw const tail)); + let inserted = NestedTupleInsert::::nested_insert((1_u8, &tail), 2_u16); + assert_eq!((inserted.0, inserted.1.0), (1, 2)); + assert!(core::ptr::eq(inserted.1.1, &raw const tail)); + let (removed, remainder) = NestedTupleRemove::::nested_remove((1_u8, &tail)); + assert_eq!(removed, 1); + assert!(core::ptr::eq(remainder, &raw const tail)); + let empty = (); + let result: (_, (u8,)) = NestedTupleRemove::::nested_remove((1_u8, (2_u16, &empty))); + assert_eq!(result, (2, (1,))); + assert_eq!(NestedTupleReverse::nested_reverse((1_u8, &empty)), (1,)); +} + +#[test] +fn reference_elements_use_the_same_consuming_operations() { + let mut values = neple!(String::from("a"), String::from("b"), String::from("c")); + let mut extra = String::from("new"); + { + let (prefix, suffix) = NestedTupleSplit::::nested_split(values.nested_tuple_mut()); + let joined = prefix.chain(suffix); + let inserted = NestedTupleInsert::::nested_insert(joined, &mut extra); + let (removed, remainder) = NestedTupleRemove::::nested_remove(inserted); + removed.push('?'); + let reversed = remainder.nested_reverse(); + reversed.0.push('#'); + reversed.1.0.push('+'); + reversed.1.1.0.push('!'); + } + assert_eq!( + ( + values.0.as_str(), + values.1.0.as_str(), + values.1.1.0.as_str(), + extra.as_str() + ), + ("a!", "b?", "c#", "new+") + ); + let shared = values.nested_tuple_ref().nested_reverse(); + assert_eq!( + ( + shared.0.as_str(), + shared.1.0.as_str(), + shared.1.1.0.as_str() + ), + ("c#", "b?", "a!") + ); +} + +#[derive(Debug)] +struct Tracked<'a> { + id: u8, + drops: &'a Cell, +} + +impl Drop for Tracked<'_> { + fn drop(&mut self) { + self.drops.set(self.drops.get().saturating_add(1)); + } +} + +#[test] +fn all_operations_transfer_noncopy_elements_and_drop_each_once() { + let drops: [Cell; 4] = core::array::from_fn(|_| Cell::new(0)); + { + let source = neple!( + Tracked { + id: 0, + drops: &drops[0] + }, + Tracked { + id: 1, + drops: &drops[1] + }, + Tracked { + id: 2, + drops: &drops[2] + } + ); + let (prefix, suffix) = NestedTupleSplit::::nested_split(source); + let inserted = NestedTupleInsert::::nested_insert( + prefix.chain(suffix), + Tracked { + id: 3, + drops: &drops[3], + }, + ); + let (removed, remainder) = NestedTupleRemove::::nested_remove(inserted); + let reversed = remainder.nested_reverse(); + assert_eq!(removed.id, 1); + assert_eq!( + (reversed.0.id, reversed.1.0.id, reversed.1.1.0.id), + (2, 3, 0) + ); + assert_eq!(drops.each_ref().map(Cell::get), [0, 0, 0, 0]); + drop(removed); + assert_eq!(drops.each_ref().map(Cell::get), [0, 1, 0, 0]); + } + assert_eq!(drops.each_ref().map(Cell::get), [1, 1, 1, 1]); +} + +#[test] +fn mutable_borrowed_suffixes_preserve_storage_without_traversal() { + let mut tail = neple!(String::from("head"), String::from("tail")); + { + let (prefix, suffix) = NestedTupleSplit::::nested_split((1_u8, &mut tail)); + assert_eq!(prefix, (1,)); + suffix.0.push('!'); + let inserted = NestedTupleInsert::::nested_insert((prefix.0, suffix), 2_u16); + inserted.1.1.1.0.push('?'); + let (removed, remainder) = NestedTupleRemove::::nested_remove(inserted); + assert_eq!(removed, 2); + assert_eq!(remainder.0, 1); + } + assert_eq!((tail.0.as_str(), tail.1.0.as_str()), ("head!", "tail?")); + let mut empty = (); + let remainder: (u8,) = NestedTupleRemove::::nested_remove((1_u8, (2_u16, &mut empty))).1; + assert_eq!(remainder, (1,)); + assert_eq!(NestedTupleReverse::nested_reverse((3_u8, &mut empty)), (3,)); +}