Skip to main content

Crate fory_derive

Crate fory_derive 

Source
Expand description

§Fory Derive Macros

This crate provides procedural macros for the Fory serialization framework. It generates serialization and deserialization code for Rust types. Most applications should import these macros from the fory facade crate, which also provides the runtime API used by generated code. Direct fory-derive usage is for crates that intentionally depend on the lower-level fory-core runtime crate.

§Available Macros

§#[derive(ForyStruct)], #[derive(ForyEnum)], #[derive(ForyUnion)]

Generates Serializer implementations for structs, pure enums, and tagged unions with payload variants.

Supported Types:

  • ForyStruct: named, tuple, and unit structs
  • ForyEnum: pure unit enums
  • ForyUnion: enums with payload variants

Example:

use fory_derive::{ForyEnum, ForyStruct};
use std::collections::HashMap;

#[derive(ForyStruct, Debug, PartialEq)]
struct Person {
    name: String,
    age: i32,
    address: Address,
    hobbies: Vec<String>,
    metadata: HashMap<String, String>,
}

#[derive(ForyStruct, Debug, PartialEq)]
struct Address {
    street: String,
    city: String,
}

#[derive(ForyEnum, Debug, PartialEq, Default)]
enum Status {
    #[default]
    Active,
    Inactive,
    Suspended,
}

§#[derive(ForyRow)]

Generates Standard Row Format serialization and borrowed field views for a named struct. The macro implements RowValue and the root Row marker. Enums, unions, tuple structs, and unit structs are rejected at compile time.

Supported Types:

  • Fixed values: bool, i8, i16, i32, i64, f32, f64, Date, Timestamp, and Duration
  • Variable values: String and &str, binary Vec<u8> and &[u8], fixed and variable arrays, BTreeMap, and other derived row structs
  • Option<T> for nullable fields and array elements
  • Every field type must implement RowValue

Example:

use fory_core::error::Error;
use fory_core::row::{from_row, to_row};
use fory_derive::ForyRow;

#[derive(ForyRow)]
struct UserProfile {
    id: i64,
    username: String,
    email: Option<String>,
}

let bytes = to_row(&UserProfile {
    id: 7,
    username: "fory".to_owned(),
    email: None,
})?;
let view = from_row::<UserProfile>(&bytes)?;
assert_eq!(view.id()?, 7);
assert_eq!(view.username()?, "fory");
assert_eq!(view.email()?, None);

§Generated Code

§For #[derive(ForyStruct)], #[derive(ForyEnum)], and #[derive(ForyUnion)]

The macro generates:

  • Serializer trait implementation
  • Serialization methods for writing data to buffers
  • Deserialization methods for reading data from buffers
  • Type ID management for cross-language compatibility

§For #[derive(ForyRow)]

The macro generates:

  • A RowValue implementation and a root Row marker implementation
  • A borrowed view type whose visibility matches the source struct
  • RowView backing-byte access and cheap Copy/Clone views
  • One declaration-order field method preserving each source field’s visibility
  • Field methods returning Result<<Field as RowValue>::View<'_>, Error>

§Attributes

  • #[fory(debug)] / #[fory(debug = true)]: Enables per-field debug instrumentation for the annotated struct, allowing you to install custom hooks via fory_core::serializer::struct_.
  • #[fory(evolving = false)]: Disables compatible struct type IDs for the annotated struct, forcing STRUCT/NAMED_STRUCT even when compatible mode is enabled.
  • #[fory(skip)]: Marks an individual field (or enum variant) to be ignored by the generated serializer, retaining compatibility with previous releases.
  • #[fory(generate_default)]: Enables the macro to generate Default implementation. By default, ForyStruct does NOT generate impl Default to avoid conflicts with existing Default implementations. This attribute is not valid with target.
  • #[fory(target = path::Type)]: Makes the derived declaration an external structural serializer for the target type. Generated code accesses and constructs the target directly; the serializer declaration itself is never instantiated.
  • #[fory(with = SerializerType)]: Selects a serializer whose target is the exact field value node. Use carrier serializers for exact wrapper or container nodes, and use list, map, or tuple metadata to select serializers recursively at child nodes.
  • #[fory(default)]: Marks the fallible deserialization default ForyUnion variant. ForyUnion requires exactly one default variant.

§Field Types

The object-format derives support a wide range of field types:

Primitive Types:

  • bool, i8, i16, i32, i64, f32, f64
  • String
  • Vec<u8> for binary data

Collections:

  • Vec<T> where T implements the appropriate trait
  • HashMap<K, V> and BTreeMap<K, V> where keys and values implement the trait
  • Option<T> for nullable values

Date/Time:

  • fory::Date
  • fory::Timestamp
  • fory::Duration
  • chrono::NaiveDate, chrono::NaiveDateTime, and chrono::Duration when the chrono feature is enabled

Custom Types:

  • Any type that implements Serializer

ForyRow uses the separate, exact type set documented under its macro section. A row field implements RowValue; only derived structs, arrays, and maps implement the root Row marker.

Derived structs, enums, and unions can be used behind Arc<dyn Any + Send + Sync> when the concrete type satisfies Send + Sync. Known non-Send + Sync field types such as Rc<T> and RefCell<T> are not eligible for that carrier.

§Usage with Fory

After deriving the macros, you can use the types with the Fory serialization framework:

use fory_core::{fory::Fory, error::Error};
use fory_derive::{ForyEnum, ForyStruct, ForyUnion};

#[derive(ForyStruct, Debug, PartialEq)]
struct MyData {
    value: i32,
    text: String,
}

fn main() -> Result<(), Error> {
    let mut fory = Fory::builder().xlang(true).build();
    fory.register_by_name::<MyData>("example.MyData")?;
     
    let data = MyData {
        value: 42,
        text: "Hello, Fory!".to_string(),
    };
     
    let serialized = fory.serialize(&data)?;
    let deserialized: MyData = fory.deserialize(&serialized)?;
     
    assert_eq!(data, deserialized);
    Ok(())
}

§Performance Considerations

  • Fory: Best for complex object graphs with references and nested structures
  • ForyRow: Provides lazy, borrowed access to Standard Row Format data
  • Both macros generate optimized code with minimal runtime overhead

Derive Macros§

ForyEnum
Derive macro for pure enum serialization.
ForyRow
Derive macro for Standard Row Format serialization.
ForyStruct
Derive macro for struct serialization.
ForyUnion
Derives serialization for data-carrying Rust enums.