Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bebytes/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bebytes"
version = "3.0.0"
version = "3.0.1"
edition = "2021"
rust-version = "1.75.0"
license = "MIT"
Expand All @@ -21,7 +21,7 @@ path = "./bin/performance_benchmark.rs"
required-features = ["std"]

[dependencies]
bebytes_derive = { version = "3.0.0" }
bebytes_derive = { version = "3.0.1" }
bytes = { version = "1", optional = true }

[dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion bebytes_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "bebytes_derive"
description = "A macro to generate/parse binary representation of messages with custom bit fields"
version = "3.0.0"
version = "3.0.1"
edition = "2021"
rust-version = "1.75.0"
publish = true
Expand Down
18 changes: 12 additions & 6 deletions bebytes_derive/src/functional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,18 @@ pub mod pure_helpers {
use quote::quote;
use syn::Ident;

/// Create a field accessor without side effects
pub fn create_field_accessor(field_name: &Ident, needs_owned: bool) -> TokenStream {
if needs_owned {
quote! { let #field_name = self.#field_name.clone(); }
} else {
quote! { let #field_name = self.#field_name; }
#[derive(Clone, Copy)]
pub enum AccessorMode {
Copy,
Reference,
Clone,
}

pub fn create_field_accessor(field_name: &Ident, mode: AccessorMode) -> TokenStream {
match mode {
AccessorMode::Copy => quote! { let #field_name = self.#field_name; },
AccessorMode::Reference => quote! { let #field_name = &self.#field_name; },
AccessorMode::Clone => quote! { let #field_name = self.#field_name.clone(); },
}
}

Expand Down
23 changes: 10 additions & 13 deletions bebytes_derive/src/structs.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::functional::pure_helpers::{create_field_accessor, AccessorMode};
use crate::{attrs, utils};
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
Expand Down Expand Up @@ -482,7 +483,7 @@ fn process_bits_field_functional(
let field_name = &context.field_name;
let field_type = context.field_type;

let accessor = crate::functional::pure_helpers::create_field_accessor(field_name, false);
let accessor = create_field_accessor(field_name, AccessorMode::Copy);
let bit_sum = crate::functional::pure_helpers::create_bit_sum(size);
let limit_check =
crate::functional::pure_helpers::create_bit_field_limit_check(field_name, field_type, size);
Expand Down Expand Up @@ -769,7 +770,7 @@ fn process_primitive_type_functional(

let field_size = utils::get_primitive_type_size(field_type)?;

let accessor = crate::functional::pure_helpers::create_field_accessor(field_name, false);
let accessor = create_field_accessor(field_name, AccessorMode::Copy);
let bit_sum = crate::functional::pure_helpers::create_byte_bit_sum(field_size);

let parsing_tokens = vec![
Expand Down Expand Up @@ -817,8 +818,7 @@ fn process_array_functional(
if let syn::Type::Path(elem) = &*tp.elem {
let segments = &elem.path.segments;
if segments.len() == 1 && segments[0].ident == "u8" {
let accessor =
crate::functional::pure_helpers::create_field_accessor(field_name, true);
let accessor = create_field_accessor(field_name, AccessorMode::Copy);
let bit_sum = crate::functional::pure_helpers::create_byte_bit_sum(length);

let parsing = quote! {
Expand Down Expand Up @@ -1011,7 +1011,7 @@ fn process_vector_functional(
let field = context.field;
let is_last_field = context.is_last_field;

let accessor = crate::functional::pure_helpers::create_field_accessor(field_name, true);
let accessor = create_field_accessor(field_name, AccessorMode::Clone);

if let syn::Type::Path(tp) = field_type {
if let Some(syn::Type::Path(ref inner_tp)) = utils::solve_for_inner_type(tp, "Vec") {
Expand Down Expand Up @@ -1250,8 +1250,7 @@ fn process_option_array(
let array_len: usize = lit_int.base10_parse()?;
let total_size = array_len + 1;

let accessor =
crate::functional::pure_helpers::create_field_accessor(field_name, true);
let accessor = create_field_accessor(field_name, AccessorMode::Copy);
let bit_sum = crate::functional::pure_helpers::create_byte_bit_sum(total_size);

let parsing = quote! {
Expand Down Expand Up @@ -1339,8 +1338,7 @@ fn process_option_type_functional(
let field_size = utils::get_primitive_type_size(&inner_type)?;
let total_size = field_size + 1;

let accessor =
crate::functional::pure_helpers::create_field_accessor(field_name, false);
let accessor = create_field_accessor(field_name, AccessorMode::Copy);
let bit_sum = crate::functional::pure_helpers::create_byte_bit_sum(total_size);

let value_parsing = create_option_inner_parsing(
Expand Down Expand Up @@ -1430,8 +1428,7 @@ fn process_custom_type_functional(
let field_name = &context.field_name;
let field_type = context.field_type;

let needs_owned = !utils::is_copy(field_type);
let accessor = crate::functional::pure_helpers::create_field_accessor(field_name, needs_owned);
let accessor = create_field_accessor(field_name, AccessorMode::Clone);

let bit_sum = quote! {
bit_sum += 8 * #field_type::field_size();
Expand Down Expand Up @@ -1480,7 +1477,7 @@ fn process_string_functional(
let field = context.field;
let is_last_field = context.is_last_field;

let accessor = crate::functional::pure_helpers::create_field_accessor(field_name, true);
let accessor = create_field_accessor(field_name, AccessorMode::Reference);

// Generate parsing code based on size constraints
let (bit_sum, parsing, writing) = match (size, string_size_ident) {
Expand Down Expand Up @@ -1523,7 +1520,7 @@ fn process_size_expression_functional(
let field_name = &context.field_name;
let field_type = context.field_type;

let accessor = crate::functional::pure_helpers::create_field_accessor(field_name, true);
let accessor = create_field_accessor(field_name, AccessorMode::Clone);

// Generate the size calculation code
let size_calculation = size_expr.generate_evaluation_code();
Expand Down
120 changes: 0 additions & 120 deletions bebytes_derive/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,76 +138,6 @@ pub fn is_vec_of_vec_u8(tp: &syn::TypePath) -> bool {
false
}

pub(crate) fn is_copy(field_type: &syn::Type) -> bool {
match field_type {
syn::Type::Never(_) | syn::Type::Infer(_) => true, // ! and _ are Copy

syn::Type::Path(type_path) => {
// Check if it's a known Copy primitive or standard library type
if let Some(ident) = type_path.path.get_ident() {
let name = ident.to_string();
match name.as_str() {
// Types that are Copy
"bool" | "char" | "u8" | "u16" | "u32" | "u64" | "u128" | "usize" | "i8"
| "i16" | "i32" | "i64" | "i128" | "isize" | "f32" | "f64" | "NonZero"
| "NonZeroU8" | "NonZeroU16" | "NonZeroU32" | "NonZeroU64" | "NonZeroU128"
| "NonZeroUsize" | "NonZeroI8" | "NonZeroI16" | "NonZeroI32" | "NonZeroI64"
| "NonZeroI128" | "NonZeroIsize" => true,

_ => false, // Conservatively assume non-Copy
}
} else if !type_path.path.segments.is_empty() {
// Handle generic types
let last_segment = &type_path.path.segments.last().unwrap();
match last_segment.ident.to_string().as_str() {
"Option" => {
// Option<T> is Copy if T is Copy
if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments {
if !args.args.is_empty() {
if let syn::GenericArgument::Type(ty) = &args.args[0] {
return is_copy(ty);
}
}
}
false
}
"Result" => {
// Result<T, E> is Copy if both T and E are Copy
if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments {
if args.args.len() >= 2 {
if let syn::GenericArgument::Type(t) = &args.args[0] {
if let syn::GenericArgument::Type(e) = &args.args[1] {
return is_copy(t) && is_copy(e);
}
}
}
}
false
}
// Add more cases for other generic types
_ => false, // Conservatively assume non-Copy
}
} else {
false
}
}

syn::Type::Array(type_array) => is_copy(&type_array.elem), // Array<T> is Copy if T is Copy
syn::Type::Tuple(type_tuple) => {
// A tuple is Copy if all its elements are Copy
type_tuple.elems.iter().all(is_copy)
}
syn::Type::Paren(type_paren) => is_copy(&type_paren.elem),
syn::Type::Group(type_group) => is_copy(&type_group.elem),

syn::Type::Reference(type_reference) => {
// &T is always Copy, &mut T is never Copy
type_reference.mutability.is_none()
}
_ => false, // Conservative default for any other types
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -302,44 +232,6 @@ mod tests {
}
}

#[test]
fn test_is_copy_trait() {
// Types that implement Copy
let copy_types = vec![
parse_quote!(u32),
parse_quote!(i64),
parse_quote!([u8; 10]),
parse_quote!(Option<u32>),
parse_quote!((u32, u64)),
parse_quote!(Result<u32, u32>),
];

for ty in copy_types {
assert!(is_copy(&ty), "Type should implement Copy");
}

// Types that don't implement Copy
let non_copy_types = vec![
parse_quote!(String),
parse_quote!(Vec<u8>),
parse_quote!(Option<String>),
parse_quote!(Result<String, u32>),
];

for ty in non_copy_types {
assert!(!is_copy(&ty), "Type should not implement Copy");
}
}

#[test]
fn test_is_copy_nested_types() {
// Test nested type checking
assert!(is_copy(&parse_quote!(Option<Option<u32>>)));
assert!(!is_copy(&parse_quote!(Option<Vec<u8>>)));
assert!(is_copy(&parse_quote!(Result<[u8; 10], u32>)));
assert!(!is_copy(&parse_quote!(Result<String, String>)));
}

#[test]
fn test_solve_for_inner_type() {
// Test Option inner type extraction
Expand Down Expand Up @@ -424,21 +316,9 @@ mod tests {

#[test]
fn test_edge_cases() {
// Test empty path segments
let empty_path: syn::Type = parse_quote!(::std::vec::Vec<u8>);
if let syn::Type::Path(tp) = &empty_path {
assert!(!is_primitive_type(tp));
}

// Test parenthesized types
let paren_ty: syn::Type = parse_quote!((u32));
assert!(is_copy(&paren_ty));

// Test reference types
let ref_ty: syn::Type = parse_quote!(&u32);
assert!(is_copy(&ref_ty));

let mut_ref_ty: syn::Type = parse_quote!(&mut u32);
assert!(!is_copy(&mut_ref_ty));
}
}