Expand description
§thalassa-derive
§Description
Derives for thalassa
Note: A lot of this is similar to tls_codec’s derives, in an effort to ease migration between the derives/attrs
§Attributes
§On Enums
#[tlspl(untagged)]- Marks that this enum contents should not be de/serialized preceded by their discriminant. This is especially useful when using the#[tlspl(select)]attribute#[tlspl(extensible)]- This marks an enum as “extensible”, meaning that the contents of the variants (eg. its fields) will be serialized as a variable-length bytes container, to ensure that it can be extended, serialized and deserialized even in the case of future evolutions or downstream-defined extensions. This is inspired by how MLS (RFC9420) Extensions are done.
§On Enum Variants
#[tlspl(discrmininant = "path::to::constant"|1337)]- Allows to point to a discriminant tag for cases where it’s not supported by the Rust language (eg complex data types/structs where explicit discriminant isn’t allowed).- This also supports the following forms
- integer literals:
#[tlspl(discriminant = 69)] - constants:
#[tlspl(discriminant = "MY_CONST")]- note: wrapped in a string - enum variants that have an explicit discriminant:
#[tlspl(discriminant = "MyEnum::CaseN")]- note: wrapped in a string
- integer literals:
- This also supports the following forms
#[tlspl(other)]- Marks a “catch-all” or “unknown” variant that needs to be a tuple having 1 field equal to the #[repr] of the enum (for naked enums), or 2 fields equal to(repr, Cow<[u8]>)(for enums that have data)- Example
ⓘ
#[derive(TlsplSize, TlsplDeserialize, TlsplSerialize)]
#[repr(u8)]
enum Thing {
CaseA = 0,
CaseB = 1,
#[tlspl(other)]
Unknown(u8)
}
#[derive(TlsplSize, TlsplDeserialize, TlsplSerialize)]
#[tlspl(extensible)]
#[repr(u8)]
enum ThingWithData<'a> {
#[tlspl(discriminant = "Thing::CaseA")]
CaseA {
name: std::borrow::Cow<'a, str>,
},
#[tlspl(discriminant = "Thing::CaseB")]
CaseB {
flag: bool
},
#[tlspl(other)]
Unknown(u8, std::borrow::Cow<'a, [u8]>),
}§On Fields
#[tlspl(skip)]- Skips this field during both serialization and deserialization. RequiresDefaultto be implemented on the field since this data format has a fixed data layout.#[tlspl(with = path::to::module)]- Allows to override the ser/deser implementation of the underlying type with a custom implementation. The module should export any of those functions, depending on which trait your’re deriving:tlspl_serialized_len(&T) -> usizetlspl_serialize_to(&T, writer) -> TlsplWriteResult<usize>tlspl_deserialize_from(reader) -> TlsplReadResult<T>
#[tlspl(select = field.member.thing)]- mirrors theselectkeyword in TLSPL prose found in specifications.- Restrictions
- The targeted field must be declared BEFORE this field. The order of declaration matters in TLSPL.
- The type of the field with this attribute must be an enum that has
#[tlspl(untagged)]
- Example
- Restrictions
ⓘ
#[derive(TlsplAll)]
#[repr(u8)]
pub enum FieldDiscriminant {
Variant1 = 0x01,
Variant2 = 0x02,
}
#[derive(TlsplAll)]
#[tlspl(untagged)]
pub enum FieldContents {
#[tlspl(discriminant = "FieldDiscriminant::Variant1")]
Variant1,
#[tlspl(discriminant = "FieldDiscriminant::Variant2")]
Variant2 {
thing: bool,
}
}
#[derive(TlsplAll)]
pub struct ComplexStructure<'a> {
pub field_type: FieldDiscriminant,
pub unrelated_field: u64,
pub another_field: Cow<'a, [u8]>,
#[tlspl(select = field_type)]
pub field_contents: FieldContents,
}- Enum Variants