#[derive(ConstWriteXDR)]
{
// Attributes available to this derive:
#[xdr]
#[xdrs]
}
derive only.Expand description
Derives const-compatible XDR encoding methods for compile-time use.
Generates four inherent const fn methods on the type:
const_write_cxs<const N: usize>(&self, w: &mut cxs::ConstWriter<N>)const_write_txs<const N: usize>(&self, w: &mut txs::ConstWriter<N>)const_cxs_size(&self) -> usizeconst_txs_size(&self) -> usize
These methods can be used in const blocks to encode values at compile time.
The size methods allow the buffer size to be derived automatically:
static ENCODED: [u8; MY_VAL.const_txs_size()] = {
let mut w = xdrs::txs::ConstWriter::<{ MY_VAL.const_txs_size() }>::new();
MY_VAL.const_write_txs(&mut w);
w.into_bytes()
};For worst-case size bounds over all values of a type (buffer sizing
before a value is known), see #[derive(ConstXDRSize)].
§Limitations
- Does not support
#[xdr(into_type)]or#[xdr(via)]attributes on the derive input, struct fields, or enum variant fields. Thevia/into_typeconversions requireInto::into()which is notconst fn. - Supports lifetime and const generics, but not type parameters
- Field types may use recursive concrete shapes inline, including
Option<T>,Result<T, E>,&[T],[T; N],Box<T>,VecM<T, MAX>,BytesM<MAX>,StringM<MAX>, and tuples, as long as leaf types are concrete and const-encodable - With the
allocfeature, non-emptyVecM/BytesM/StringMvalues cannot be constructed in const contexts (const heap allocation is not possible), so const encoding of non-empty values of these types is only available in no-allocbuilds, where they wrap&'static [T] - Likewise
Box<T>values can only be constructed in const contexts in no-allocbuilds, whereBox::newis const and the value is inline; withallocthe generated methods still compile and run at runtime
§Generated code hygiene
The generated const fn methods are syntax-directed: type recognition uses
raw identifiers rather than Rust’s resolved types, and generated code emits
unqualified names into the call site scope. This means:
- Use bare primitive names.
u32is recognized;core::primitive::u32is not and will be treated as a named leaf type. - Do not shadow built-in types. A local
type u8 = MyType;will cause the opaque byte fast-path to misfire. Similarly, shadowingstrwill confuse string detection. - Length guards use
::core::assert!()to resist call-site macro shadowing. - Do not use
__N-prefixed names in discriminant expressions. The generated methods introduce a buffer-size const generic with an__N-prefixed name; discriminant expressions referencing a same-named constant will resolve to the wrong binding. - Avoid naming const generics
i,arr,slice, ortotal. The generated array/slice iteration uses these as local bindings, and Rust does not allow aletbinding to shadow an in-scope const parameter. - Avoid naming modules
cxsortxsin discriminant paths. The generated const block importsuse xdrs::cxs; use xdrs::txs;, which can capture discriminant expressions whose paths start with those segments.
§Standard library type recognition
The macro recognizes Option, Result, Box, PhantomData, Infallible,
and the xdr_common container types VecM, BytesM, and StringM by their
last path segment (e.g. both Option<T> and std::option::Option<T>
match). This is a syntactic check — type aliases are not resolved. A field
declared as type MyOpt = Option<Foo>; .. my_field: MyOpt will not be
recognized as an Option and will instead be treated as a named leaf whose
type must provide its own const_cxs_size / const_write_cxs / etc. inherent
methods (i.e. it must itself derive ConstWriteXDR or provide them manually).
The same applies to PhantomData — if you need a type-alias, wrap it in a
newtype and derive ConstWriteXDR on the newtype instead.