1#![no_std]
7#![deny(warnings)]
8
9extern crate alloc;
10
11use alloc::vec::Vec;
12
13pub use miden_field::{Felt, Word};
14pub use miden_field_repr_derive::DeriveFromFeltRepr as FromFeltRepr;
16pub use miden_field_repr_derive::DeriveToFeltRepr as ToFeltRepr;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21#[non_exhaustive]
22pub enum FeltReprError {
23 UnexpectedEof {
25 pos: usize,
27 len: usize,
29 },
30 ValueOutOfRange {
32 pos: usize,
34 len: usize,
36 ty: &'static str,
38 value: u64,
40 max: u64,
42 },
43 InvalidOptionTag {
45 pos: usize,
47 len: usize,
49 tag: u64,
51 },
52 InvalidBool {
54 pos: usize,
56 len: usize,
58 value: u64,
60 },
61 UnknownEnumTag {
63 pos: usize,
65 len: usize,
67 ty: &'static str,
69 tag: u32,
71 },
72 TrailingData {
74 pos: usize,
76 len: usize,
78 },
79 Custom(&'static str),
81}
82
83impl core::fmt::Display for FeltReprError {
84 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85 match self {
86 Self::UnexpectedEof { pos, len } => {
87 write!(f, "unexpected end of input at felt {pos} of {len}")
88 }
89 Self::ValueOutOfRange {
90 pos,
91 len,
92 ty,
93 value,
94 max,
95 } => {
96 write!(f, "value {value} out of range for {ty} at felt {pos} of {len} (max {max})")
97 }
98 Self::InvalidOptionTag { pos, len, tag } => {
99 write!(f, "invalid Option tag at felt {pos} of {len}: {tag}")
100 }
101 Self::InvalidBool { pos, len, value } => {
102 write!(f, "invalid bool value at felt {pos} of {len}: {value}")
103 }
104 Self::UnknownEnumTag { pos, len, ty, tag } => {
105 write!(f, "unknown enum tag for {ty} at felt {pos} of {len}: {tag}")
106 }
107 Self::TrailingData { pos, len } => {
108 write!(f, "trailing data starting at felt {pos} of {len}")
109 }
110 Self::Custom(msg) => f.write_str(msg),
111 }
112 }
113}
114
115pub type FeltReprResult<T> = core::result::Result<T, FeltReprError>;
117
118pub struct FeltReader<'a> {
120 data: &'a [Felt],
121 pos: usize,
122}
123
124impl<'a> FeltReader<'a> {
125 #[inline(always)]
127 pub fn new(data: &'a [Felt]) -> Self {
128 Self { data, pos: 0 }
129 }
130
131 #[inline(always)]
133 pub fn pos(&self) -> usize {
134 self.pos
135 }
136
137 #[inline(always)]
139 pub fn len(&self) -> usize {
140 self.data.len()
141 }
142
143 #[inline(always)]
145 pub fn is_empty(&self) -> bool {
146 self.data.is_empty()
147 }
148
149 #[inline(always)]
151 pub fn remaining(&self) -> usize {
152 self.data.len().saturating_sub(self.pos)
153 }
154
155 #[inline(always)]
157 pub fn ensure_eof(&self) -> FeltReprResult<()> {
158 if self.remaining() != 0 {
159 return Err(FeltReprError::TrailingData {
160 pos: self.pos,
161 len: self.data.len(),
162 });
163 }
164 Ok(())
165 }
166
167 #[inline(always)]
169 pub fn read(&mut self) -> FeltReprResult<Felt> {
170 if self.pos >= self.data.len() {
171 return Err(FeltReprError::UnexpectedEof {
172 pos: self.pos,
173 len: self.data.len(),
174 });
175 }
176
177 let felt = self.data[self.pos];
178 self.pos += 1;
179 Ok(felt)
180 }
181
182 #[inline(always)]
184 pub fn read_u32(&mut self) -> FeltReprResult<u32> {
185 let pos = self.pos;
186 let len = self.data.len();
187 let value = self.read()?.as_canonical_u64();
188 if value > u32::MAX as u64 {
189 return Err(FeltReprError::ValueOutOfRange {
190 pos,
191 len,
192 ty: "u32",
193 value,
194 max: u32::MAX as u64,
195 });
196 }
197 Ok(value as u32)
198 }
199
200 #[inline(always)]
202 pub fn read_u8(&mut self) -> FeltReprResult<u8> {
203 let pos = self.pos;
204 let len = self.data.len();
205 let value = self.read()?.as_canonical_u64();
206 if value > u8::MAX as u64 {
207 return Err(FeltReprError::ValueOutOfRange {
208 pos,
209 len,
210 ty: "u8",
211 value,
212 max: u8::MAX as u64,
213 });
214 }
215 Ok(value as u8)
216 }
217
218 #[inline(always)]
222 pub fn read_bool(&mut self) -> FeltReprResult<bool> {
223 let pos = self.pos;
224 let len = self.data.len();
225 match self.read()?.as_canonical_u64() {
226 0 => Ok(false),
227 1 => Ok(true),
228 value => Err(FeltReprError::InvalidBool { pos, len, value }),
229 }
230 }
231
232 #[inline(always)]
236 pub fn read_len_u32(&mut self) -> FeltReprResult<usize> {
237 Ok(self.read_u32()? as usize)
238 }
239}
240
241pub struct FeltWriter<'a> {
243 data: &'a mut Vec<Felt>,
244}
245
246impl<'a> FeltWriter<'a> {
247 #[inline(always)]
249 pub fn new(data: &'a mut Vec<Felt>) -> Self {
250 Self { data }
251 }
252
253 #[inline(always)]
255 pub fn write(&mut self, felt: Felt) {
256 self.data.push(felt);
257 }
258}
259
260#[doc(hidden)]
266pub const fn sum_fixed_len(lens: &[Option<usize>]) -> Option<usize> {
267 let mut total = 0usize;
268 let mut i = 0;
269 while i < lens.len() {
270 match lens[i] {
271 Some(len) => total += len,
272 None => return None,
273 }
274 i += 1;
275 }
276 Some(total)
277}
278
279#[doc(hidden)]
284pub const fn uniform_fixed_len(lens: &[Option<usize>]) -> Option<usize> {
285 if lens.is_empty() {
286 return Some(0);
287 }
288 let first = match lens[0] {
289 Some(len) => len,
290 None => return None,
291 };
292 let mut i = 1;
293 while i < lens.len() {
294 match lens[i] {
295 Some(len) => {
296 if len != first {
297 return None;
298 }
299 }
300 None => return None,
301 }
302 i += 1;
303 }
304 Some(first)
305}
306
307pub trait FromFeltRepr: Sized {
309 const FIXED_LEN: Option<usize> = None;
321
322 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self>;
324}
325
326impl FromFeltRepr for Felt {
327 const FIXED_LEN: Option<usize> = Some(1);
328
329 #[inline(always)]
330 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
331 reader.read()
332 }
333}
334
335impl FromFeltRepr for Word {
337 const FIXED_LEN: Option<usize> = Some(4);
338
339 #[inline(always)]
340 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
341 let a = reader.read()?;
342 let b = reader.read()?;
343 let c = reader.read()?;
344 let d = reader.read()?;
345 Ok(Word::new([a, b, c, d]))
346 }
347}
348
349impl FromFeltRepr for u64 {
350 const FIXED_LEN: Option<usize> = Some(2);
351
352 #[inline(always)]
353 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
354 let lo = reader.read_u32()? as u64;
356 let hi = reader.read_u32()? as u64;
357 Ok((hi << 32) | lo)
358 }
359}
360
361impl FromFeltRepr for u32 {
362 const FIXED_LEN: Option<usize> = Some(1);
363
364 #[inline(always)]
365 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
366 reader.read_u32()
367 }
368}
369
370impl FromFeltRepr for u8 {
371 const FIXED_LEN: Option<usize> = Some(1);
372
373 #[inline(always)]
374 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
375 reader.read_u8()
376 }
377}
378
379impl FromFeltRepr for bool {
380 const FIXED_LEN: Option<usize> = Some(1);
381
382 #[inline(always)]
383 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
384 reader.read_bool()
385 }
386}
387
388impl<T> FromFeltRepr for Option<T>
394where
395 T: FromFeltRepr,
396{
397 #[inline(always)]
398 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
399 let pos = reader.pos();
400 let len = reader.len();
401 match reader.read()?.as_canonical_u64() {
402 0 => Ok(None),
403 1 => Ok(Some(T::from_felt_repr(reader)?)),
404 tag => Err(FeltReprError::InvalidOptionTag { pos, len, tag }),
405 }
406 }
407}
408
409impl<T> FromFeltRepr for Vec<T>
413where
414 T: FromFeltRepr,
415{
416 #[inline(always)]
417 fn from_felt_repr(reader: &mut FeltReader<'_>) -> FeltReprResult<Self> {
418 let len = reader.read_len_u32()?;
419
420 let mut result = match T::FIXED_LEN {
423 Some(width) if width > 0 => match len.checked_mul(width) {
424 Some(total) if total <= reader.remaining() => Vec::with_capacity(len),
425 _ => {
426 return Err(FeltReprError::UnexpectedEof {
427 pos: reader.pos(),
428 len: reader.len(),
429 });
430 }
431 },
432 _ => Vec::new(),
433 };
434
435 let mut i = 0usize;
436 while i < len {
437 result.push(T::from_felt_repr(reader)?);
438 i += 1;
439 }
440 Ok(result)
441 }
442}
443
444pub trait ToFeltRepr {
446 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>);
448
449 fn to_felt_repr(&self) -> Vec<Felt> {
451 let mut data = Vec::with_capacity(256);
453 self.write_felt_repr(&mut FeltWriter::new(&mut data));
454 data
455 }
456}
457
458impl ToFeltRepr for Felt {
459 #[inline(always)]
460 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
461 writer.write(*self);
462 }
463}
464
465impl ToFeltRepr for Word {
467 #[inline(always)]
468 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
469 for felt in self.as_elements() {
470 writer.write(*felt);
471 }
472 }
473}
474
475impl ToFeltRepr for u64 {
476 #[inline(always)]
477 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
478 let lo = (*self & 0xffff_ffff) as u32;
479 let hi = (*self >> 32) as u32;
480 writer.write(Felt::new(lo as u64).unwrap());
481 writer.write(Felt::new(hi as u64).unwrap());
482 }
483}
484
485impl ToFeltRepr for u32 {
486 #[inline(always)]
487 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
488 writer.write(Felt::new(*self as u64).unwrap());
489 }
490}
491
492impl ToFeltRepr for u8 {
493 #[inline(always)]
494 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
495 writer.write(Felt::new(*self as u64).unwrap());
496 }
497}
498
499impl ToFeltRepr for bool {
500 #[inline(always)]
501 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
502 writer.write(Felt::new(*self as u64).unwrap());
503 }
504}
505
506impl<T> ToFeltRepr for Option<T>
512where
513 T: ToFeltRepr,
514{
515 #[inline(always)]
516 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
517 match self {
518 None => writer.write(Felt::new(0).unwrap()),
519 Some(value) => {
520 writer.write(Felt::new(1).unwrap());
521 value.write_felt_repr(writer);
522 }
523 }
524 }
525}
526
527impl<T> ToFeltRepr for Vec<T>
531where
532 T: ToFeltRepr,
533{
534 #[inline(always)]
535 fn write_felt_repr(&self, writer: &mut FeltWriter<'_>) {
536 let len = self.len();
537 assert!(len <= u32::MAX as usize, "Vec: length out of range");
538 writer.write(Felt::new(len as u64).unwrap());
539
540 let mut i = 0usize;
541 while i < len {
542 self[i].write_felt_repr(writer);
543 i += 1;
544 }
545 }
546}