From e75d56e23a88f0e134c7dcbd161778b34c853256 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Mon, 26 Oct 2026 11:39:45 +0000 Subject: [PATCH] Implement derive macro for Pixel --- Cargo.lock | 46 ++++++++++++++++ Cargo.toml | 1 + proc_macros/Cargo.lock | 46 ++++++++++++++++ proc_macros/Cargo.toml | 11 ++++ proc_macros/src/lib.rs | 68 ++++++++++++++++++++++++ src/image/linear_rgb.rs | 56 ++----------------- src/image/srgb.rs | 115 ++-------------------------------------- 7 files changed, 179 insertions(+), 164 deletions(-) create mode 100644 proc_macros/Cargo.lock create mode 100644 proc_macros/Cargo.toml create mode 100644 proc_macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 300ef4f..0f0066d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,49 @@ version = 4 [[package]] name = "ccvl" version = "0.1.0" +dependencies = [ + "ccvl_proc_macros", +] + +[[package]] +name = "ccvl_proc_macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" diff --git a/Cargo.toml b/Cargo.toml index 1469f4f..0ca21fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +ccvl_proc_macros = { path = "proc_macros" } diff --git a/proc_macros/Cargo.lock b/proc_macros/Cargo.lock new file mode 100644 index 0000000..15a5274 --- /dev/null +++ b/proc_macros/Cargo.lock @@ -0,0 +1,46 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ccvl_proc_macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" diff --git a/proc_macros/Cargo.toml b/proc_macros/Cargo.toml new file mode 100644 index 0000000..926cec2 --- /dev/null +++ b/proc_macros/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ccvl_proc_macros" +version = "0.1.0" +edition = "2024" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.47" +syn = "3.0.9" diff --git a/proc_macros/src/lib.rs b/proc_macros/src/lib.rs new file mode 100644 index 0000000..6e86f54 --- /dev/null +++ b/proc_macros/src/lib.rs @@ -0,0 +1,68 @@ +use proc_macro::TokenStream; + +#[proc_macro_derive(Pixel)] +pub fn pixel_derive(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = + syn::parse(input).expect("Invalid structure declaration"); + + if let syn::Data::Struct(def) = ast.data { + if let syn::Fields::Named(fields) = def.fields { + let names = + fields.named.into_iter().map(|field| field.ident.unwrap()); + impl_pixel(ast.ident, names.collect()) + } else { + panic!("Can only derive Pixel for named fields") + } + } else { + panic!("Can only derive Pixel for a struct") + } +} + +fn impl_pixel(name: syn::Ident, fields: Vec) -> TokenStream { + quote::quote! { + impl std::ops::AddAssign for #name { + fn add_assign(&mut self, other: Self) { + #( self.#fields += other.#fields; )* + } + } + + impl std::ops::MulAssign for #name { + fn mul_assign(&mut self, scalar: f32) { + #( self.#fields *= scalar; )* + } + } + + impl std::ops::DivAssign for #name { + fn div_assign(&mut self, scalar: f32) { + #( self.#fields /= scalar; )* + } + } + + impl std::ops::Mul for #name { + type Output = Self; + + fn mul(mut self, scalar: f32) -> Self { + self *= scalar; + self + } + } + + impl std::ops::Div for #name { + type Output = Self; + + fn div(mut self, scalar: f32) -> Self { + self /= scalar; + self + } + } + + impl std::default::Default for #name { + fn default() -> Self { + Self { + #( #fields: Default::default(), )* + } + } + } + } + .into() +} diff --git a/src/image/linear_rgb.rs b/src/image/linear_rgb.rs index 5b10484..1782b3d 100644 --- a/src/image/linear_rgb.rs +++ b/src/image/linear_rgb.rs @@ -1,4 +1,6 @@ -#[derive(Clone, Copy, Debug, PartialEq)] +use ccvl_proc_macros::Pixel; + +#[derive(Clone, Copy, Debug, PartialEq, Pixel)] pub struct LinearRGB { pub r: f32, pub g: f32, @@ -10,55 +12,3 @@ impl LinearRGB { Self { r, g, b } } } - -impl std::ops::AddAssign for LinearRGB { - fn add_assign(&mut self, other: LinearRGB) { - self.r += other.r; - self.g += other.g; - self.b += other.b; - } -} - -impl std::ops::MulAssign for LinearRGB { - fn mul_assign(&mut self, scalar: f32) { - self.r *= scalar; - self.g *= scalar; - self.b *= scalar; - } -} - -impl std::ops::DivAssign for LinearRGB { - fn div_assign(&mut self, scalar: f32) { - self.r /= scalar; - self.g /= scalar; - self.b /= scalar; - } -} - -impl std::ops::Mul for LinearRGB { - type Output = Self; - - fn mul(mut self, scalar: f32) -> Self { - self *= scalar; - self - } -} - -impl std::ops::Div for LinearRGB { - type Output = Self; - - fn div(mut self, scalar: f32) -> Self { - self /= scalar; - self - } -} - -impl std::default::Default for LinearRGB { - fn default() -> Self { - Self { - r: 0.0, - g: 0.0, - b: 0.0, - } - } -} diff --git a/src/image/srgb.rs b/src/image/srgb.rs index a9a0abb..a57db41 100644 --- a/src/image/srgb.rs +++ b/src/image/srgb.rs @@ -1,4 +1,6 @@ -#[derive(Clone, Copy, Debug, PartialEq)] +use ccvl_proc_macros::Pixel; + +#[derive(Clone, Copy, Debug, PartialEq, Pixel)] pub struct SRGBA { pub r: f32, pub g: f32, @@ -6,7 +8,7 @@ pub struct SRGBA { pub a: f32, } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Pixel)] pub struct SRGB { pub r: f32, pub g: f32, @@ -18,117 +20,8 @@ impl SRGBA { Self { r, g, b, a } } } - -impl std::ops::AddAssign for SRGBA { - fn add_assign(&mut self, other: SRGBA) { - self.r += other.r; - self.g += other.g; - self.b += other.b; - self.a += other.a; - } -} - -impl std::ops::MulAssign for SRGBA { - fn mul_assign(&mut self, scalar: f32) { - self.r *= scalar; - self.g *= scalar; - self.b *= scalar; - self.a *= scalar; - } -} - -impl std::ops::DivAssign for SRGBA { - fn div_assign(&mut self, scalar: f32) { - self.r /= scalar; - self.g /= scalar; - self.b /= scalar; - self.a /= scalar; - } -} - -impl std::ops::Mul for SRGBA { - type Output = Self; - - fn mul(mut self, scalar: f32) -> Self { - self *= scalar; - self - } -} - -impl std::ops::Div for SRGBA { - type Output = Self; - - fn div(mut self, scalar: f32) -> Self { - self /= scalar; - self - } -} - -impl std::default::Default for SRGBA { - fn default() -> Self { - Self { - r: 0.0, - g: 0.0, - b: 0.0, - a: 0.0, - } - } -} - impl SRGB { pub fn new(r: f32, g: f32, b: f32) -> Self { Self { r, g, b } } } - -impl std::ops::AddAssign for SRGB { - fn add_assign(&mut self, other: SRGB) { - self.r += other.r; - self.g += other.g; - self.b += other.b; - } -} - -impl std::ops::MulAssign for SRGB { - fn mul_assign(&mut self, scalar: f32) { - self.r *= scalar; - self.g *= scalar; - self.b *= scalar; - } -} - -impl std::ops::DivAssign for SRGB { - fn div_assign(&mut self, scalar: f32) { - self.r /= scalar; - self.g /= scalar; - self.b /= scalar; - } -} - -impl std::ops::Mul for SRGB { - type Output = Self; - - fn mul(mut self, scalar: f32) -> Self { - self *= scalar; - self - } -} - -impl std::ops::Div for SRGB { - type Output = Self; - - fn div(mut self, scalar: f32) -> Self { - self /= scalar; - self - } -} - -impl std::default::Default for SRGB { - fn default() -> Self { - Self { - r: 0.0, - g: 0.0, - b: 0.0, - } - } -}