Skip to main content

miden_field_repr/
lib.rs

1//! Serialization/deserialization for felt representation.
2//!
3//! This crate provides traits and utilities for converting Rust types to and from
4//! a sequence of [`Felt`] elements.
5
6#![no_std]
7#![deny(warnings)]
8
9extern crate alloc;
10
11use alloc::vec::Vec;
12
13pub use miden_field::Felt;
14/// Re-export `DeriveFromFeltRepr` as `FromFeltRepr` for `#[derive(FromFeltRepr)]` ergonomics.
15pub use miden_field_repr_derive::DeriveFromFeltRepr as FromFeltRepr;
16/// Re-export `DeriveToFeltRepr` as `ToFeltRepr` for `#[derive(ToFeltRepr)]` ergonomics.
17pub use miden_field_repr_derive::DeriveToFeltRepr as ToFeltRepr;
18
19/// A reader that wraps a slice of `Felt` elements and tracks the current position.
20pub struct FeltReader<'a> {
21    data: &'a [Felt],
22    pos: usize,
23}
24
25impl<'a> FeltReader<'a> {
26    /// Creates a new `FeltReader` from a slice of `Felt` elements.
27    #[inline(always)]
28    pub fn new(data: &'a [Felt]) -> Self {
29        Self { data, pos: 0 }
30    }
31
32    /// Reads the next `Felt` element, advancing the position.
33    ///
34    /// # Panics
35    ///
36    /// Panics if there are no more elements to read.
37    #[inline(always)]
38    pub fn read(&mut self) -> Felt {
39        assert!(self.pos < self.data.len(), "FeltReader: no more elements to read");
40        let felt = self.data[self.pos];
41        self.pos += 1;
42        felt
43    }
44}
45
46/// A writer that wraps a `Vec<Felt>` and appends elements to it.
47pub struct FeltWriter<'a> {
48    data: &'a mut Vec<Felt>,
49}
50
51impl<'a> FeltWriter<'a> {
52    /// Creates a new `FeltWriter` from a mutable reference to a `Vec<Felt>`.
53    #[inline(always)]
54    pub fn new(data: &'a mut Vec<Felt>) -> Self {
55        Self { data }
56    }
57
58    /// Writes a `Felt` element to the output.
59    #[inline(always)]
60    pub fn write(&mut self, felt: Felt) {
61        self.data.push(felt);
62    }
63}
64
65/// Trait for deserialization from felt memory representation.
66pub trait FromFeltRepr: Sized {
67    /// Deserializes from a `FeltReader`, consuming the required elements.
68    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self;
69}
70
71impl FromFeltRepr for Felt {
72    #[inline(always)]
73    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
74        reader.read()
75    }
76}
77
78#[cfg(not(target_family = "wasm"))]
79impl FromFeltRepr for miden_core::Felt {
80    #[inline(always)]
81    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
82        Self::from(reader.read())
83    }
84}
85
86impl FromFeltRepr for u64 {
87    #[inline(always)]
88    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
89        // Encode u64 as 2 u32 limbs
90        let lo = reader.read().as_u64();
91        assert!(lo <= u32::MAX as u64, "u64: low limb out of range");
92        let hi = reader.read().as_u64();
93        assert!(hi <= u32::MAX as u64, "u64: high limb out of range");
94
95        (hi << 32) | lo
96    }
97}
98
99impl FromFeltRepr for u32 {
100    #[inline(always)]
101    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
102        reader.read().as_u64() as u32
103    }
104}
105
106impl FromFeltRepr for u8 {
107    #[inline(always)]
108    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
109        reader.read().as_u64() as u8
110    }
111}
112
113impl FromFeltRepr for bool {
114    #[inline(always)]
115    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
116        reader.read().as_u64() != 0
117    }
118}
119
120/// Encodes an `Option<T>` as a 1-felt tag followed by the payload (if present).
121///
122/// Format:
123/// - `None` => `[0]`
124/// - `Some(x)` => `[1, x...]`
125impl<T> FromFeltRepr for Option<T>
126where
127    T: FromFeltRepr,
128{
129    #[inline(always)]
130    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
131        match reader.read().as_u64() {
132            0 => None,
133            1 => Some(T::from_felt_repr(reader)),
134            _ => panic!("Option: invalid tag"),
135        }
136    }
137}
138
139/// Encodes a `Vec<T>` as a length prefix followed by elements.
140///
141/// Format: `[len, elem0..., elemN-1...]` where `len` is a `u32` encoded in a single `Felt`.
142impl<T> FromFeltRepr for Vec<T>
143where
144    T: FromFeltRepr,
145{
146    #[inline(always)]
147    fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self {
148        let len = reader.read().as_u64();
149        assert!(len <= u32::MAX as u64, "Vec: length out of range");
150        let len = len as usize;
151
152        let mut result = Vec::with_capacity(len);
153
154        let mut i = 0usize;
155        while i < len {
156            result.push(T::from_felt_repr(reader));
157            i += 1;
158        }
159        result
160    }
161}
162
163/// Trait for serializing a type into its felt memory representation.
164pub trait ToFeltRepr {
165    /// Writes this value's felt representation to the writer.
166    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>);
167
168    /// Convenience method that allocates and returns a `Vec<Felt>`.
169    fn to_felt_repr(&self) -> Vec<Felt> {
170        // Allocate ahead to avoid reallocations
171        let mut data = Vec::with_capacity(256);
172        self.write_felt_repr(&mut FeltWriter::new(&mut data));
173        data
174    }
175}
176
177impl ToFeltRepr for Felt {
178    #[inline(always)]
179    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
180        writer.write(*self);
181    }
182}
183
184#[cfg(not(target_family = "wasm"))]
185impl ToFeltRepr for miden_core::Felt {
186    #[inline(always)]
187    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
188        writer.write((*self).into());
189    }
190}
191
192impl ToFeltRepr for u64 {
193    #[inline(always)]
194    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
195        let lo = (*self & 0xffff_ffff) as u32;
196        let hi = (*self >> 32) as u32;
197        writer.write(Felt::from_u32(lo));
198        writer.write(Felt::from_u32(hi));
199    }
200}
201
202impl ToFeltRepr for u32 {
203    #[inline(always)]
204    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
205        writer.write(Felt::from_u64_unchecked(*self as u64));
206    }
207}
208
209impl ToFeltRepr for u8 {
210    #[inline(always)]
211    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
212        writer.write(Felt::from_u64_unchecked(*self as u64));
213    }
214}
215
216impl ToFeltRepr for bool {
217    #[inline(always)]
218    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
219        writer.write(Felt::from_u64_unchecked(*self as u64));
220    }
221}
222
223/// Encodes an `Option<T>` as a 1-felt tag followed by the payload (if present).
224///
225/// Format:
226/// - `None` => `[0]`
227/// - `Some(x)` => `[1, x...]`
228impl<T> ToFeltRepr for Option<T>
229where
230    T: ToFeltRepr,
231{
232    #[inline(always)]
233    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
234        match self {
235            None => writer.write(Felt::from_u64_unchecked(0)),
236            Some(value) => {
237                writer.write(Felt::from_u64_unchecked(1));
238                value.write_felt_repr(writer);
239            }
240        }
241    }
242}
243
244/// Encodes a `Vec<T>` as a length prefix followed by elements.
245///
246/// Format: `[len, elem0..., elemN-1...]` where `len` is a `u32` encoded in a single `Felt`.
247impl<T> ToFeltRepr for Vec<T>
248where
249    T: ToFeltRepr,
250{
251    #[inline(always)]
252    fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
253        let len = self.len();
254        assert!(len <= u32::MAX as usize, "Vec: length out of range");
255        writer.write(Felt::from_u64_unchecked(len as u64));
256
257        let mut i = 0usize;
258        while i < len {
259            self[i].write_felt_repr(writer);
260            i += 1;
261        }
262    }
263}