diff options
| author | Dylan <boss@tehbox.org> | 2026-08-26 23:58:16 +1200 |
|---|---|---|
| committer | Dylan <boss@tehbox.org> | 2026-08-26 23:58:16 +1200 |
| commit | 7c640bfeaf2a0fbc8c3550b4c19790a800a7f6a2 (patch) | |
| tree | 60ef598fa415b6a01bed7b1c1f62c1c696111c8f /byte_encode_derive/src/lib.rs | |
| parent | f8ffb92f2857677e4a9986ef154800ddb2e233fd (diff) | |
| download | tehimage-rs-7c640bfeaf2a0fbc8c3550b4c19790a800a7f6a2.tar.gz tehimage-rs-7c640bfeaf2a0fbc8c3550b4c19790a800a7f6a2.zip | |
Added derive macro for byte encode
Added start for PNG reading
Added BMP writing
Diffstat (limited to 'byte_encode_derive/src/lib.rs')
| -rw-r--r-- | byte_encode_derive/src/lib.rs | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/byte_encode_derive/src/lib.rs b/byte_encode_derive/src/lib.rs new file mode 100644 index 0000000..5970c66 --- /dev/null +++ b/byte_encode_derive/src/lib.rs @@ -0,0 +1,128 @@ +// Code mostly made by gemini somehow + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DeriveInput, Fields}; + +#[proc_macro_derive(ByteEncode)] +pub fn derive_byte_encode(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + // We only support structs with named fields for this example + let fields = match input.data { + Data::Struct(data) => match data.fields { + Fields::Named(fields) => fields.named, + _ => panic!("Only named fields are supported"), + }, + _ => panic!("Only structs are supported"), + }; + + // --- 1. Generate from_le_bytes parsing logic --- + let mut current_offset = quote! { 0 }; + let from_le_bytes_initializers = fields.iter().map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + + // Calculate start and end bounds for the current field slice + let start = quote! { #current_offset }; + let end = quote! { #start + <#field_type>::SIZE }; + + // Update the offset tracking for the next iteration loop + current_offset = quote! { #end }; + + quote! { + #field_name: <#field_type as ByteEncode<{<#field_type>::SIZE}>>::from_le_bytes( + buffer[#start..#end].try_into().unwrap() + ) + } + }); + let mut current_offset = quote! { 0 }; + let from_be_bytes_initializers = fields.iter().map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + + // Calculate start and end bounds for the current field slice + let start = quote! { #current_offset }; + let end = quote! { #start + <#field_type>::SIZE }; + + // Update the offset tracking for the next iteration loop + current_offset = quote! { #end }; + + quote! { + #field_name: <#field_type as ByteEncode<{<#field_type>::SIZE}>>::from_be_bytes( + &mut buffer[#start..#end].try_into().unwrap() + ) + } + }); + + + // --- 2. Generate to_le_bytes serialization logic --- + let mut current_offset = quote! { 0 }; + let to_le_bytes_writers = fields.iter().map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + + let start = quote! { #current_offset }; + let end = quote! { #start + <#field_type>::SIZE }; + + current_offset = quote! { #end }; + + quote! { + res[#start..#end].copy_from_slice(&self.#field_name.to_le_bytes()); + } + }); + let mut current_offset = quote! { 0 }; + let to_be_bytes_writers = fields.iter().map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + + let start = quote! { #current_offset }; + let end = quote! { #start + <#field_type>::SIZE }; + + current_offset = quote! { #end }; + + quote! { + res[#start..#end].copy_from_slice(&self.#field_name.to_be_bytes()); + } + }); + + + // --- 3. Construct final token stream --- + // This dynamically sums up sizes like: 0 + Field1::SIZE + Field2::SIZE ... + let total_size_expr = fields.iter().fold(quote! { 0 }, |acc, f| { + let field_type = &f.ty; + quote! { #acc + <#field_type>::SIZE } + }); + + let expanded = quote! { + impl ByteEncode<{ #total_size_expr }> for #name { + fn from_le_bytes(buffer: &[u8; { #total_size_expr }]) -> Self { + Self { + #( #from_le_bytes_initializers, )* + } + } + + fn to_le_bytes(&self) -> [u8; { #total_size_expr }] { + let mut res = [0u8; { #total_size_expr }]; + #( #to_le_bytes_writers )* + res + } + + + fn from_be_bytes(buffer: &mut [u8; { #total_size_expr }]) -> Self { + Self { + #( #from_be_bytes_initializers, )* + } + } + + fn to_be_bytes(&self) -> [u8; { #total_size_expr }] { + let mut res = [0u8; { #total_size_expr }]; + #( #to_be_bytes_writers )* + res + } + } + }; + + TokenStream::from(expanded) +} |
