#attributes #fixed-length #macro #string #size #struct #variables

macro fixed-size

Attribute macro to replace variable length types with fixed length types in struct definitions. Useful for overriding String when using prost.

1 stable release

1.0.0 Nov 6, 2023

#1630 in Procedural macros

21 downloads per month

MIT/Apache

9KB
77 lines

crates.io MIT/Apache 2.0

fixed-size

fixed-size - A struct attribute to set fixed sizes for certain fields which are normally dynamic

Documentation on docs.rs


lib.rs:

struct attribute to set fixed sizes for certain fields which are normally dynamic

This is useful when generating structs from protobufs using prost and also using those structs with a serde format that requires fixed length strings

Example

syntax = "proto3";
message Foo
{
 string my_string = 1;
}

Prost will create use String for the my_string field. If you have a binary format requiring exactly 4 characters in a string this will be difficult to handle in a generic manner. If you add the #[fixed(my_string=4)] attribute then you'll end up with a ArrayString::<4> instead.

By default, ArrayString will be used but this can be overridden with #[fixed(typ=MyString, thestring=4)] The typical use is

use arrayvec::ArrayString;

struct MyString<const CAP: usize>(ArrayString<CAP>);

impl<const CAP: usize> AsRef<ArrayString<CAP>> for MyString<CAP> {
   fn as_ref(&self) -> &ArrayString<CAP> {
       &self.0
   }
}
impl<const CAP: usize> serde::Serialize for MyString<CAP> {
   fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
       where S: serde::Serializer
   {
       // specialized serialize to override ArrayString's conversion to &str
       todo!()
   }
}
// More impls, probably AsMut, etc.
use arrayvec::ArrayString;
use fixed_size::fixed;

#[fixed(my_string=4)]
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
struct Foo {
  my_string: String,
}

let foo = Foo { my_string: ArrayString::<4>::from("abcd").unwrap() };
// bincode actually supports var length strings but it's just used as an example and test
let encoded = bincode::serialize(&foo).unwrap();
let decoded: Foo = bincode::deserialize(&encoded[..]).unwrap();
assert_eq!(foo, decoded);

Adding fewer than 4 characters to my_string will 0 pad the value. Adding more than 4 characters will result in an error.

Dependencies

~0.4–1MB
~21K SLoC