assign-1.1.1/.cargo_vcs_info.json0000644000000001121377305776200123710ustar { "git": { "sha1": "033393524a27ba8e051ea9f34f112f5303033d5a" } } assign-1.1.1/.github/workflows/build_test.yml010064400017500001750000000014151377305740400174500ustar 00000000000000on: push: branches: [master] pull_request: name: Build, Test jobs: build-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal components: rustfmt, clippy - name: Build uses: actions-rs/cargo@v1 with: command: build - name: Run tests uses: actions-rs/cargo@v1 with: command: test - name: Check formatting uses: actions-rs/cargo@v1 with: command: fmt args: -- --check - name: Catch common mistakes uses: actions-rs/cargo@v1 with: command: clippy args: --all-targets -- -D warnings assign-1.1.1/.gitignore010064400017500001750000000000231370355563200131530ustar 00000000000000/target Cargo.lock assign-1.1.1/CONTRIBUTING.md010064400017500001750000000022011370355564300134160ustar 00000000000000# Contributing to assign! assign! welcomes contribution via issues or code. ## Issues Task tracking, enhancements, and bugs go to [issues](https://github.com/Kelerchian/assign/issues). ## Submitting code To submit code, please follow these steps: 1. Fork the repository, or create branch if you are a contributor 2. Push commits in your fork or branch. Commit pushes will be automatically tested. See versioning [Versioning section](#versioning) below. 3. Create Pull Request from your branch to the repository 4. Pull Request will be reviewed and merged after it is approved ### Documentation and Tests Write [documentation tests](https://doc.rust-lang.org/rustdoc/documentation-tests.html) to document and test code in one go. Use `cargo doc` to review the documentation before submitting code. ## Versioning assign! uses [semver](https://semver.org/) for versioning. Adjust the version in `Cargo.toml` accordingly. ## Publishing to crates.io Publishing assign! to crates.io is manually done from local machine. ``` cargo publish ``` You need to `cargo login` before publishing. Contact owner or contributor for ownership or API token. assign-1.1.1/Cargo.toml0000644000000016241377305776200104000ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "assign" version = "1.1.1" authors = ["Alan Darmasaputra ", "Jonas Platte "] description = "Simple macro to allow mutating instance with declarative flavor" readme = "README.md" keywords = ["macro"] categories = ["no-std"] license = "MIT" license-file = "LICENSE" repository = "https://github.com/Kelerchian/assign" assign-1.1.1/Cargo.toml.orig010064400017500001750000000006221377305761400140630ustar 00000000000000[package] name = "assign" version = "1.1.1" edition = "2018" description = "Simple macro to allow mutating instance with declarative flavor" categories = ["no-std"] keywords = ["macro"] authors = [ "Alan Darmasaputra ", "Jonas Platte ", ] repository = "https://github.com/Kelerchian/assign" readme = "README.md" license = "MIT" license-file = "LICENSE" assign-1.1.1/LICENSE010064400017500001750000000020411370355563200121720ustar 00000000000000Copyright 2020 Alan Darmasaputra 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. assign-1.1.1/README.md010064400017500001750000000031321377305740400124470ustar 00000000000000![Build, Test](https://github.com/Kelerchian/assign/workflows/Build,%20Test/badge.svg) # Assign Mutate instances with declarative flavor! This module provides macro `assign!` to allow mutating instance with declarative flavor The motivation of this macro is to enable programmer to document a sequence of mutations instance fields as initialization by writing it in a declarative way. `assign!` macro also allows programmer to skip defining fields that has default value. Such case are used when a dependency is exposing an non-exhaustive struct ## Usage ```rust #[macro_use] extern crate assign; fn main() { struct SomeStruct { a: u32, b: Option, c: String, } impl SomeStruct { fn new() -> SomeStruct { SomeStruct { a: 1u32, b: None, c: String::from("old"), } } } // In order to treat the mutation of field `a` and `c` as an initialization, // Use assign to mutate field in declarative flavor, thus avoiding the risk inserting code // between the line that defines a field and the line that defines the other // Note that field `b` is skipped let instance = assign!(SomeStruct::new(), { a: 2u32, c: String::from("new"), }); // Equivalent let instance2 = { let mut item = SomeStruct::new(); item.a = 2u32; item.c = String::from("new"); item }; assert_eq!(instance.a, instance2.a); assert_eq!(&instance.c, &instance2.c); assert_eq!(instance.b, instance2.b); } ``` ## License [MIT](LICENSE) assign-1.1.1/src/lib.rs010064400017500001750000000114071371302466300130720ustar 00000000000000//! This module provides the `assign!` macro to allow mutating a struct value in //! a declarative style. //! //! It is an alternative to [struct update syntax][] that works with //! [non-exhaustive][] structs. //! //! [struct update syntax]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax //! [non-exhaustive]: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute //! //! It is used as //! //! ``` //! # use assign::assign; //! # struct Struct { field: u8 } //! # let init_expression = Struct { field: 0 }; //! # let new_field_value = 1; //! let foo = assign!(init_expression, { //! field: new_field_value, //! // other_field: new_other_field_value, //! // ... //! }); //! ``` //! //! For details and examples, see the documentation for the macro itself. #![no_std] /// Mutate a struct value in a declarative style. /// /// # Basic usage /// /// ``` /// # use assign::assign; /// # /// #[non_exhaustive] /// #[derive(Debug, PartialEq)] /// struct SomeStruct { /// a: u32, /// b: Option, /// c: String, /// } /// /// impl SomeStruct { /// fn new() -> Self { /// // ... /// # SomeStruct { /// # a: 1u32, /// # b: None, /// # c: String::from("old"), /// # } /// } /// } /// /// let instance1 = assign!(SomeStruct::new(), { /// a: 2, /// c: "new".into(), /// }); /// /// // The same thing using mutation explicitly. /// // This is what the above expands to. /// let instance2 = { /// let mut item = SomeStruct::new(); /// item.a = 2; /// item.c = "new".into(); /// item /// }; /// /// // The same thing using struct update syntax (does not work for /// // non-exhaustive structs defined in external crates). /// let instance3 = SomeStruct { /// a: 2, /// c: "new".into(), /// ..SomeStruct::new() /// }; /// /// assert_eq!(instance1, instance2); /// assert_eq!(instance1, instance3); /// ``` /// /// # Slightly more realistic example /// /// ``` /// # struct Arg {} /// # impl Arg { fn new(_opt: ArgOptions) -> Self { Self {} } } /// // in awesome_cli_lib /// #[non_exhaustive] /// # #[derive(Default)] /// struct ArgOptions { /// pub name: String, /// pub short: Option, /// pub long: Option, /// pub help: Option, /// pub required: bool, /// pub takes_value: bool, /// pub multiple: bool, /// pub default_value: Option, /// } /// /// impl ArgOptions { /// pub fn new(name: String) -> Self { /// // ... /// # Self { name, ..Default::default() } /// } /// } /// /// // your crate /// use assign::assign; /// /// let arg = Arg::new(assign!(ArgOptions::new("version".into()), { /// short: Some("V".into()), /// long: Some("version".into()), /// help: Some("prints the version and quits.".into()), /// })); /// ``` #[macro_export] macro_rules! assign { ($initial_value:expr, { $( $field:ident $( : $value:expr )? ),+ $(,)? }) => ({ let mut item = $initial_value; $( $crate::assign!(@assign item $field $( : $value )?); )+ item }); (@assign $item:ident $field:ident : $value:expr) => { $item.$field = $value; }; (@assign $item:ident $field:ident) => { $item.$field = $field; }; } #[cfg(test)] mod tests { #[derive(Debug, Default, PartialEq)] struct SomeStruct { a: u32, b: Option, c: Option, } #[test] fn basic() { let res = assign!(SomeStruct::default(), { a: 5, b: None, }); assert_eq!( res, SomeStruct { a: 5, b: None, c: None } ); } #[test] fn shorthand() { let def = SomeStruct::default(); let a = 5; let res = assign!(def, { a }); assert_eq!( res, SomeStruct { a: 5, b: None, c: None } ); } #[test] fn field_expr_inference() { let b = 0.0.into(); let res = assign!(SomeStruct::default(), { b, c: 1.into(), }); assert_eq!( res, SomeStruct { a: 0, b: Some(0.0), c: Some(1) } ); } #[test] fn all_fields() { let a = 1; let b = Some(1.0); let res = assign!(SomeStruct::default(), { a, b, c: 1.into(), }); assert_eq!( res, SomeStruct { a: 1, b: Some(1.0), c: Some(1), } ); } }