Skip to main content
Version: dev

Rust

Output Layout

Rust output is one module file per schema, for example:

  • <rust_out>/addressbook.rs

When --grpc is used and the schema contains services, Rust also emits:

  • <rust_out>/addressbook_service.rs
  • <rust_out>/addressbook_service_grpc.rs

Type Generation

Unions map to Rust enums with #[fory(id = ...)] schema case attributes. #[fory(unknown)] Unknown(::fory::UnknownCase) marks the Fory-provided forward-compatibility carrier. The marker only selects the carrier and does not add an entry to the schema case table; schema cases still use the full 0..N ID range. A generated typed union must have at least one non-Unknown case. The compiler marks the first declared non-Unknown case as #[fory(default)]. When that case's payload implements Rust's standard Default trait, the compiler also emits a standard Default implementation from that case:

#[derive(::fory::ForyUnion, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Animal {
#[fory(unknown)]
Unknown(::fory::UnknownCase),
#[fory(id = 0, default)]
Dog(self::Dog),
#[fory(id = 1)]
Cat(self::Cat),
}

impl ::std::default::Default for Animal {
fn default() -> Self {
Self::Dog(<self::Dog as ::std::default::Default>::default())
}
}

If the selected payload does not implement standard Default, such as an any payload, the generated union has no infallible Default implementation. This model-level default is independent of Fory's fallible deserialization default, which reconstructs the selected case through its codecs and active read context.

Nested types generate nested modules:

pub mod person {
#[derive(ForyEnum, Debug, Clone, PartialEq, Default)]
#[repr(i32)]
pub enum PhoneType {
#[default]
Mobile = 0,
Home = 1,
Work = 2,
}

#[derive(ForyStruct, Debug, Clone, PartialEq, Default)]
pub struct PhoneNumber {
#[fory(id = 1)]
pub number: String,
#[fory(id = 2)]
pub phone_type: PhoneType,
}
}

Messages derive ForyStruct and include to_bytes/from_bytes helpers:

#[derive(ForyStruct, Debug, Clone, PartialEq, Default)]
pub struct Person {
#[fory(id = 1)]
pub name: String,
#[fory(id = 7)]
pub phones: Vec<person::PhoneNumber>,
#[fory(id = 8)]
pub pet: Animal,
}

Registration

Generated registration function:

pub fn register_types(fory: &mut Fory) -> Result<(), fory::Error> {
fory.register_union::<Animal>(106)?;
fory.register::<person::PhoneType>(101)?;
fory.register::<person::PhoneNumber>(102)?;
fory.register::<Person>(100)?;
fory.register::<Dog>(104)?;
fory.register::<Cat>(105)?;
fory.register::<AddressBook>(103)?;
Ok(())
}

For schemas without explicit [id=...], generated registration uses computed numeric IDs:

fory.register::<Status>(1124725126)?;
fory.register_union::<Wrapper>(1471345060)?;
fory.register::<Envelope>(3022445236)?;
fory.register_union::<envelope::Detail>(1609214087)?;
fory.register::<envelope::Payload>(2862577837)?;

If option enable_auto_type_id = false; is set:

fory.register_by_name::<Config>("myapp.models.Config")?;
fory.register_union_by_name::<Holder>("myapp.models.Holder")?;

Usage

let person = Person {
name: "Alice".into(),
pet: Animal::Dog(self::Dog::default()),
..Default::default()
};

let bytes = person.to_bytes()?;
let restored = Person::from_bytes(&bytes)?;

gRPC Service Companions

With --grpc, Rust emits <module>_service.rs for the async service trait and path constants, and <module>_service_grpc.rs for tonic clients, servers, codecs, and ForyGrpcPayload implementations backed by the model's to_bytes and from_bytes helpers. See Rust gRPC for dependencies and usage.