diff --git a/.github/workflows/cargo-clippy.yml b/.github/workflows/cargo-clippy.yml index fc73199..8d6a574 100644 --- a/.github/workflows/cargo-clippy.yml +++ b/.github/workflows/cargo-clippy.yml @@ -6,46 +6,43 @@ concurrency: on: pull_request: - branches: [main, master] - types: [opened, reopened, ready_for_review] - paths: - - ".github/workflows/cargo-clippy.yml" - - "**.rs" - - "Cargo.toml" - - "Cargo.lock" + types: [auto_merge_enabled, opened, ready_for_review, reopened] push: branches: [main, master] tags: [latest, v*.*.*, "*-nightly"] - release: - types: [created, edited] repository_dispatch: - types: [clippy] + types: [clippy, cargo-clippy] workflow_dispatch: +permissions: + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + contents: read + security-events: write + statuses: write + jobs: clippy: runs-on: ubuntu-latest - permissions: - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - contents: read - security-events: write - statuses: write steps: - - name: Checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + repository: ${{ github.repository }} + ref: ${{ github.event.client_payload.ref || github.ref }} + token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 with: cache-key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - components: clippy, rustfmt - toolchain: nightly - - name: Setup the for sarif output - run: cargo install clippy-sarif sarif-fmt + components: clippy,rustfmt + - uses: taiki-e/install-action@v2 + with: + tool: clippy-sarif sarif-fmt - name: Run Clippy - run: cargo clippy - --all-features - --message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt - continue-on-error: true + run: | + cargo clippy \ + --features full \ + --message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt - name: Upload analysis uses: github/codeql-action/upload-sarif@v4 with: diff --git a/.github/workflows/cargo-publish.yml b/.github/workflows/cargo-publish.yml index fbc9b1c..d3f5465 100644 --- a/.github/workflows/cargo-publish.yml +++ b/.github/workflows/cargo-publish.yml @@ -30,8 +30,6 @@ jobs: package: - rspace-traits - rspace-core - - rspace-derive - - rspace-macros - rspace steps: - name: Checkout diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 1e33b04..5d46dbe 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -11,10 +11,6 @@ on: push: branches: [main, master] tags: [latest, v*.*.*, "*-nightly"] - paths: - - "**.nix" - - "flake.nix" - - "nix/**" repository_dispatch: types: [nix, nix-build] workflow_dispatch: @@ -28,10 +24,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 + repository: ${{ github.repository }} + ref: ${{ github.ref }} + token: ${{ github.token }} - name: Setup Nix uses: cachix/install-nix-action@v31 with: - github_access_token: ${{ secrets.GITHUB_TOKEN }} + github_access_token: ${{ github.token}} - name: Build run: nix build - name: Check the flake diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4a1d935..9aa7efc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -7,7 +7,7 @@ concurrency: on: pull_request: branches: [main, master] - types: [opened, synchronize, reopened] + types: [synchronize] paths: - ".github/workflows/rust.yml" - "Cargo.toml" @@ -22,11 +22,15 @@ on: types: [created] workflow_dispatch: inputs: - nightly: - default: false - description: "Run `nightly` tests?" + toolchain: + default: stable + description: "Choose which toolchain to test (stable, nightly, all)" required: true - type: boolean + type: choice + options: + - stable + - nightly + - all env: CARGO_TERM_COLOR: always @@ -41,8 +45,12 @@ jobs: target: [x86_64-unknown-linux-gnu] toolchain: [stable] steps: - - name: Checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + repository: ${{ github.repository }} + ref: ${{ github.ref }} + token: ${{ github.token }} - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 with: @@ -53,6 +61,7 @@ jobs: - name: Build the workspace run: cargo build -r --locked --workspace --features full --target ${{ matrix.target }} test: + if: (github.event_name == 'workflow_dispatch' && github.event.inputs.toolchain != 'nightly') || true needs: build runs-on: ubuntu-latest strategy: @@ -60,17 +69,18 @@ jobs: matrix: features: [full, default] target: [x86_64-unknown-linux-gnu] - toolchain: [stable] steps: - - name: Checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + repository: ${{ github.repository }} + ref: ${{ github.ref }} + token: ${{ github.token }} - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 with: cache-key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} target: ${{ matrix.target }} - toolchain: ${{ matrix.toolchain }} - override: true - name: Test (default) if: matrix.features == 'default' run: cargo test -r --locked --workspace --target ${{ matrix.target}} @@ -78,7 +88,7 @@ jobs: if: matrix.features != 'default' run: cargo test -r --locked --workspace --target ${{ matrix.target}} --features ${{ matrix.features }} test_nightly: - if: github.event.inputs.nightly || false + if: (github.event_name == 'workflow_dispatch' && github.event.inputs.toolchain != 'stable') || true continue-on-error: true needs: build runs-on: ubuntu-latest @@ -89,8 +99,15 @@ jobs: - all - no_std - "alloc,nightly" + package: + - rspace-traits steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 + repository: ${{ github.repository }} + ref: ${{ github.ref }} + token: ${{ github.token }} - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 with: @@ -99,16 +116,16 @@ jobs: override: true - name: Test (all-features) if: matrix.features == 'all' - run: cargo test -r --locked --workspace --all-features + run: cargo test -r --locked --all-features --package ${{ matrix.package }} - name: Test (no_std) continue-on-error: true if: matrix.features == 'no_std' - run: cargo test -r --locked --workspace --no-default-features --features nightly + run: cargo test -r --locked --no-default-features --package ${{ matrix.package }} env: RUSTFLAGS: "-C panic=abort -Z panic_abort_tests" - name: Test (${{ matrix.features }}) continue-on-error: true if: matrix.features != 'all' && matrix.features != 'no_std' - run: cargo test -r --locked --workspace --no-default-features --features ${{ matrix.features }} + run: cargo test -r --locked --no-default-features --features ${{ matrix.features }} --package ${{ matrix.package }} env: RUSTFLAGS: "-C panic=abort -Z panic_abort_tests" diff --git a/Cargo.lock b/Cargo.lock index b3fa316..d9fe139 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -713,19 +713,18 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rspace" -version = "0.0.6" +version = "0.0.7" dependencies = [ "criterion", "rspace-core", - "rspace-derive", - "rspace-macros", + "rspace-traits", "tracing", "tracing-subscriber", ] [[package]] name = "rspace-core" -version = "0.0.6" +version = "0.0.7" dependencies = [ "getrandom", "hashbrown 0.16.1", @@ -741,27 +740,9 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "rspace-derive" -version = "0.0.6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "rspace-macros" -version = "0.0.6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "rspace-traits" -version = "0.0.6" +version = "0.0.7" dependencies = [ "hashbrown 0.16.1", "num-complex", @@ -893,9 +874,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.111" +version = "2.0.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4" dependencies = [ "proc-macro2", "quote", @@ -1247,6 +1228,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d" +checksum = "de9211a9f64b825911bdf0240f58b7a8dac217fe260fc61f080a07f61372fbd5" diff --git a/Cargo.toml b/Cargo.toml index 8ec9e39..19e725b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,6 @@ default-members = ["rspace"] members = [ "rspace", "core", - "derive", - "macros", "traits", ] resolver = "3" @@ -22,20 +20,14 @@ license = "Apache-2.0" readme = "README.md" repository = "https://github.com/FL03/rspace.git" rust-version = "1.85.0" -version = "0.0.6" +version = "0.0.7" [workspace.dependencies] -rspace = { default-features = false, path = "rspace", version = "0.0.6" } -rspace-core = { default-features = false, path = "core", version = "0.0.6" } -rspace-traits = { default-features = false, path = "traits", version = "0.0.6" } - -rspace-derive = { default-features = false, path = "derive", version = "0.0.6" } -rspace-macros = { default-features = false, path = "macros", version = "0.0.6" } +rspace = { default-features = false, path = "rspace", version = "0.0.7" } +rspace-core = { default-features = false, path = "core", version = "0.0.7" } +rspace-traits = { default-features = false, path = "traits", version = "0.0.7" } # development & benchmarking criterion = { version = "0.8" } -# concurrency & parallelism -rayon = { default-features = false, version = "1" } -rayon-core = { default-features = false, version = "1" } # data structures hashbrown = { default-features = false, version = "0.16" } # error handling @@ -50,7 +42,6 @@ num-traits = { default-features = false, version = "0.2" } # random getrandom = { default-features = false, version = "0.3" } rand = { default-features = false, version = "0.9" } -rand_core = { default-features = false, version = "0.9" } rand_distr = { default-features = false, version = "0.5" } # serialization serde = { default-features = false, features = ["derive"], version = "1" } @@ -72,7 +63,7 @@ opt-level = 2 overflow-checks = true panic = "abort" rpath = false -strip = "symbols" +strip = false [profile.release] codegen-units = 16 diff --git a/clippy.toml b/Clippy.toml similarity index 100% rename from clippy.toml rename to Clippy.toml diff --git a/SECURITY.md b/SECURITY.md index ff38363..576daf6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,8 +8,8 @@ Checkout the current and supported packages below | Version | Supported | |:-----------------|:--------------------| -| 0.0.6 (latest) | :white_check_mark: | -| >0.0.1,<=0.0.5 | :white_check_mark: | +| 0.0.7 (latest) | :white_check_mark: | +| >0.0.1,<=0.0.6 | :white_check_mark: | | 0.0.0 | :x: | ## Reporting a Vulnerability diff --git a/core/Cargo.toml b/core/Cargo.toml index 507d23d..4326b64 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -26,7 +26,7 @@ tag-name = "{{version}}" [lib] bench = false -crate-type = ["cdylib", "rlib"] +crate-type = ["lib"] doctest = true test = true diff --git a/core/src/lib.rs b/core/src/lib.rs index 5958fd5..28c6d98 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -19,8 +19,6 @@ compile_error! { // external crates #[cfg(feature = "alloc")] extern crate alloc; -#[doc(inline)] -pub use rspace_traits as traits; // macros #[macro_use] pub(crate) mod macros { @@ -35,11 +33,9 @@ pub mod point; pub use self::{ error::{Error, Result}, point::*, - traits::prelude::*, }; // prelude #[doc(hidden)] pub mod prelude { pub use crate::point::*; - pub use rspace_traits::prelude::*; } diff --git a/core/src/point.rs b/core/src/point.rs index 416ca59..9c629a4 100644 --- a/core/src/point.rs +++ b/core/src/point.rs @@ -6,6 +6,15 @@ mod impl_point; mod impl_point_ext; mod impl_point_repr; +/// An instance of the [`Point`] implementation containing owned references to the inner values. +pub type PointView<'a, X, Y = X> = Point<&'a X, &'a Y>; +/// An instance of the [`Point`] implementation containing mutable references to the inner +/// values. +pub type PointViewMut<'a, X, Y = X> = Point<&'a mut X, &'a mut Y>; +/// A [`Point`] whose elements are raw pointers to `X` and `Y` +pub type RawPoint = Point<*const X, *const Y>; +/// A mutable [`Point`] whose elements are raw pointers to `X` and `Y` +pub type RawPointMut = Point<*mut X, *mut Y>; /// The [`Point`] implementation is designed a generic, 2-dimensional point object used to /// define coordinates, vectors, or positions in a 2D space. diff --git a/default.nix b/default.nix index 2d06ae8..b7dacd0 100644 --- a/default.nix +++ b/default.nix @@ -26,7 +26,7 @@ let }; common = { - version = "0.0.6"; + version = "0.0.7"; src = self; cargoLock = { diff --git a/derive/Cargo.toml b/derive/Cargo.toml deleted file mode 100644 index 26e82a8..0000000 --- a/derive/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -build = "build.rs" -description = "useful derive macros for the rspace ecosystem" -name = "rspace-derive" - -authors.workspace = true -categories.workspace = true -edition.workspace = true -homepage.workspace = true -keywords.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true -rust-version.workspace = true -version.workspace = true - -[package.metadata.docs.rs] -all-features = false -features = ["default"] -rustc-args = ["--cfg", "docsrs"] -version = "v{{version}}" - -[package.metadata.release] -no-dev-version = true -tag-name = "{{version}}" - -[lib] -bench = false -doc = true -doctest = true -proc-macro = true -test = true - -[dependencies] -proc-macro2 = { version = "1" } -quote = { version = "1" } -syn = { features = ["full"], version = "2" } - -[features] -default = [] - -nightly = ["proc-macro2/nightly"] - diff --git a/derive/build.rs b/derive/build.rs deleted file mode 100644 index 940a4ce..0000000 --- a/derive/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -/* - Appellation: build - Contrib: FL03 -*/ - -fn main() { - println!("cargo::rustc-check-cfg=cfg(no_std)"); -} diff --git a/derive/src/attrs/display_attrs.rs b/derive/src/attrs/display_attrs.rs deleted file mode 100644 index 82486f4..0000000 --- a/derive/src/attrs/display_attrs.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* - Appellation: display_attrs - Contrib: @FL03 -*/ -use syn::meta::ParseNestedMeta; -use syn::parse::{Parse, ParseBuffer, ParseStream}; -use syn::{Ident, parenthesized}; - -#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct DisplayAttr { - pub format: Option, -} - -impl DisplayAttr { - /// attempts to parse the attribute from the given metadata - pub fn parse_nested(meta: &ParseNestedMeta<'_>) -> syn::Result { - let content; - parenthesized!(content in meta.input); - // try finding the optional name parameter - let format = content.parse::(); - // create a new instance of ParamsAttr - let parsed = DisplayAttr { - format: format.ok(), - }; - // return the parsed instance - Ok(parsed) - } -} diff --git a/derive/src/attrs/nested.rs b/derive/src/attrs/nested.rs deleted file mode 100644 index 58d997c..0000000 --- a/derive/src/attrs/nested.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* - Appellation: nested - Contrib: @FL03 -*/ -use super::DisplayAttr; -use syn::Ident; -use syn::parse::{Parse, ParseStream}; - -/// [`NestedAttr`] is an enumeration of various nested attributes the crate recognizes. -#[derive(Debug)] -pub enum NestedAttr { - Inner(DisplayAttr), -} - -impl NestedAttr { - /// attempts to parse the attribute from the given metadata - pub fn parse_nested(meta: &syn::meta::ParseNestedMeta<'_>) -> syn::Result { - // #[wrap(inner(...))] - if meta.path.is_ident("inner") { - let attr = DisplayAttr::parse_nested(meta)?; - return Ok(Self::Inner(attr)); - } - - Err(meta.error("unrecognized repr")) - } -} - -impl Parse for NestedAttr { - fn parse(input: ParseStream) -> syn::Result { - let ident: Ident = input.parse()?; - if ident == "inner" { - let content; - syn::parenthesized!(content in input); - // Parse an optional identifier - let format = if content.is_empty() { - None - } else { - Some(content.parse::()?) - }; - - Ok(NestedAttr::Inner(DisplayAttr { format })) - } else { - Err(syn::Error::new_spanned(ident, "unknown attribute")) - } - } -} diff --git a/derive/src/attrs/root.rs b/derive/src/attrs/root.rs deleted file mode 100644 index 2fc7083..0000000 --- a/derive/src/attrs/root.rs +++ /dev/null @@ -1,41 +0,0 @@ -/* - appellation: root - authors: @FL03 -*/ -use crate::attrs::{DisplayAttr, NestedAttr}; -use syn::Attribute; - -// AST for the root attribute -#[derive(Debug, Default)] -pub struct RootAttr { - pub inner: Option, -} - -impl RootAttr { - const BASEPATH: &'static str = "wrap"; - - pub fn set_inner(&mut self, attr: DisplayAttr) { - self.inner = Some(attr); - } - - // tries to extract the root attribute from a list of attributes - pub fn extract(attrs: &[Attribute]) -> syn::Result { - let mut root = Self::default(); - for attr in attrs { - if attr.path().is_ident(Self::BASEPATH) { - attr.parse_nested_meta(|meta| { - if let Ok(nested) = NestedAttr::parse_nested(&meta) { - match nested { - NestedAttr::Inner(inner) => { - root.set_inner(inner); - return Ok(()); - } - } - } - Err(meta.error("unrecognized attribute")) - })?; - } - } - Ok(root) - } -} diff --git a/derive/src/impls/wrapper.rs b/derive/src/impls/wrapper.rs deleted file mode 100644 index e36c51c..0000000 --- a/derive/src/impls/wrapper.rs +++ /dev/null @@ -1,188 +0,0 @@ -/* - appellation: wrapper - authors: @FL03 -*/ -use quote::quote; -use syn::{Data, DataStruct, DeriveInput, Field, Generics, Ident}; - -pub fn impl_wrapper(input: &DeriveInput) -> proc_macro2::TokenStream { - // deconstruct the input to get the struct name and generics - let DeriveInput { - data, - generics, - ident: name, - .. // ignore other fields - } = input; - // split the generics for implementation - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - // handle the case where the data is a struct - if let Data::Struct(DataStruct { fields, .. }) = data { - // ensure the struct is a single field struct - if fields.len() != 1 { - panic!("The `Wrapper` macro can only be derived for single field structs"); - } - // handle the fields - let methods = fields - .iter() - .map(|field| _handle_field(field, generics, name)); - // inject generics to ensure the wrapper can be used with generic types - return quote! { - impl #impl_generics #name #ty_generics #where_clause { - #(#methods)* - } - }; - } - - panic!("The `Wrapper` macro can only be derived for single field structs"); -} - -fn _handle_field( - field: &Field, - generics: &Generics, - name: &syn::Ident, -) -> proc_macro2::TokenStream { - // deconstruct the field for easier access - let Field { - ident: field_name, - ty: field_type, - .. - } = field; - // handle both named and unnamed fields - let methods = match field_name { - Some(_) => _handle_named(field, generics, name), - None => _handle_unnamed(field, generics, name), - }; - // generate the code for the wrapper methods - quote! { - #methods - /// consumes the current instance and returns a new one that captures the result of the - /// closure on the wrapped field - #[inline] - pub fn map(self, f: F) -> #name - where - F: FnOnce(#field_type) -> U, - { - #name::new(f(self.value())) - } - /// [`replace`](core::mem::replace) the wrapped field with a new value and return - /// the old value - pub const fn replace(&mut self, value: #field_type) -> #field_type { - ::core::mem::replace(self.get_mut(), value) - } - /// set the wrapped field to a new value and return a mutable reference to the - /// current instance - #[inline] - pub fn set(&mut self, value: #field_type) -> &mut Self { - *self.get_mut() = value; - self - } - /// [`swap`](core::mem::swap) the wrapped field with another instance - pub const fn swap(&mut self, other: &mut Self) { - ::core::mem::swap(self.get_mut(), other.get_mut()); - } - /// [`take`](core::mem::take) the wrapped field and replace it with a default value - #[inline] - pub fn take(&mut self) -> #field_type - where - #field_type: Default - { - ::core::mem::take(self.get_mut()) - } - /// returns a new instance of the wrapper that contains a reference to the inner value - pub const fn view(&self) -> #name<&#field_type> { - #name::new(self.get()) - } - /// returns a new instance of the wrapper that contains a mutable reference to the - /// inner value - pub const fn view_mut(&mut self) -> #name<&mut #field_type> { - #name::new(self.get_mut()) - } - } -} - -fn _handle_named( - field: &Field, - generics: &Generics, - _name: &syn::Ident, -) -> proc_macro2::TokenStream { - let Field { - ident, - ty: field_type, - .. - } = field; - - let _where_clause_u = generics.where_clause.as_ref(); - if ident.is_none() { - panic!("The `Wrapper` macro can only be derived for single field structs"); - } - // get a reference to the field name - let field_name = ident.as_ref().unwrap(); - // implement the methods for named fields - quote! { - pub const fn new(#field_name: #field_type) -> Self { - Self { #field_name } - } - /// returns a reference to the wrapped field - pub const fn get(&self) -> &#field_type { - &self.#field_name - } - /// returns a mutable reference to the wrapped field - pub const fn get_mut(&mut self) -> &mut #field_type { - &mut self.#field_name - } - /// consumes the current instance and returns the wrapped field - #[inline] - pub fn value(self) -> #field_type { - self.#field_name - } - } -} - -fn _handle_unnamed( - field: &Field, - _generics: &Generics, - _name: &syn::Ident, -) -> proc_macro2::TokenStream { - let field_type = &field.ty; - quote! { - pub const fn new(value: #field_type) -> Self { - Self(value) - } - /// returns a reference to the wrapped field - pub const fn get(&self) -> &#field_type { - &self.0 - } - /// returns a mutable reference to the wrapped field - pub const fn get_mut(&mut self) -> &mut #field_type { - &mut self.0 - } - /// consumes the current instance and returns the wrapped field - #[inline] - pub fn value(self) -> #field_type { - self.0 - } - } -} - -fn _convert_generic_where_clause( - new_ident: &Ident, - clause: &syn::WhereClause, -) -> proc_macro2::TokenStream { - let predicates = clause.predicates.iter().map(|p| { - if let syn::WherePredicate::Type(inner) = p { - let mut pred = inner.clone(); - pred.bounded_ty = if let syn::Type::Verbatim(_ty) = &inner.bounded_ty { - syn::Type::Verbatim(quote!(#new_ident)) - } else { - inner.bounded_ty.clone() - }; - // For other types of predicates, we can just return them as is - return quote!(#pred); - } - // For other types of predicates, we can just return them as is - quote!(#p) - }); - quote! { - where #(#predicates),* - } -} diff --git a/derive/src/lib.rs b/derive/src/lib.rs deleted file mode 100644 index 6c2752c..0000000 --- a/derive/src/lib.rs +++ /dev/null @@ -1,40 +0,0 @@ -/* - Appellation: rspace-derive - Contrib: FL03 -*/ -//! derive macros for facilitating the creation of containers, fields, and spaces. - -extern crate proc_macro; -extern crate quote; -extern crate syn; - -#[allow(unused)] -pub(crate) mod attrs { - pub use self::{display_attrs::*, nested::*, root::*}; - - mod display_attrs; - mod nested; - mod root; -} - -pub(crate) mod impls { - #[doc(inline)] - pub use self::wrapper::*; - - mod wrapper; -} -use proc_macro::TokenStream; -use syn::{DeriveInput, parse_macro_input}; - -/// The [`Spatial`] macro is designed for single-field structs, implementing additional methods -/// supporting interactions with the inner value -#[proc_macro_derive(Spatial, attributes(wrap))] -pub fn spatial(input: TokenStream) -> TokenStream { - // Parse the inputs into the proper struct - let ast = parse_macro_input!(input as DeriveInput); - - // Build the impl - let res = impls::impl_wrapper(&ast); - - res.into() -} diff --git a/derive/tests/default.rs b/derive/tests/default.rs deleted file mode 100644 index 90ecaa5..0000000 --- a/derive/tests/default.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - appellation: default - authors: @FL03 -*/ - -fn adder(a: A, b: B) -> C -where - A: core::ops::Add, -{ - a + b -} - -#[test] -fn compiles() { - assert_eq!(adder(1, 100), 101); - assert_eq!(adder(1.0, 100.0), 101.0); -} diff --git a/derive/tests/wrapper.rs b/derive/tests/wrapper.rs deleted file mode 100644 index 59c36a1..0000000 --- a/derive/tests/wrapper.rs +++ /dev/null @@ -1,25 +0,0 @@ -use rspace_derive::Spatial; - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Spatial)] -pub struct A(T); - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Spatial)] -pub struct B { - pub value: T, -} - -#[test] -fn test_derive_tuple_spatial() { - let mut a: A = A::new(1).map(|x| x + 100); - assert_eq!(a.get_mut(), &mut 101); - a.set(::MAX); - assert_eq!(a.get(), &::MAX); -} - -#[test] -fn test_derive_struct_spatial() { - let mut b: B = B::new(1).map(|x| x + 100); - assert_eq!(b.get_mut(), &mut 101); - b.set(::MAX); - assert_eq!(b.get(), &::MAX); -} diff --git a/flake.nix b/flake.nix index f4ffd3d..07a096e 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ in rec { packages.default = pkgs.rustPlatform.buildRustPackage { pname = "rspace"; - version = "0.0.6"; + version = "0.0.7"; src = self; # ./.; cargoLock = { lockFile = ./Cargo.lock; diff --git a/macros/Cargo.toml b/macros/Cargo.toml deleted file mode 100644 index 49c6c30..0000000 --- a/macros/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -build = "build.rs" -description = "procedural macros for containers and spaces" -name = "rspace-macros" - -authors.workspace = true -categories.workspace = true -edition.workspace = true -homepage.workspace = true -keywords.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true -rust-version.workspace = true -version.workspace = true - -[package.metadata.docs.rs] -all-features = false -features = ["default"] -rustc-args = [ "--cfg", "docsrs" ] -version = "v{{version}}" - -[package.metadata.release] -no-dev-version = true -tag-name = "{{version}}" - -[lib] -bench = false -doc = true -doctest = true -proc-macro = true -test = true - -[dependencies] -# procedural macros -proc-macro2 = { version = "1" } -quote = { version = "1" } -syn = { features = ["full"], version = "2" } - -[features] -default = [] - -nightly = ["proc-macro2/nightly"] diff --git a/macros/build.rs b/macros/build.rs deleted file mode 100644 index 940a4ce..0000000 --- a/macros/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -/* - Appellation: build - Contrib: FL03 -*/ - -fn main() { - println!("cargo::rustc-check-cfg=cfg(no_std)"); -} diff --git a/macros/src/ast.rs b/macros/src/ast.rs deleted file mode 100644 index 2dd2281..0000000 --- a/macros/src/ast.rs +++ /dev/null @@ -1,20 +0,0 @@ -/* - Appellation: ast - Created At: 2025.12.18:07:44:04 - Contrib: @FL03 -*/ -mod impl_ast_wrapper_ops; - -use syn::token::Impl; -use syn::{AngleBracketedGenericArguments, Ident, WhereClause}; - -/// The abstract syntax tree for the `binary_wrapper` macro input; -/// e.g. `impl A { Add.add, Sub.sub }` or `impl B.field { Add.add, Sub.sub }` -pub struct WrapperOpsAst { - pub _impl: Impl, - pub _generics: Option, - pub target: Ident, - pub field: Option, - pub _where: Option, - pub ops: Vec<(Ident, Ident)>, -} diff --git a/macros/src/ast/impl_ast_wrapper_ops.rs b/macros/src/ast/impl_ast_wrapper_ops.rs deleted file mode 100644 index 22bb0cd..0000000 --- a/macros/src/ast/impl_ast_wrapper_ops.rs +++ /dev/null @@ -1,57 +0,0 @@ -/* - appellation: ops - authors: @FL03 -*/ -use crate::ast::WrapperOpsAst; - -use syn::parse::{Parse, ParseStream}; -use syn::token::Impl; -use syn::{Ident, Token, braced}; - -impl Parse for WrapperOpsAst { - fn parse(input: ParseStream) -> syn::Result { - // parse the `impl` keyword - let _impl = input.parse::()?; - // detect any generic parameters - let generics = if input.peek(Token![<]) { - input.parse().ok() - } else { - None - }; - let target = input.parse::()?; - // resolve the optional named field - let field = if input.peek(Token![.]) { - input.parse::()?; - Some(input.parse()?) - } else { - None - }; - // parse the optional where clause - let where_clause = if input.peek(Token![where]) { - Some(input.parse()?) - } else { - None - }; - // parse the operations defined within braces - let content; - braced!(content in input); - let mut ops = Vec::new(); - while !content.is_empty() { - let op: Ident = content.parse()?; - content.parse::()?; - let call: Ident = content.parse()?; - if content.peek(Token![,]) { - content.parse::()?; - } - ops.push((op, call)); - } - Ok(Self { - _impl, - _generics: generics, - target, - field, - _where: where_clause, - ops, - }) - } -} diff --git a/macros/src/impls.rs b/macros/src/impls.rs deleted file mode 100644 index 3b97f87..0000000 --- a/macros/src/impls.rs +++ /dev/null @@ -1,8 +0,0 @@ -/* - Appellation: impls - Created At: 2025.12.26:18:20:37 - Contrib: @FL03 -*/ -pub use self::binary::impl_wrapper_binary_ops; - -pub mod binary; diff --git a/macros/src/impls/binary.rs b/macros/src/impls/binary.rs deleted file mode 100644 index 4362540..0000000 --- a/macros/src/impls/binary.rs +++ /dev/null @@ -1,247 +0,0 @@ -/* - appellation: impl_binary - authors: @FL03 -*/ -use crate::ast::WrapperOpsAst; -use proc_macro2::TokenStream; -use quote::{format_ident, quote}; -use syn::Ident; - -/// Procedural macro entry point -pub fn impl_wrapper_binary_ops(input: WrapperOpsAst) -> TokenStream { - let base = impl_core_binary_ops(&input); - let assign = impl_assign_ops(&input); - - quote! { - #(#base)* - - #(#assign)* - } -} - -fn impl_core_binary_ops( - WrapperOpsAst { - target, field, ops, .. - }: &WrapperOpsAst, -) -> Vec { - let mut impls = Vec::new(); - for (op, call) in ops { - let _impl = if let Some(f) = field { - impl_named(op, target, call, f) - } else { - impl_unnamed(op, target, call) - }; - impls.push(_impl); - } - impls -} - -fn impl_assign_ops(options: &WrapperOpsAst) -> Vec { - let WrapperOpsAst { - target, field, ops, .. - } = options; - - let mut impls = Vec::new(); - for (op, call) in ops { - let op_assign = format_ident!("{}Assign", op); - let call_assign = format_ident!("{}_assign", call); - - let _impl = if let Some(f) = field { - quote! { - impl<_A, _B> ::core::ops::#op_assign<#target<_B>> for #target<_A> - where - _A: ::core::ops::#op_assign<_B>, - { - fn #call_assign(&mut self, rhs: #target<_B>) { - ::core::ops::#op_assign::#call_assign(&mut self.#f, rhs.#f) - } - } - } - } else { - quote! { - impl<_A, _B> ::core::ops::#op_assign<#target<_B>> for #target<_A> - where - _A: ::core::ops::#op_assign<_B>, - { - fn #call_assign(&mut self, rhs: #target<_B>) { - ::core::ops::#op_assign::#call_assign(&mut self.0, rhs.0) - } - } - } - }; - // register the implementation - impls.push(_impl); - } - impls -} - -fn impl_unnamed(op: &Ident, target: &Ident, call: &Ident) -> TokenStream { - quote! { - impl<_A, _B, _C> ::core::ops::#op<#target<_B>> for #target<_A> - where - _A: ::core::ops::#op<_B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: #target<_B>) -> Self::Output { - #target(::core::ops::#op::#call(self.0, rhs.0)) - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a #target<_B>> for #target<_A> - where - _A: ::core::ops::#op<&'a _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a #target<_B>) -> Self::Output { - #target(::core::ops::#op::#call(self.0, &rhs.0)) - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a #target<_B>> for &'a #target<_A> - where - &'a _A: ::core::ops::#op<&'a _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a #target<_B>) -> Self::Output { - #target(::core::ops::#op::#call(&self.0, &rhs.0)) - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<#target<_B>> for &'a #target<_A> - where - &'a _A: ::core::ops::#op<_B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: #target<_B>) -> Self::Output { - #target(::core::ops::#op::#call(&self.0, rhs.0)) - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a mut #target<_B>> for #target<_A> - where - _A: ::core::ops::#op<&'a mut _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a mut #target<_B>) -> Self::Output { - #target(::core::ops::#op::#call(self.0, &mut rhs.0)) - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a mut #target<_B>> for &'a mut #target<_A> - where - &'a mut _A: ::core::ops::#op<&'a mut _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a mut #target<_B>) -> Self::Output { - #target(::core::ops::#op::#call(&mut self.0, &mut rhs.0)) - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<#target<_B>> for &'a mut #target<_A> - where - &'a mut _A: ::core::ops::#op<_B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: #target<_B>) -> Self::Output { - #target(::core::ops::#op::#call(&mut self.0, rhs.0)) - } - } - } -} - -fn impl_named(op: &Ident, target: &Ident, call: &Ident, field: &Ident) -> TokenStream { - quote! { - impl<_A, _B, _C> ::core::ops::#op<#target<_B>> for #target<_A> - where - _A: ::core::ops::#op<_B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: #target<_B>) -> Self::Output { - let #field = ::core::ops::#op::#call(self.#field, rhs.#field); - #target { #field } - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a #target<_B>> for #target<_A> - where - _A: ::core::ops::#op<&'a _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a #target<_B>) -> Self::Output { - let #field = ::core::ops::#op::#call(self.#field, &rhs.#field); - #target { #field } - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a #target<_B>> for &'a #target<_A> - where - &'a _A: ::core::ops::#op<&'a _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a #target<_B>) -> Self::Output { - let #field = ::core::ops::#op::#call(&self.#field, &rhs.#field); - #target { #field } - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<#target<_B>> for &'a #target<_A> - where - &'a _A: ::core::ops::#op<_B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: #target<_B>) -> Self::Output { - let #field = ::core::ops::#op::#call(&self.#field, rhs.#field); - #target { #field } - } - } - - - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a mut #target<_B>> for #target<_A> - where - _A: ::core::ops::#op<&'a mut _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a mut #target<_B>) -> Self::Output { - let #field = ::core::ops::#op::#call(self.#field, &mut rhs.#field); - #target { #field } - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<&'a mut #target<_B>> for &'a mut #target<_A> - where - &'a mut _A: ::core::ops::#op<&'a mut _B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: &'a mut #target<_B>) -> Self::Output { - let #field = ::core::ops::#op::#call(&mut self.#field, &mut rhs.#field); - #target { #field } - } - } - - impl<'a, _A, _B, _C> ::core::ops::#op<#target<_B>> for &'a mut #target<_A> - where - &'a mut _A: ::core::ops::#op<_B, Output = _C>, - { - type Output = #target<_C>; - - fn #call(self, rhs: #target<_B>) -> Self::Output { - let #field = ::core::ops::#op::#call(&mut self.#field, rhs.#field); - #target { #field } - } - } - } -} diff --git a/macros/src/lib.rs b/macros/src/lib.rs deleted file mode 100644 index b38f57e..0000000 --- a/macros/src/lib.rs +++ /dev/null @@ -1,58 +0,0 @@ -/* - Appellation: rspace-macros - Contributors: FL03 -*/ -//! procedural macros for interacting with various wrappers -extern crate proc_macro; - -mod ast; -mod impls; - -use crate::ast::WrapperOpsAst; -use proc_macro::TokenStream; -use syn::parse_macro_input; - -/// The [`binary_wrapper!`] macro generates implementations for the core binary operations -/// onto a generic wrapper type. It supports both tuple structs and structs with named fields. -/// -/// ```rust -/// extern crate rspace_macros as macros; -/// -/// pub struct Wrapper(pub T); -/// -/// macros::binary_wrapper! { -/// impl Wrapper { -/// Add.add, -/// Sub.sub, -/// Mul.mul, -/// Div.div, -/// Rem.rem, -/// } -/// } -/// ``` -/// -/// or, for transparent structs with a named field: -/// -/// ```rust -/// extern crate rspace_macros as macros; -/// -/// pub struct Wrapper { -/// pub field: T, -/// } -/// -/// macros::binary_wrapper! { -/// impl Wrapper.field { -/// Add.add, -/// Sub.sub, -/// Mul.mul, -/// Div.div, -/// Rem.rem, -/// } -/// } -/// ``` -#[proc_macro] -pub fn binary_wrapper(input: TokenStream) -> TokenStream { - let ast = parse_macro_input!(input as WrapperOpsAst); - let output = impls::impl_wrapper_binary_ops(ast); - output.into() -} diff --git a/macros/tests/default.rs b/macros/tests/default.rs deleted file mode 100644 index 90ecaa5..0000000 --- a/macros/tests/default.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - appellation: default - authors: @FL03 -*/ - -fn adder(a: A, b: B) -> C -where - A: core::ops::Add, -{ - a + b -} - -#[test] -fn compiles() { - assert_eq!(adder(1, 100), 101); - assert_eq!(adder(1.0, 100.0), 101.0); -} diff --git a/rspace/Cargo.toml b/rspace/Cargo.toml index 8e52c70..c2ab9df 100644 --- a/rspace/Cargo.toml +++ b/rspace/Cargo.toml @@ -25,7 +25,6 @@ no-dev-version = true tag-name = "v{{version}}" [lib] -crate-type = ["cdylib", "rlib"] bench = true doc = true doctest = true @@ -33,8 +32,8 @@ path = "lib.rs" test = true [[bench]] -name = "default" harness = false +name = "default" [[example]] name = "space" @@ -42,8 +41,7 @@ required-features = ["default"] [dependencies] rspace-core = { workspace = true } -rspace-derive = { optional = true, workspace = true } -rspace-macros = { optional = true, workspace = true } +rspace-traits = { workspace = true } [dev-dependencies] criterion = { features = ["plotters"], workspace = true } @@ -56,7 +54,6 @@ default = ["std"] full = [ "default", "complex", - "derive", "hashbrown", "json", "rand", @@ -64,20 +61,12 @@ full = [ ] # ********* [FF] Features ********* -derive = [ - "dep:rspace-derive", - "macros", -] - macros = [ - "dep:rspace-macros", "rspace-core/macros", ] nightly = [ "rspace-core/nightly", - "rspace-derive?/nightly", - "rspace-macros?/nightly", ] json = [ @@ -90,39 +79,45 @@ json = [ std = [ "alloc", "rspace-core/std", + "rspace-traits/std", ] wasi = [ - "alloc", "rspace-core/wasi", + "rspace-traits/wasi", ] wasm = [ - "alloc", "wasm_bindgen", "rspace-core/wasm", + "rspace-traits/wasm", ] # ********* [FF] Dependencies ********* alloc = [ "rspace-core/alloc", + "rspace-traits/alloc", ] complex = [ "rspace-core/complex", + "rspace-traits/complex", ] hashbrown = [ "rspace-core/hashbrown", + "rspace-traits/hashbrown", ] rand = [ "rspace-core/rand", + "rspace-traits/rand", "rng", ] rayon = [ "rspace-core/rayon", + "rspace-traits/rayon", ] rng = [ @@ -131,6 +126,7 @@ rng = [ serde = [ "rspace-core/serde", + "rspace-traits/serde", ] serde_json = [ @@ -139,4 +135,5 @@ serde_json = [ wasm_bindgen = [ "rspace-core/wasm_bindgen", + "rspace-traits/wasm_bindgen", ] diff --git a/rspace/lib.rs b/rspace/lib.rs index dcfb587..be5b6b8 100644 --- a/rspace/lib.rs +++ b/rspace/lib.rs @@ -1,9 +1,10 @@ -/* - Appellation: rspace - Contrib: FL03 -*/ -//! `rspace` works to establish a solid foundation for handling and defining containers, space, -//! and fields within Rust. +#![crate_name = "rspace"] +#![crate_type = "lib"] +//! `rspace` is a fundmanetal crate looking to support containers via a set of well established +//! interfaces, traits, primitives, and other useful tools. The crate is working towards +//! becoming `no_std` compatible, seeking to support embedded and other resource constrained +//! environments. Additionally, the crate is extensively feature-gated to ensure it remains as +//! lightweight and modular as possible. #![allow( clippy::missing_errors_doc, clippy::missing_safety_doc, @@ -19,18 +20,17 @@ compile_error! { "either the \"std\" or \"alloc\" feature must be enabled" } // external crates #[cfg(any(feature = "alloc", feature = "std"))] extern crate alloc; +// declare external crates as modules +#[doc(inline)] +pub use rspace_traits as traits; // re-exports +#[doc(inline)] pub use rspace_core::*; -#[cfg(feature = "derive")] -pub use rspace_derive::*; -#[cfg(feature = "macros")] -pub use rspace_macros::*; +#[doc(inline)] +pub use rspace_traits::*; // prelude #[doc(hidden)] pub mod prelude { pub use rspace_core::prelude::*; - #[cfg(feature = "derive")] - pub use rspace_derive::*; - #[cfg(feature = "macros")] - pub use rspace_macros::*; + pub use rspace_traits::prelude::*; } diff --git a/traits/Cargo.toml b/traits/Cargo.toml index a99ad7e..d019ade 100644 --- a/traits/Cargo.toml +++ b/traits/Cargo.toml @@ -26,7 +26,7 @@ tag-name = "v{{version}}" [lib] bench = false -crate-type = ["cdylib", "rlib", "staticlib"] +crate-type = ["lib"] doc = true doctest = true test = true diff --git a/traits/src/container.rs b/traits/src/container.rs index 9c8979e..d600796 100644 --- a/traits/src/container.rs +++ b/traits/src/container.rs @@ -3,7 +3,7 @@ Created At: 2025.12.29:14:39:20 Contrib: @FL03 */ -use crate::{Apply, RawSpace}; +use crate::RawSpace; /// The [`Container`] trait is a higher-kinded trait used to establish an interface for /// defining containers themselves. @@ -14,26 +14,109 @@ where type Cont: ?Sized; } -pub trait ContainerMap: Container +pub trait ContainerIndex: Container where - Self::Cont: RawSpace, + Self::Cont: RawSpace + core::ops::Index, { - fn map(&self, f: F) -> Self::Cont - where - Self::Cont: Apply>, - Self::Cont: Sized; + type Output; + + fn get(&self, index: Idx) -> Option<&Self::Output>; } /// The [`ContainerIter`] trait extends the [`Container`] trait to provide an interface /// for obtaining iterators over the elements of the container. -pub trait ContainerIter: Container +pub trait ContainerIter: Container where - Self::Cont: RawSpace, + Self::Cont: RawSpace, +{ + type Iter<'a, U>: Iterator + where + Self: 'a, + U: 'a; + + fn iter(&self) -> Self::Iter<'_, T>; +} + +pub trait ContainerIterMut: Container +where + Self::Cont: RawSpace, { - type Iter<'a, T>: Iterator + type Iter<'a, U>: Iterator + where + Self: 'a, + U: 'a; + + fn iter_mut(&mut self) -> Self::Iter<'_, T>; +} + +impl ContainerIter for [T] { + type Iter<'a, U> + = core::slice::Iter<'a, U> + where + Self: 'a, + U: 'a; + + fn iter(&self) -> Self::Iter<'_, T> { + <[T]>::iter(self) + } +} + +impl ContainerIterMut for [T] { + type Iter<'a, U> + = core::slice::IterMut<'a, U> + where + Self: 'a, + U: 'a; + + fn iter_mut(&mut self) -> Self::Iter<'_, T> { + <[T]>::iter_mut(self) + } +} + +impl ContainerIter for [T; N] { + type Iter<'a, U> + = core::slice::Iter<'a, U> + where + Self: 'a, + U: 'a; + + fn iter(&self) -> Self::Iter<'_, T> { + <[T]>::iter(self) + } +} + +impl ContainerIterMut for [T; N] { + type Iter<'a, U> + = core::slice::IterMut<'a, U> + where + Self: 'a, + U: 'a; + + fn iter_mut(&mut self) -> Self::Iter<'_, T> { + <[T]>::iter_mut(self) + } +} + +impl ContainerIter for &[T] { + type Iter<'a, U> + = core::slice::Iter<'a, U> + where + Self: 'a, + U: 'a; + + fn iter(&self) -> Self::Iter<'_, T> { + <[T]>::iter(self) + } +} + +impl ContainerIterMut for &mut [T] { + type Iter<'a, U> + = core::slice::IterMut<'a, U> where Self: 'a, - T: 'a; + U: 'a; - fn iter(&self) -> Self::Iter<'_, U>; + fn iter_mut(&mut self) -> Self::Iter<'_, T> { + <[T]>::iter_mut(self) + } } diff --git a/traits/src/functor.rs b/traits/src/functor.rs index ee95964..2183460 100644 --- a/traits/src/functor.rs +++ b/traits/src/functor.rs @@ -21,17 +21,6 @@ where fn apply(self, f: F) -> Self::Cont; } -pub trait FunctorIter -where - F: FnOnce(Self::Elem) -> T, -{ - type Cont: ?Sized; - type Iter; - type Elem; - - fn apply_all(self, f: F) -> Self::Cont; -} - // pub trait Applicative: Functor { // fn pure(value: T) -> Self::Cont; // } @@ -69,21 +58,6 @@ where } } -impl FunctorIter for S -where - S: IntoIterator, - F: FnMut(X) -> Y, - I: Iterator, -{ - type Cont = core::iter::Map<::IntoIter, F>; - type Iter = I; - type Elem = X; - - fn apply_all(self, f: F) -> Self::Cont { - self.into_iter().map(f) - } -} - #[cfg(test)] mod tests { use super::*; @@ -95,7 +69,7 @@ mod tests { } assert_eq! { Some(42u8).apply(sample), - Some(43.25) + Some(43.25f32) } } } diff --git a/traits/src/impls/impl_apply.rs b/traits/src/impls/impl_apply.rs new file mode 100644 index 0000000..08715cf --- /dev/null +++ b/traits/src/impls/impl_apply.rs @@ -0,0 +1,112 @@ +/* + Appellation: impl_apply + Created At: 2026.01.01:21:39:28 + Contrib: @FL03 +*/ +use crate::ops::apply::{Apply, ApplyMut, ApplyOnce}; + +impl ApplyOnce for Option +where + F: FnOnce(U) -> V, +{ + type Output = Option; + + fn apply_once(self, rhs: F) -> Self::Output { + self.map(rhs) + } +} + +impl Apply for Option +where + F: Fn(&U) -> V, +{ + type Output = Option; + + fn apply(&self, rhs: F) -> Self::Output { + self.as_ref().map(rhs) + } +} + +impl ApplyMut for Option +where + F: FnMut(&mut U) -> V, +{ + type Output = Option; + + fn apply_mut(&mut self, rhs: F) -> Self::Output { + self.as_mut().map(rhs) + } +} + +impl Apply for [U; N] +where + F: Fn(&U) -> V, +{ + type Output = [V; N]; + + fn apply(&self, rhs: F) -> Self::Output { + core::array::from_fn(|i| rhs(&self[i])) + } +} + +#[cfg(all(feature = "alloc", feature = "nightly"))] +mod impl_alloc { + use crate::ops::Apply; + use alloc::alloc::Allocator; + use alloc::boxed::Box; + use alloc::vec::Vec; + + impl Apply for Box + where + A: Allocator, + F: Fn(&U) -> V, + { + type Output = Box; + + fn apply(&self, rhs: F) -> Self::Output { + Box::new(rhs(self.as_ref())) + } + } + + impl Apply for Vec + where + A: Allocator, + F: Fn(&U) -> V, + Vec: FromIterator, + { + type Output = Vec; + + fn apply(&self, rhs: F) -> Self::Output { + self.iter().map(rhs).collect() + } + } +} +#[cfg(all(feature = "alloc", not(feature = "nightly")))] +mod impl_alloc { + use crate::ops::Apply; + use alloc::boxed::Box; + use alloc::vec::Vec; + + impl Apply for Box + where + F: Fn(&U) -> V, + { + type Output = Box; + + fn apply(&self, rhs: F) -> Self::Output { + Box::new(rhs(self.as_ref())) + } + } + + impl Apply for Vec + where + F: Fn(&U) -> V, + Vec: FromIterator, + { + type Output = Vec; + + fn apply(&self, rhs: F) -> Self::Output { + self.iter().map(rhs).collect() + } + } +} diff --git a/traits/src/impls/impl_container.rs b/traits/src/impls/impl_container.rs index ca1bf41..cfe5f5e 100644 --- a/traits/src/impls/impl_container.rs +++ b/traits/src/impls/impl_container.rs @@ -3,8 +3,7 @@ Created At: 2025.12.26:19:32:27 Contrib: @FL03 */ -use crate::container::{Container, ContainerMap}; -use crate::ops::Apply; +use crate::container::Container; use crate::space::RawSpace; impl Container for S @@ -14,20 +13,6 @@ where type Cont = S; } -impl ContainerMap for S -where - S: Container = S>, - S::Cont: RawSpace, -{ - fn map(&self, f: F) -> Self::Cont - where - Self::Cont: Apply>, - Self::Cont: Sized, - { - as Apply>::apply(self, f) - } -} - impl Container for [T] { type Cont = [U]; } diff --git a/traits/src/impls/impl_map.rs b/traits/src/impls/impl_map.rs new file mode 100644 index 0000000..5df7572 --- /dev/null +++ b/traits/src/impls/impl_map.rs @@ -0,0 +1,109 @@ +/* + Appellation: impl_map + Created At: 2026.01.01:21:59:39 + Contrib: @FL03 +*/ +use crate::ops::map::{MapInto, MapTo}; + +impl MapInto for Option +where + F: FnOnce(X) -> Y, +{ + type Cont = Option; + type Elem = X; + + fn map_into(self, f: F) -> Self::Cont { + self.map(f) + } +} + +impl<'a, F, X, Y> MapInto for &'a Option +where + F: FnOnce(&X) -> Y, +{ + type Cont = Option; + type Elem = &'a X; + + fn map_into(self, f: F) -> Self::Cont { + self.as_ref().map(f) + } +} + +impl MapTo for Option +where + F: FnOnce(&X) -> Y, +{ + type Cont = Option; + type Elem = X; + + fn map_to(&self, f: F) -> Self::Cont { + self.as_ref().map(f) + } +} + +#[cfg(all(feature = "alloc", feature = "nightly"))] +mod impl_alloc { + use crate::ops::map::{MapInto, MapTo}; + use alloc::alloc::Allocator; + use alloc::vec::Vec; + + impl MapInto for Vec + where + A: Allocator, + F: FnMut(X) -> Y, + Vec: FromIterator, + { + type Cont = Vec; + type Elem = X; + + fn map_into(self, f: F) -> Self::Cont { + self.into_iter().map(f).collect() + } + } + + impl MapTo for Vec + where + A: Allocator, + F: FnMut(&X) -> Y, + Vec: FromIterator, + { + type Cont = Vec; + type Elem = X; + + fn map_to(&self, f: F) -> Self::Cont { + self.iter().map(f).collect() + } + } +} + +#[cfg(all(feature = "alloc", not(feature = "nightly")))] +mod impl_alloc { + use crate::ops::map::{MapInto, MapTo}; + use alloc::vec::Vec; + + impl MapInto for Vec + where + F: FnMut(X) -> Y, + Vec: FromIterator, + { + type Cont = Vec; + type Elem = X; + + fn map_into(self, f: F) -> Self::Cont { + self.into_iter().map(f).collect() + } + } + + impl MapTo for Vec + where + F: FnMut(&X) -> Y, + Vec: FromIterator, + { + type Cont = Vec; + type Elem = X; + + fn map_to(&self, f: F) -> Self::Cont { + self.iter().map(f).collect() + } + } +} diff --git a/traits/src/impls/impl_space.rs b/traits/src/impls/impl_space.rs index cc190ac..a4a1869 100644 --- a/traits/src/impls/impl_space.rs +++ b/traits/src/impls/impl_space.rs @@ -3,7 +3,19 @@ Created At: 2025.12.26:19:20:09 Contrib: @FL03 */ -use crate::space::RawSpace; +use crate::{RawSpace, RawSpaceMut, RawSpaceRef, SliceSpace, SliceSpaceMut}; + +macro_rules! impl_scalar_space { + (impl $trait:ident for {$($T:ty),* $(,)?}) => { + $(impl_scalar_space! { @impl $trait for $T })* + }; + (@impl $trait:ident for $T:ty) => { + impl $crate::$trait for $T { + type Elem = $T; + + } + }; +} macro_rules! impl_raw_space { (impl $trait:ident for {$( @@ -14,7 +26,7 @@ macro_rules! impl_raw_space { })* }; (@impl $trait:ident for $($cont:ident)::*<$($lt:lifetime,)? $($T:ident),*> $(where $($rest:tt)*)?) => { - impl<$($lt,)? $($T),*> $trait for $($cont)::*<$($lt,)? $($T),*> $(where $($rest)*)? { + impl<$($lt,)? $($T),*> $crate::$trait for $($cont)::*<$($lt,)? $($T),*> $(where $($rest)*)? { type Elem = $E; } }; @@ -22,7 +34,7 @@ macro_rules! impl_raw_space { macro_rules! impl_raw_tuple_store { (@impl $trait:ident for ($($name:ident),+ $(,)?)) => { - impl<$E> $trait for ($($name),+) { + impl<$E> $crate::$trait for ($($name),+) { type Elem = $E; } }; @@ -31,6 +43,21 @@ macro_rules! impl_raw_tuple_store { }; } +impl_scalar_space! { + impl RawSpace for { + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize, + f32, f64, + bool, char + } +} +#[cfg(feature = "alloc")] +impl_scalar_space! { + impl RawSpace for { + alloc::string::String + } +} + impl_raw_tuple_store! { impl RawSpace for { (T, T), @@ -78,13 +105,13 @@ impl_raw_space! { #[cfg(all(feature = "alloc", feature = "nightly"))] impl_raw_space! { impl RawSpace for { - alloc::collections::BTreeSet { where A: alloc::allocator::Allocator }, - alloc::collections::LinkedList { where A: alloc::allocator::Allocator }, - alloc::collections::VecDeque { where A: alloc::allocator::Allocator }, - alloc::collections::BinaryHeap { where A: alloc::allocator::Allocator }, - alloc::collections::BTreeMap { where A: alloc::allocator::Allocator }, - alloc::collections::btree_map::Entry<'a, K, T, a> { where A: alloc::allocator::Allocator }, - alloc::vec::Vec { where A: alloc::allocator::Allocator }, + alloc::collections::BTreeSet { where A: Clone + alloc::alloc::Allocator }, + alloc::collections::LinkedList { where A: alloc::alloc::Allocator }, + alloc::collections::VecDeque { where A: alloc::alloc::Allocator }, + alloc::collections::BinaryHeap { where A: alloc::alloc::Allocator }, + alloc::collections::BTreeMap { where A: Clone + alloc::alloc::Allocator }, + alloc::collections::btree_map::Entry<'a, K, T, A> { where A: Clone + alloc::alloc::Allocator }, + alloc::vec::Vec { where A: alloc::alloc::Allocator }, } } @@ -128,3 +155,160 @@ impl RawSpace for &mut [T] { impl RawSpace for [T; N] { type Elem = T; } + +impl RawSpaceRef for [T; N] { + fn as_ptr(&self) -> *const Self::Elem { + <[T]>::as_ptr(self) + } +} + +impl RawSpaceMut for [T; N] { + fn as_ptr_mut(&mut self) -> *mut Self::Elem { + <[T]>::as_mut_ptr(self) + } +} + +impl SliceSpace for [T; N] { + fn as_slice(&self) -> &[Self::Elem] { + self + } +} + +impl SliceSpaceMut for [T; N] { + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } +} + +impl RawSpaceRef for [T] { + fn as_ptr(&self) -> *const Self::Elem { + <[T]>::as_ptr(self) + } +} + +impl RawSpaceMut for [T] { + fn as_ptr_mut(&mut self) -> *mut Self::Elem { + <[T]>::as_mut_ptr(self) + } +} + +impl SliceSpace for [T] { + fn as_slice(&self) -> &[Self::Elem] { + self + } +} + +impl SliceSpaceMut for [T] { + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } +} + +impl RawSpaceRef for &[T] { + fn as_ptr(&self) -> *const Self::Elem { + <[T]>::as_ptr(self) + } +} + +impl SliceSpace for &[T] { + fn as_slice(&self) -> &[Self::Elem] { + self + } +} + +impl RawSpaceRef for &mut [T] { + fn as_ptr(&self) -> *const Self::Elem { + <[T]>::as_ptr(self) + } +} + +impl RawSpaceMut for &mut [T] { + fn as_ptr_mut(&mut self) -> *mut Self::Elem { + <[T]>::as_mut_ptr(self) + } +} + +impl SliceSpace for &mut [T] { + fn as_slice(&self) -> &[Self::Elem] { + self + } +} + +impl SliceSpaceMut for &mut [T] { + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self + } +} + +#[cfg(all(feature = "alloc", feature = "nightly"))] +mod impl_alloc { + use crate::space::*; + use alloc::alloc::Allocator; + use alloc::vec::Vec; + + impl RawSpaceRef for Vec + where + A: Allocator, + { + fn as_ptr(&self) -> *const Self::Elem { + Vec::as_ptr(self) + } + } + + impl RawSpaceMut for Vec + where + A: Allocator, + { + fn as_ptr_mut(&mut self) -> *mut Self::Elem { + Vec::as_mut_ptr(self) + } + } + + impl SliceSpace for Vec + where + A: Allocator, + { + fn as_slice(&self) -> &[Self::Elem] { + self.as_slice() + } + } + + impl SliceSpaceMut for Vec + where + A: Allocator, + { + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self.as_mut_slice() + } + } +} + +#[cfg(all(feature = "alloc", not(feature = "nightly")))] +mod impl_alloc { + use crate::space::*; + use alloc::vec::Vec; + + impl RawSpaceRef for Vec { + fn as_ptr(&self) -> *const Self::Elem { + Vec::as_ptr(self) + } + } + + impl RawSpaceMut for Vec { + fn as_ptr_mut(&mut self) -> *mut Self::Elem { + Vec::as_mut_ptr(self) + } + } + + impl SliceSpace for Vec { + fn as_slice(&self) -> &[Self::Elem] { + self.as_slice() + } + } + + impl SliceSpaceMut for Vec { + fn as_mut_slice(&mut self) -> &mut [Self::Elem] { + self.as_mut_slice() + } + } +} diff --git a/traits/src/impls/impl_store.rs b/traits/src/impls/impl_store.rs index a54641d..b9d1c11 100644 --- a/traits/src/impls/impl_store.rs +++ b/traits/src/impls/impl_store.rs @@ -5,22 +5,24 @@ */ #[cfg(all(feature = "alloc", feature = "nightly"))] mod impl_alloc { - use crate::store::*; - use alloc::allocator::Allocator; + use crate::store::{RawStore, Store, StoreEntry}; + use alloc::alloc::Allocator; use alloc::collections::btree_map::{self, BTreeMap}; use alloc::vec::Vec; impl<'a, K, V, A> StoreEntry<'a> for btree_map::Entry<'a, K, V, A> where - A: Allocator, + A: Allocator + Clone, { type Key = K; type Value = V; } + impl RawStore for BTreeMap where A: Allocator + Clone {} + impl Store for BTreeMap where - A: Allocator, + A: Allocator + Clone, { type Entry<'a> = btree_map::Entry<'a, K, V, A> @@ -33,8 +35,9 @@ mod impl_alloc { #[cfg(all(feature = "alloc", not(feature = "nightly")))] mod impl_alloc { - use crate::store::*; + use crate::store::{RawStore, Store, StoreEntry}; use alloc::collections::btree_map::{self, BTreeMap}; + use alloc::vec::Vec; impl<'a, K, V> StoreEntry<'a> for btree_map::Entry<'a, K, V> { type Key = K; diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 4936a04..4fffa12 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -14,9 +14,9 @@ )] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "nightly", feature(allocator_api))] -// compiler check -#[cfg(not(any(feature = "std", feature = "alloc")))] -compile_error! { "either the \"std\" or \"alloc\" feature must be enabled" } +// // compiler check +// #[cfg(not(any(feature = "std", feature = "alloc")))] +// compile_error! { "either the \"std\" or \"alloc\" feature must be enabled" } // macros #[macro_use] pub(crate) mod macros { @@ -33,7 +33,9 @@ pub mod space; pub mod store; mod impls { + mod impl_apply; mod impl_container; + mod impl_map; mod impl_space; mod impl_store; } @@ -41,10 +43,17 @@ mod impls { pub mod ops { //! This module provides various operations traits and implementations for musical concepts #[doc(inline)] - pub use self::{apply::*, get::*}; + pub use self::{apply::*, get::*, map::*}; - mod apply; - mod get; + pub(crate) mod apply; + pub(crate) mod get; + pub(crate) mod map; + + pub(crate) mod prelude { + pub use super::apply::*; + pub use super::get::*; + pub use super::map::*; + } } // re-exports #[doc(inline)] @@ -54,7 +63,7 @@ pub use self::{container::*, functor::*, ops::*, space::*, store::*}; pub mod prelude { pub use crate::container::*; pub use crate::functor::*; - pub use crate::ops::*; + pub use crate::ops::prelude::*; pub use crate::space::*; pub use crate::store::*; } diff --git a/traits/src/ops/apply.rs b/traits/src/ops/apply.rs index 85f86b6..5354ae0 100644 --- a/traits/src/ops/apply.rs +++ b/traits/src/ops/apply.rs @@ -84,107 +84,3 @@ where Ok(self.apply_mut(rhs)) } } - -impl ApplyOnce for Option -where - F: FnOnce(U) -> V, -{ - type Output = Option; - - fn apply_once(self, rhs: F) -> Self::Output { - self.map(rhs) - } -} - -impl Apply for Option -where - F: Fn(&U) -> V, -{ - type Output = Option; - - fn apply(&self, rhs: F) -> Self::Output { - self.as_ref().map(rhs) - } -} - -impl ApplyMut for Option -where - F: FnMut(&mut U) -> V, -{ - type Output = Option; - - fn apply_mut(&mut self, rhs: F) -> Self::Output { - self.as_mut().map(rhs) - } -} - -impl Apply for [U; N] -where - F: Fn(&U) -> V, -{ - type Output = [V; N]; - - fn apply(&self, rhs: F) -> Self::Output { - core::array::from_fn(|i| rhs(&self[i])) - } -} - -#[cfg(all(feature = "alloc", feature = "nightly"))] -mod impl_alloc { - use super::Apply; - use alloc::allocator::Allocator; - use alloc::boxed::Box; - use alloc::vec::Vec; - - impl Apply for Box - where - A: Allocator, - F: Fn(&U) -> V, - { - type Output = Box; - - fn apply(&self, rhs: F) -> Self::Output { - Box::new(rhs(self.as_ref())) - } - } - - impl Apply for Vec - where - A: Allocator, - F: Fn(&U) -> V, - { - type Output = Vec; - - fn apply(&self, rhs: F) -> Self::Output { - self.iter().map(rhs).collect() - } - } -} -#[cfg(all(feature = "alloc", not(feature = "nightly")))] -mod impl_alloc { - use super::Apply; - use alloc::boxed::Box; - use alloc::vec::Vec; - - impl Apply for Box - where - F: Fn(&U) -> V, - { - type Output = Box; - - fn apply(&self, rhs: F) -> Self::Output { - Box::new(rhs(self.as_ref())) - } - } - - impl Apply for Vec - where - F: Fn(&U) -> V, - { - type Output = Vec; - - fn apply(&self, rhs: F) -> Self::Output { - self.iter().map(rhs).collect() - } - } -} diff --git a/traits/src/ops/map.rs b/traits/src/ops/map.rs new file mode 100644 index 0000000..acd5d6d --- /dev/null +++ b/traits/src/ops/map.rs @@ -0,0 +1,38 @@ +/* + Appellation: map + Created At: 2026.01.01:21:31:12 + Contrib: @FL03 +*/ +/// The [`MapTo`] trait defines an interface for containers able to _map_ or apply a given +/// function onto a reference to each of its constituting elements, producing a new container +/// with the results of those function applications. The construction of the trait itself +/// allows implementors to have granular controls over exactly which type of function and +/// output is being produced, relying on associated type parameters to define the container +/// and its _current_ element type. +pub trait MapTo +where + F: FnOnce(&Self::Elem) -> X, +{ + type Cont: ?Sized; + type Elem; + + fn map_to(&self, f: F) -> Self::Cont; +} +/// [`MapInto`] describes a consuming interface for containers that enables the mapping of a +/// given function onto each element of the container. While the trait definition constrains +/// the generic function parameters, `F` to a `FnOnce` closure, implementors coulds choose +/// to strengthen this constraint to `FnMut` or `Fn` as needed. +pub trait MapInto +where + F: FnOnce(Self::Elem) -> X, +{ + type Cont: ?Sized; + /// the current type of element associated with the contained + type Elem; + + fn map_into(self, f: F) -> Self::Cont; +} + +/* + ************* Implementations ************* +*/ diff --git a/traits/src/space.rs b/traits/src/space.rs index 85c6945..974fe01 100644 --- a/traits/src/space.rs +++ b/traits/src/space.rs @@ -12,37 +12,52 @@ pub trait RawSpace { /// The type of elements associated with the space type Elem; } - +/// [`ScalarSpace`] defins a type of space that consists of a single element. This trait is +/// useful in that it generally allows for a tensor-like treatment of scalar values within +/// more complex mathematical structures. +pub trait ScalarSpace: RawSpace { + private! {} +} +/// [`RawSpaceRef`] is a trait that provides various read-only methods for accessing elements. +pub trait RawSpaceRef: RawSpace { + fn as_ptr(&self) -> *const Self::Elem; +} /// [`RawSpaceMut`] is a trait that provides various mutable methods for accessing elements. -pub trait RawSpaceMut: RawSpace {} +pub trait RawSpaceMut: RawSpace { + /// returns a mutable pointer to the element currently within scope + fn as_ptr_mut(&mut self) -> *mut Self::Elem; +} -/// [`RawSpaceRef`] is a trait that provides various read-only methods for accessing elements. -pub trait RawSpaceRef: RawSpace {} /// [`SliceSpace`] is used to define sequential collections, spaces, or containers that can be /// viewed as slices. -pub trait SliceSpace: RawSpace { +pub trait SliceSpace: RawSpaceRef { fn as_slice(&self) -> &[Self::Elem]; - /// returns a raw pointer to the underlying elements - fn as_ptr(&self) -> *const Self::Elem { - self.as_slice().as_ptr() - } fn len(&self) -> usize { self.as_slice().len() } -} - -pub trait SliceSpaceMut: SliceSpace { - fn as_mut_slice(&mut self) -> &mut [Self::Elem]; - fn as_mut_ptr(&mut self) -> *mut Self::Elem { - self.as_mut_slice().as_mut_ptr() + fn is_empty(&self) -> bool { + self.len() == 0 } } +/// [`SliceSpaceMut`] is used to define sequential collections, spaces, or containers that can be +pub trait SliceSpaceMut: SliceSpace + RawSpaceMut { + /// returns a mutable slice of the elements + fn as_mut_slice(&mut self) -> &mut [Self::Elem]; +} /* ************* Implementations ************* */ + +impl ScalarSpace for T +where + T: RawSpace, +{ + seal! {} +} + impl RawSpace for &C where C: RawSpace, @@ -56,3 +71,21 @@ where { type Elem = C::Elem; } + +impl RawSpaceRef for &U +where + U: RawSpaceRef, +{ + fn as_ptr(&self) -> *const Self::Elem { + U::as_ptr(*self) + } +} + +impl RawSpaceRef for &mut U +where + U: RawSpaceRef, +{ + fn as_ptr(&self) -> *const Self::Elem { + U::as_ptr(*self) + } +} diff --git a/traits/tests/ops.rs b/traits/tests/ops.rs new file mode 100644 index 0000000..a60a77e --- /dev/null +++ b/traits/tests/ops.rs @@ -0,0 +1,23 @@ +/* + Appellation: ops + Created At: 2026.01.01:21:49:55 + Contrib: @FL03 +*/ +use rspace_traits::Apply; + +fn add(a: A, b: B) -> C +where + A: core::ops::Add, +{ + core::ops::Add::add(a, b) +} + +#[test] +fn test_apply() { + let something = Some(19u8); + let result = something.apply(|&x| { + let new_x = x as f64; + add(new_x, 3.0f64) + }); + assert_eq! {result, Some(22.0f64)}; +}