Skip to main content

facet_xdr/
lib.rs

1//! XDR (External Data Representation) format support via facet-format.
2//!
3//! XDR is a binary format defined in RFC 4506 for encoding structured data.
4//! It is primarily used in Sun RPC (ONC RPC) protocols.
5//!
6//! Key characteristics:
7//! - Big-endian byte order
8//! - Fixed-size integers (4 bytes for i32/u32, 8 bytes for i64/u64)
9//! - No support for i128/u128
10//! - Strings are length-prefixed with 4-byte aligned padding
11//! - Arrays have explicit length prefixes
12//!
13//! # Serialization
14//!
15//! ```
16//! use facet::Facet;
17//! use facet_xdr::to_vec;
18//!
19//! #[derive(Facet)]
20//! struct Point { x: i32, y: i32 }
21//!
22//! let point = Point { x: 10, y: 20 };
23//! let bytes = to_vec(&point).unwrap();
24//! ```
25//!
26//! # Deserialization
27//!
28//! ```
29//! use facet::Facet;
30//! use facet_xdr::from_slice;
31//!
32//! #[derive(Facet, Debug, PartialEq)]
33//! struct Point { x: i32, y: i32 }
34//!
35//! // XDR encoding of Point { x: 10, y: 20 }
36//! let bytes = &[0, 0, 0, 10, 0, 0, 0, 20];
37//! let point: Point = from_slice(bytes).unwrap();
38//! assert_eq!(point.x, 10);
39//! assert_eq!(point.y, 20);
40//! ```
41
42#![forbid(unsafe_code)]
43
44extern crate alloc;
45
46mod error;
47mod parser;
48mod serializer;
49
50pub use error::{XdrError, XdrSerializeError};
51pub use parser::XdrParser;
52pub use serializer::{XdrSerializer, to_vec, to_writer};
53
54// Re-export DeserializeError for convenience
55pub use facet_format::DeserializeError;
56
57/// Deserialize a value from XDR bytes into an owned type.
58///
59/// This is the recommended default for most use cases.
60///
61/// # Example
62///
63/// ```
64/// use facet::Facet;
65/// use facet_xdr::from_slice;
66///
67/// #[derive(Facet, Debug, PartialEq)]
68/// struct Point { x: i32, y: i32 }
69///
70/// // XDR encoding of Point { x: 10, y: 20 }
71/// let bytes = &[0, 0, 0, 10, 0, 0, 0, 20];
72/// let point: Point = from_slice(bytes).unwrap();
73/// assert_eq!(point.x, 10);
74/// assert_eq!(point.y, 20);
75/// ```
76pub fn from_slice<T>(input: &[u8]) -> Result<T, DeserializeError<XdrError>>
77where
78    T: facet_core::Facet<'static>,
79{
80    use facet_format::FormatDeserializer;
81    let parser = XdrParser::new(input);
82    let mut de = FormatDeserializer::new_owned(parser);
83    de.deserialize()
84}
85
86/// Deserialize a value from XDR bytes, allowing zero-copy borrowing.
87///
88/// This variant requires the input to outlive the result (`'input: 'facet`),
89/// enabling zero-copy deserialization of byte slices as `&[u8]` or `Cow<[u8]>`.
90///
91/// # Example
92///
93/// ```
94/// use facet::Facet;
95/// use facet_xdr::from_slice_borrowed;
96/// use std::borrow::Cow;
97///
98/// #[derive(Facet, Debug, PartialEq)]
99/// struct Message<'a> {
100///     id: u32,
101///     #[facet(sensitive)]
102///     data: Cow<'a, [u8]>,
103/// }
104///
105/// // XDR encoding of Message { id: 1, data: [0xAB, 0xCD, 0xEF] }
106/// // id (4 bytes) + data length (4 bytes) + data (3 bytes) + padding (1 byte)
107/// let bytes = &[0, 0, 0, 1, 0, 0, 0, 3, 0xAB, 0xCD, 0xEF, 0];
108/// let msg: Message = from_slice_borrowed(bytes).unwrap();
109/// assert_eq!(msg.id, 1);
110/// assert_eq!(&*msg.data, &[0xAB, 0xCD, 0xEF]);
111/// ```
112pub fn from_slice_borrowed<'input, 'facet, T>(
113    input: &'input [u8],
114) -> Result<T, DeserializeError<XdrError>>
115where
116    T: facet_core::Facet<'facet>,
117    'input: 'facet,
118{
119    use facet_format::FormatDeserializer;
120    let parser = XdrParser::new(input);
121    let mut de = FormatDeserializer::new(parser);
122    de.deserialize()
123}