diff --git a/.cargo/config.toml b/.cargo/config.toml index 8af940d..1e98ea8 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,4 +1,4 @@ -[build] -rustdocflags = ["--cfg", "docsrs"] - -[env] +[build] +rustdocflags = ["--cfg", "docsrs"] + +[env] diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a3437e5..92f5664 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -github: djkoloski +github: djkoloski diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfb86ac..ab358d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,128 +1,128 @@ -name: CI - -on: - push: - pull_request: - workflow_dispatch: - schedule: - - cron: "0 10 * * *" - -permissions: - contents: read - -env: - RUSTFLAGS: -Dwarnings - -jobs: - toolchain: - name: Toolchain / ${{ matrix.toolchain }} ${{ matrix.opt }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - toolchain: - - stable - - beta - - nightly - opt: - - '' - - --release - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.toolchain }} - - run: cargo test --verbose ${{ matrix.opt }} - - miri: - name: Miri / ${{ matrix.opt }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - opt: - - '' - - --release - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@miri - - run: cargo miri setup - - run: cargo miri test ${{ matrix.opt }} --verbose - env: - MIRIFLAGS: -Zmiri-disable-stacked-borrows -Zmiri-tree-borrows - - test: - name: Test / ${{ matrix.target }} ${{ matrix.opt }} - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - opt: - - '' - - --release - include: - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - - os: macos-latest - target: aarch64-apple-darwin - - os: windows-latest - target: x86_64-pc-windows-msvc - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - run: cargo test ${{ matrix.opt }} - - cross: - name: Cross / ${{ matrix.target }} - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - target: - - i686-unknown-linux-gnu - - i586-unknown-linux-gnu - - armv7-unknown-linux-gnueabihf - - aarch64-unknown-linux-gnu - - thumbv6m-none-eabi - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - run: cargo install cross - - run: cross build --no-default-features --target ${{ matrix.target }} --verbose - - format: - name: Format - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly - with: - components: rustfmt - - run: cargo fmt --check - - clippy: - name: Clippy - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly - with: - components: clippy - - run: cargo clippy - - doc: - name: Doc - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly - - run: cargo doc +name: CI + +on: + push: + pull_request: + workflow_dispatch: + schedule: + - cron: "0 10 * * *" + +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + +jobs: + toolchain: + name: Toolchain / ${{ matrix.toolchain }} ${{ matrix.opt }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + toolchain: + - stable + - beta + - nightly + opt: + - '' + - --release + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.toolchain }} + - run: cargo test --verbose ${{ matrix.opt }} + + miri: + name: Miri / ${{ matrix.opt }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + opt: + - '' + - --release + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@miri + - run: cargo miri setup + - run: cargo miri test ${{ matrix.opt }} --verbose + env: + MIRIFLAGS: -Zmiri-disable-stacked-borrows -Zmiri-tree-borrows + + test: + name: Test / ${{ matrix.target }} ${{ matrix.opt }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + opt: + - '' + - --release + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + - os: macos-latest + target: aarch64-apple-darwin + - os: windows-latest + target: x86_64-pc-windows-msvc + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test ${{ matrix.opt }} + + cross: + name: Cross / ${{ matrix.target }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + target: + - i686-unknown-linux-gnu + - i586-unknown-linux-gnu + - armv7-unknown-linux-gnueabihf + - aarch64-unknown-linux-gnu + - thumbv6m-none-eabi + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: cargo install cross + - run: cross build --no-default-features --target ${{ matrix.target }} --verbose + + format: + name: Format + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + - run: cargo fmt --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + components: clippy + - run: cargo clippy + + doc: + name: Doc + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo doc diff --git a/LICENSE b/LICENSE index 520fc25..717da2e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ -Copyright 2024 David Koloski - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Copyright 2024 David Koloski + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/munge/LICENSE b/munge/LICENSE index 520fc25..717da2e 100644 --- a/munge/LICENSE +++ b/munge/LICENSE @@ -1,7 +1,7 @@ -Copyright 2024 David Koloski - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Copyright 2024 David Koloski + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/munge/example.md b/munge/example.md index a436060..861320a 100644 --- a/munge/example.md +++ b/munge/example.md @@ -1,116 +1,116 @@ - -Initialize `MaybeUninit`s: - -```rust -use core::mem::MaybeUninit; -use munge::munge; - -pub struct Example { - a: u32, - b: (char, f32), -} - -let mut mu = MaybeUninit::::uninit(); - -munge!(let Example { a, b: (c, mut f) } = &mut mu); -assert_eq!(a.write(10), &10); -assert_eq!(c.write('x'), &'x'); -assert_eq!(f.write(3.14), &3.14); -// Note that `mut` bindings can be reassigned like you'd expect: -f = &mut MaybeUninit::uninit(); - -// SAFETY: `mu` is completely initialized. -let init = unsafe { mu.assume_init() }; -assert_eq!(init.a, 10); -assert_eq!(init.b.0, 'x'); -assert_eq!(init.b.1, 3.14); -``` - -Destructure `Cell`s: - -```rust -use core::cell::Cell; -use munge::munge; - -pub struct Example { - a: u32, - b: (char, f32), -} - -let value = Example { - a: 10, - b: ('x', 3.14), -}; -let cell = Cell::::new(value); - -munge!(let Example { a, b: (c, f) } = &cell); -assert_eq!(a.get(), 10); -a.set(42); -assert_eq!(c.get(), 'x'); -c.set('!'); -assert_eq!(f.get(), 3.14); -f.set(1.41); - -let value = cell.into_inner(); -assert_eq!(value.a, 42); -assert_eq!(value.b.0, '!'); -assert_eq!(value.b.1, 1.41); -``` - -You can even extend munge to work with your own types by implementing its -`Destructure` and `Restructure` traits: - -```rust -use munge::{Destructure, Restructure, Move, munge}; - -pub struct Invariant(T); - -impl Invariant { - /// # Safety - /// - /// `value` must uphold my custom invariant. - pub unsafe fn new_unchecked(value: T) -> Self { - Self(value) - } - - pub fn unwrap(self) -> T { - self.0 - } -} - -// SAFETY: -// - `Invariant` is destructured by move, so its `Destructuring` type is -// `Move`. -// - `underlying` returns a pointer to its inner type, so it is guaranteed -// to be non-null, properly aligned, and valid for reads. -unsafe impl Destructure for Invariant { - type Underlying = T; - type Destructuring = Move; - - fn underlying(&mut self) -> *mut Self::Underlying { - &mut self.0 as *mut Self::Underlying - } -} - -// SAFETY: `restructure` returns an `Invariant` that takes ownership of -// the restructured field because `Invariant` is destructured by move. -unsafe impl Restructure for Invariant { - type Restructured = Invariant; - - unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured { - // SAFETY: The caller has guaranteed that `ptr` is a pointer to a - // subfield of some `T`, so it must be properly aligned, valid for - // reads, and initialized. We may move the fields because the - // destructuring type for `Invariant` is `Move`. - let value = unsafe { ptr.read() }; - Invariant(value) - } -} - -// SAFETY: `(1, 2, 3)` upholds my custom invariant. -let value = unsafe { Invariant::new_unchecked((1, 2, 3)) }; -munge!(let (one, two, three) = value); -assert_eq!(one.unwrap(), 1); -assert_eq!(two.unwrap(), 2); -assert_eq!(three.unwrap(), 3); -``` + +Initialize `MaybeUninit`s: + +```rust +use core::mem::MaybeUninit; +use munge::munge; + +pub struct Example { + a: u32, + b: (char, f32), +} + +let mut mu = MaybeUninit::::uninit(); + +munge!(let Example { a, b: (c, mut f) } = &mut mu); +assert_eq!(a.write(10), &10); +assert_eq!(c.write('x'), &'x'); +assert_eq!(f.write(3.14), &3.14); +// Note that `mut` bindings can be reassigned like you'd expect: +f = &mut MaybeUninit::uninit(); + +// SAFETY: `mu` is completely initialized. +let init = unsafe { mu.assume_init() }; +assert_eq!(init.a, 10); +assert_eq!(init.b.0, 'x'); +assert_eq!(init.b.1, 3.14); +``` + +Destructure `Cell`s: + +```rust +use core::cell::Cell; +use munge::munge; + +pub struct Example { + a: u32, + b: (char, f32), +} + +let value = Example { + a: 10, + b: ('x', 3.14), +}; +let cell = Cell::::new(value); + +munge!(let Example { a, b: (c, f) } = &cell); +assert_eq!(a.get(), 10); +a.set(42); +assert_eq!(c.get(), 'x'); +c.set('!'); +assert_eq!(f.get(), 3.14); +f.set(1.41); + +let value = cell.into_inner(); +assert_eq!(value.a, 42); +assert_eq!(value.b.0, '!'); +assert_eq!(value.b.1, 1.41); +``` + +You can even extend munge to work with your own types by implementing its +`Destructure` and `Restructure` traits: + +```rust +use munge::{Destructure, Restructure, Move, munge}; + +pub struct Invariant(T); + +impl Invariant { + /// # Safety + /// + /// `value` must uphold my custom invariant. + pub unsafe fn new_unchecked(value: T) -> Self { + Self(value) + } + + pub fn unwrap(self) -> T { + self.0 + } +} + +// SAFETY: +// - `Invariant` is destructured by move, so its `Destructuring` type is +// `Move`. +// - `underlying` returns a pointer to its inner type, so it is guaranteed +// to be non-null, properly aligned, and valid for reads. +unsafe impl Destructure for Invariant { + type Underlying = T; + type Destructuring = Move; + + fn underlying(&mut self) -> *mut Self::Underlying { + &mut self.0 as *mut Self::Underlying + } +} + +// SAFETY: `restructure` returns an `Invariant` that takes ownership of +// the restructured field because `Invariant` is destructured by move. +unsafe impl Restructure for Invariant { + type Restructured = Invariant; + + unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured { + // SAFETY: The caller has guaranteed that `ptr` is a pointer to a + // subfield of some `T`, so it must be properly aligned, valid for + // reads, and initialized. We may move the fields because the + // destructuring type for `Invariant` is `Move`. + let value = unsafe { ptr.read() }; + Invariant(value) + } +} + +// SAFETY: `(1, 2, 3)` upholds my custom invariant. +let value = unsafe { Invariant::new_unchecked((1, 2, 3)) }; +munge!(let (one, two, three) = value); +assert_eq!(one.unwrap(), 1); +assert_eq!(two.unwrap(), 2); +assert_eq!(three.unwrap(), 3); +``` diff --git a/munge/tests/ui/rest_patterns_ref_only.rs b/munge/tests/ui/rest_patterns_ref_only.rs index e05be09..e9f54a2 100644 --- a/munge/tests/ui/rest_patterns_ref_only.rs +++ b/munge/tests/ui/rest_patterns_ref_only.rs @@ -1,19 +1,19 @@ -use core::mem::MaybeUninit; -use munge::munge; - -fn main() { - struct Struct { - a: u32, - b: u32, - } - - let mut mu = MaybeUninit::::uninit(); - - munge!(let Struct { a, .. } = mu); - - struct Tuple(u32, u32); - - let mut mu = MaybeUninit::::uninit(); - - munge!(let Tuple(a, ..) = mu); -} +use core::mem::MaybeUninit; +use munge::munge; + +fn main() { + struct Struct { + a: u32, + b: u32, + } + + let mut mu = MaybeUninit::::uninit(); + + munge!(let Struct { a, .. } = mu); + + struct Tuple(u32, u32); + + let mut mu = MaybeUninit::::uninit(); + + munge!(let Tuple(a, ..) = mu); +} diff --git a/munge_macro/LICENSE b/munge_macro/LICENSE index 520fc25..717da2e 100644 --- a/munge_macro/LICENSE +++ b/munge_macro/LICENSE @@ -1,7 +1,7 @@ -Copyright 2024 David Koloski - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Copyright 2024 David Koloski + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.