1use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
2
3use miden_core::{
4 Word,
5 advice::AdviceMap,
6 mast::{MastForest, MastNodeExt, MastNodeId},
7 program::Kernel,
8 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
9};
10use midenc_hir_type::{FunctionType, Type};
11#[cfg(feature = "arbitrary")]
12use proptest::prelude::*;
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15use smallvec::SmallVec;
16
17use crate::ast::{AttributeSet, Ident, Path, PathBuf, ProcedureName};
18
19mod error;
20mod module;
21
22pub use module::{ConstantInfo, ItemInfo, ModuleInfo, ProcedureInfo, TypeInfo};
23pub use semver::{Error as VersionError, Version};
24
25pub use self::error::LibraryError;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
34pub enum LibraryExport {
35 Procedure(ProcedureExport),
36 Constant(ConstantExport),
37 Type(TypeExport),
38}
39
40impl LibraryExport {
41 pub fn path(&self) -> Arc<Path> {
42 match self {
43 Self::Procedure(export) => export.path.clone(),
44 Self::Constant(export) => export.path.clone(),
45 Self::Type(export) => export.path.clone(),
46 }
47 }
48
49 pub fn as_procedure(&self) -> Option<&ProcedureExport> {
50 match self {
51 Self::Procedure(proc) => Some(proc),
52 Self::Constant(_) | Self::Type(_) => None,
53 }
54 }
55
56 pub fn unwrap_procedure(&self) -> &ProcedureExport {
57 match self {
58 Self::Procedure(proc) => proc,
59 Self::Constant(_) | Self::Type(_) => panic!("expected export to be a procedure"),
60 }
61 }
62}
63
64impl From<ProcedureExport> for LibraryExport {
65 fn from(value: ProcedureExport) -> Self {
66 Self::Procedure(value)
67 }
68}
69
70impl From<ConstantExport> for LibraryExport {
71 fn from(value: ConstantExport) -> Self {
72 Self::Constant(value)
73 }
74}
75
76impl From<TypeExport> for LibraryExport {
77 fn from(value: TypeExport) -> Self {
78 Self::Type(value)
79 }
80}
81
82#[cfg(feature = "arbitrary")]
83impl Arbitrary for LibraryExport {
84 type Parameters = ();
85
86 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
87 use proptest::{arbitrary::any, prop_oneof, strategy::Strategy};
88
89 prop_oneof![
90 any::<ProcedureExport>().prop_map(Self::Procedure),
91 any::<ConstantExport>().prop_map(Self::Constant),
92 any::<TypeExport>().prop_map(Self::Type),
93 ]
94 .boxed()
95 }
96
97 type Strategy = BoxedStrategy<Self>;
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
101#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
102#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
103pub struct ProcedureExport {
104 pub node: MastNodeId,
106 #[cfg_attr(feature = "serde", serde(with = "crate::ast::path"))]
108 pub path: Arc<Path>,
109 #[cfg_attr(feature = "serde", serde(default))]
111 pub signature: Option<FunctionType>,
112 #[cfg_attr(feature = "serde", serde(default))]
113 pub attributes: AttributeSet,
114}
115
116impl ProcedureExport {
117 pub fn new(node: MastNodeId, path: Arc<Path>) -> Self {
119 Self {
120 node,
121 path,
122 signature: None,
123 attributes: Default::default(),
124 }
125 }
126
127 pub fn with_signature(mut self, signature: FunctionType) -> Self {
129 self.signature = Some(signature);
130 self
131 }
132
133 pub fn with_attributes(mut self, attrs: AttributeSet) -> Self {
135 self.attributes = attrs;
136 self
137 }
138}
139
140#[cfg(feature = "arbitrary")]
141impl Arbitrary for ProcedureExport {
142 type Parameters = ();
143
144 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
145 use proptest::collection::vec as prop_vec;
146
147 let simple_type = prop_oneof![Just(Type::Felt), Just(Type::U32), Just(Type::U64),];
149
150 let params = prop_vec(simple_type.clone(), 0..=4);
152 let results = prop_vec(simple_type, 0..=2);
153
154 let abi = Just(midenc_hir_type::CallConv::Fast);
156
157 let signature =
159 prop::option::of((abi, params, results).prop_map(|(abi, params_vec, results_vec)| {
160 let params = SmallVec::<[Type; 4]>::from_vec(params_vec);
161 let results = SmallVec::<[Type; 1]>::from_vec(results_vec);
162 FunctionType { abi, params, results }
163 }));
164
165 let nid = any::<MastNodeId>();
166 let name = any::<crate::ast::QualifiedProcedureName>();
167 (nid, name, signature)
168 .prop_map(|(nodeid, procname, signature)| Self {
169 node: nodeid,
170 path: procname.to_path_buf().into(),
171 signature,
172 attributes: Default::default(),
173 })
174 .boxed()
175 }
176
177 type Strategy = BoxedStrategy<Self>;
178}
179
180#[derive(Debug, Clone, PartialEq, Eq)]
181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
182#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
183#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
184pub struct ConstantExport {
185 #[cfg_attr(feature = "serde", serde(with = "crate::ast::path"))]
187 #[cfg_attr(
188 feature = "arbitrary",
189 proptest(strategy = "crate::arbitrary::path::constant_path_random_length(1)")
190 )]
191 pub path: Arc<Path>,
192 pub value: crate::ast::ConstantValue,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
197#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
198#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
199pub struct TypeExport {
200 #[cfg_attr(feature = "serde", serde(with = "crate::ast::path"))]
202 pub path: Arc<Path>,
203 pub ty: crate::ast::types::Type,
205}
206
207#[cfg(feature = "arbitrary")]
208impl Arbitrary for TypeExport {
209 type Parameters = ();
210
211 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
212 use proptest::strategy::{Just, Strategy};
213 let path = crate::arbitrary::path::user_defined_type_path_random_length(1);
214 let ty = Just(crate::ast::types::Type::Felt);
215
216 (path, ty).prop_map(|(path, ty)| Self { path, ty }).boxed()
217 }
218
219 type Strategy = BoxedStrategy<Self>;
220}
221
222#[derive(Debug, Clone, PartialEq, Eq)]
230#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
231pub struct Library {
232 digest: Word,
235 exports: BTreeMap<Arc<Path>, LibraryExport>,
245 mast_forest: Arc<MastForest>,
247}
248
249impl AsRef<Library> for Library {
250 #[inline(always)]
251 fn as_ref(&self) -> &Library {
252 self
253 }
254}
255
256impl Library {
259 pub fn new(
266 mast_forest: Arc<MastForest>,
267 exports: BTreeMap<Arc<Path>, LibraryExport>,
268 ) -> Result<Self, LibraryError> {
269 if exports.is_empty() {
270 return Err(LibraryError::NoExport);
271 }
272
273 for export in exports.values() {
274 if let LibraryExport::Procedure(ProcedureExport { node, path, .. }) = export
275 && !mast_forest.is_procedure_root(*node)
276 {
277 return Err(LibraryError::NoProcedureRootForExport {
278 procedure_path: path.clone(),
279 });
280 }
281 }
282
283 let digest =
284 mast_forest.compute_nodes_commitment(exports.values().filter_map(
285 |export| match export {
286 LibraryExport::Procedure(export) => Some(&export.node),
287 LibraryExport::Constant(_) | LibraryExport::Type(_) => None,
288 },
289 ));
290
291 Ok(Self { digest, exports, mast_forest })
292 }
293
294 pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
297 let mut mast_forest = (*self.mast_forest).clone();
298 mast_forest.advice_map_mut().extend(advice_map);
299 Self {
300 mast_forest: Arc::new(mast_forest),
301 ..self
302 }
303 }
304}
305
306impl Library {
309 pub fn digest(&self) -> &Word {
311 &self.digest
312 }
313
314 pub fn exports(&self) -> impl Iterator<Item = &LibraryExport> {
316 self.exports.values()
317 }
318
319 pub fn num_exports(&self) -> usize {
321 self.exports.len()
322 }
323
324 pub fn get_export_node_id(&self, path: impl AsRef<Path>) -> MastNodeId {
329 let path = path.as_ref().to_absolute();
330 self.exports
331 .get(path.as_ref())
332 .expect("procedure not exported from the library")
333 .unwrap_procedure()
334 .node
335 }
336
337 pub fn is_reexport(&self, path: impl AsRef<Path>) -> bool {
339 let path = path.as_ref().to_absolute();
340 self.exports
341 .get(path.as_ref())
342 .and_then(LibraryExport::as_procedure)
343 .map(|export| self.mast_forest[export.node].is_external())
344 .unwrap_or(false)
345 }
346
347 pub fn mast_forest(&self) -> &Arc<MastForest> {
349 &self.mast_forest
350 }
351
352 pub fn get_procedure_root_by_path(&self, path: impl AsRef<Path>) -> Option<Word> {
355 let path = path.as_ref().to_absolute();
356 let export = self.exports.get(path.as_ref()).and_then(LibraryExport::as_procedure);
357 export.map(|e| self.mast_forest()[e.node].digest())
358 }
359}
360
361impl Library {
363 pub fn module_infos(&self) -> impl Iterator<Item = ModuleInfo> {
365 let mut modules_by_path: BTreeMap<Arc<Path>, ModuleInfo> = BTreeMap::new();
366
367 for export in self.exports.values() {
368 let module_name =
369 Arc::from(export.path().parent().unwrap().to_path_buf().into_boxed_path());
370 let module = modules_by_path
371 .entry(Arc::clone(&module_name))
372 .or_insert_with(|| ModuleInfo::new(module_name));
373 match export {
374 LibraryExport::Procedure(ProcedureExport { node, path, signature, attributes }) => {
375 let proc_digest = self.mast_forest[*node].digest();
376 let name = path.last().unwrap();
377 module.add_procedure(
378 ProcedureName::new(name).expect("valid procedure name"),
379 proc_digest,
380 signature.clone().map(Arc::new),
381 attributes.clone(),
382 );
383 },
384 LibraryExport::Constant(ConstantExport { path, value }) => {
385 let name = Ident::new(path.last().unwrap()).expect("valid identifier");
386 module.add_constant(name, value.clone());
387 },
388 LibraryExport::Type(TypeExport { path, ty }) => {
389 let name = Ident::new(path.last().unwrap()).expect("valid identifier");
390 module.add_type(name, ty.clone());
391 },
392 }
393 }
394
395 modules_by_path.into_values()
396 }
397}
398
399#[cfg(feature = "std")]
400impl Library {
401 pub const LIBRARY_EXTENSION: &'static str = "masl";
403
404 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
410 let path = path.as_ref();
411
412 if let Some(dir) = path.parent() {
413 std::fs::create_dir_all(dir)?;
414 }
415
416 std::panic::catch_unwind(|| {
420 let mut file = std::fs::File::create(path)?;
421 self.write_into(&mut file);
422 Ok(())
423 })
424 .map_err(|p| {
425 match p.downcast::<std::io::Error>() {
426 Ok(err) => unsafe { core::ptr::read(&*err) },
428 Err(err) => std::panic::resume_unwind(err),
429 }
430 })?
431 }
432
433 pub fn deserialize_from_file(
434 path: impl AsRef<std::path::Path>,
435 ) -> Result<Self, DeserializationError> {
436 use miden_core::utils::ReadAdapter;
437
438 let path = path.as_ref();
439 let mut file = std::fs::File::open(path).map_err(|err| {
440 DeserializationError::InvalidValue(format!(
441 "failed to open file at {}: {err}",
442 path.to_string_lossy()
443 ))
444 })?;
445 let mut adapter = ReadAdapter::new(&mut file);
446
447 Self::read_from(&mut adapter)
448 }
449}
450
451#[derive(Debug, Clone, PartialEq, Eq)]
461#[cfg_attr(feature = "serde", derive(Deserialize))]
462#[cfg_attr(feature = "serde", serde(try_from = "Library"))]
463pub struct KernelLibrary {
464 #[cfg_attr(feature = "serde", serde(skip))]
465 kernel: Kernel,
466 #[cfg_attr(feature = "serde", serde(skip))]
467 kernel_info: ModuleInfo,
468 library: Library,
469}
470
471#[cfg(feature = "serde")]
472impl serde::Serialize for KernelLibrary {
473 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
474 where
475 S: serde::Serializer,
476 {
477 Library::serialize(&self.library, serializer)
478 }
479}
480
481impl AsRef<Library> for KernelLibrary {
482 #[inline(always)]
483 fn as_ref(&self) -> &Library {
484 &self.library
485 }
486}
487
488impl KernelLibrary {
489 pub fn kernel(&self) -> &Kernel {
491 &self.kernel
492 }
493
494 pub fn mast_forest(&self) -> &Arc<MastForest> {
496 self.library.mast_forest()
497 }
498
499 pub fn into_parts(self) -> (Kernel, ModuleInfo, Arc<MastForest>) {
501 (self.kernel, self.kernel_info, self.library.mast_forest)
502 }
503}
504
505impl TryFrom<Library> for KernelLibrary {
506 type Error = LibraryError;
507
508 fn try_from(library: Library) -> Result<Self, Self::Error> {
509 let kernel_path = Arc::from(Path::kernel_path().to_path_buf().into_boxed_path());
510 let mut proc_digests = Vec::with_capacity(library.exports.len());
511
512 let mut kernel_module = ModuleInfo::new(Arc::clone(&kernel_path));
513
514 for export in library.exports.values() {
515 match export {
516 LibraryExport::Procedure(export) => {
517 if !export.path.is_in_kernel() {
519 return Err(LibraryError::InvalidKernelExport {
520 procedure_path: export.path.clone(),
521 });
522 }
523
524 let proc_digest = library.mast_forest[export.node].digest();
525 proc_digests.push(proc_digest);
526 kernel_module.add_procedure(
527 ProcedureName::new(export.path.last().unwrap())
528 .expect("valid procedure name"),
529 proc_digest,
530 export.signature.clone().map(Arc::new),
531 export.attributes.clone(),
532 );
533 },
534 LibraryExport::Constant(export) => {
535 if export.path.is_in_kernel() {
537 let name =
538 Ident::new(export.path.last().unwrap()).expect("valid identifier");
539 kernel_module.add_constant(name, export.value.clone());
540 }
541 },
542 LibraryExport::Type(export) => {
543 if export.path.is_in_kernel() {
545 let name =
546 Ident::new(export.path.last().unwrap()).expect("valid identifier");
547 kernel_module.add_type(name, export.ty.clone());
548 }
549 },
550 }
551 }
552
553 let kernel = Kernel::new(&proc_digests).map_err(LibraryError::KernelConversion)?;
554
555 Ok(Self {
556 kernel,
557 kernel_info: kernel_module,
558 library,
559 })
560 }
561}
562
563#[cfg(feature = "std")]
564impl KernelLibrary {
565 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
567 self.library.write_to_file(path)
568 }
569}
570
571impl Serializable for Library {
576 fn write_into<W: ByteWriter>(&self, target: &mut W) {
577 let Self { digest: _, exports, mast_forest } = self;
578
579 mast_forest.write_into(target);
580
581 target.write_usize(exports.len());
582 for export in exports.values() {
583 export.write_into(target);
584 }
585 }
586}
587
588impl Deserializable for Library {
590 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
591 let mast_forest = Arc::new(MastForest::read_from(source)?);
592
593 let num_exports = source.read_usize()?;
594 if num_exports == 0 {
595 return Err(DeserializationError::InvalidValue(String::from("No exported procedures")));
596 };
597 let mut exports = BTreeMap::new();
598 for _ in 0..num_exports {
599 let tag = source.read_u8()?;
600 let path: PathBuf = source.read()?;
601 let path = Arc::<Path>::from(path.into_boxed_path());
602 let export = match tag {
603 0 => {
604 let node = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
605 let signature = if source.read_bool()? {
606 Some(FunctionTypeDeserializer::read_from(source)?.0)
607 } else {
608 None
609 };
610 let attributes = AttributeSet::read_from(source)?;
611 LibraryExport::Procedure(ProcedureExport {
612 node,
613 path: path.clone(),
614 signature,
615 attributes,
616 })
617 },
618 1 => {
619 let value = crate::ast::ConstantValue::read_from(source)?;
620 LibraryExport::Constant(ConstantExport { path: path.clone(), value })
621 },
622 2 => {
623 let ty = TypeDeserializer::read_from(source)?.0;
624 LibraryExport::Type(TypeExport { path: path.clone(), ty })
625 },
626 invalid => {
627 return Err(DeserializationError::InvalidValue(format!(
628 "unknown LibraryExport tag: '{invalid}'"
629 )));
630 },
631 };
632 exports.insert(path, export);
633 }
634
635 let digest =
636 mast_forest.compute_nodes_commitment(exports.values().filter_map(|e| match e {
637 LibraryExport::Procedure(e) => Some(&e.node),
638 LibraryExport::Constant(_) | LibraryExport::Type(_) => None,
639 }));
640
641 Ok(Self { digest, exports, mast_forest })
642 }
643}
644
645#[cfg(feature = "serde")]
646impl serde::Serialize for Library {
647 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
648 where
649 S: serde::Serializer,
650 {
651 use serde::ser::SerializeStruct;
652
653 struct LibraryExports<'a>(&'a BTreeMap<Arc<Path>, LibraryExport>);
654 impl serde::Serialize for LibraryExports<'_> {
655 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
656 where
657 S: serde::Serializer,
658 {
659 use serde::ser::SerializeSeq;
660 let mut serializer = serializer.serialize_seq(Some(self.0.len()))?;
661 for elem in self.0.values() {
662 serializer.serialize_element(elem)?;
663 }
664 serializer.end()
665 }
666 }
667
668 let Self { digest: _, exports, mast_forest } = self;
669
670 let mut serializer = serializer.serialize_struct("Library", 2)?;
671 serializer.serialize_field("mast_forest", mast_forest)?;
672 serializer.serialize_field("exports", &LibraryExports(exports))?;
673 serializer.end()
674 }
675}
676
677#[cfg(feature = "serde")]
678impl<'de> serde::Deserialize<'de> for Library {
679 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
680 where
681 D: serde::Deserializer<'de>,
682 {
683 use serde::de::Visitor;
684
685 #[derive(Deserialize)]
686 #[serde(field_identifier, rename_all = "snake_case")]
687 enum Field {
688 MastForest,
689 Exports,
690 }
691
692 struct LibraryVisitor;
693
694 impl<'de> Visitor<'de> for LibraryVisitor {
695 type Value = Library;
696
697 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
698 formatter.write_str("struct Library")
699 }
700
701 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
702 where
703 A: serde::de::SeqAccess<'de>,
704 {
705 let mast_forest = seq
706 .next_element()?
707 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
708 let exports: Vec<LibraryExport> = seq
709 .next_element()?
710 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
711 let exports = exports.into_iter().map(|export| (export.path(), export)).collect();
712 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
713 }
714
715 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
716 where
717 A: serde::de::MapAccess<'de>,
718 {
719 let mut mast_forest = None;
720 let mut exports = None;
721 while let Some(key) = map.next_key()? {
722 match key {
723 Field::MastForest => {
724 if mast_forest.is_some() {
725 return Err(serde::de::Error::duplicate_field("mast_forest"));
726 }
727 mast_forest = Some(map.next_value()?);
728 },
729 Field::Exports => {
730 if exports.is_some() {
731 return Err(serde::de::Error::duplicate_field("exports"));
732 }
733 let items: Vec<LibraryExport> = map.next_value()?;
734 exports = Some(
735 items.into_iter().map(|export| (export.path(), export)).collect(),
736 );
737 },
738 }
739 }
740 let mast_forest =
741 mast_forest.ok_or_else(|| serde::de::Error::missing_field("mast_forest"))?;
742 let exports = exports.ok_or_else(|| serde::de::Error::missing_field("exports"))?;
743 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
744 }
745 }
746
747 deserializer.deserialize_struct("Library", &["mast_forest", "exports"], LibraryVisitor)
748 }
749}
750
751impl Serializable for KernelLibrary {
753 fn write_into<W: ByteWriter>(&self, target: &mut W) {
754 let Self { kernel: _, kernel_info: _, library } = self;
755
756 library.write_into(target);
757 }
758}
759
760impl Deserializable for KernelLibrary {
762 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
763 let library = Library::read_from(source)?;
764
765 Self::try_from(library).map_err(|err| {
766 DeserializationError::InvalidValue(format!(
767 "Failed to deserialize kernel library: {err}"
768 ))
769 })
770 }
771}
772
773impl Serializable for LibraryExport {
775 fn write_into<W: ByteWriter>(&self, target: &mut W) {
776 match self {
777 LibraryExport::Procedure(ProcedureExport {
778 node,
779 path: name,
780 signature,
781 attributes,
782 }) => {
783 target.write_u8(0);
784 name.write_into(target);
785 target.write_u32(u32::from(*node));
786 if let Some(sig) = signature {
787 target.write_bool(true);
788 FunctionTypeSerializer(sig).write_into(target);
789 } else {
790 target.write_bool(false);
791 }
792 attributes.write_into(target);
793 },
794 LibraryExport::Constant(ConstantExport { path: name, value }) => {
795 target.write_u8(1);
796 name.write_into(target);
797 value.write_into(target);
798 },
799 LibraryExport::Type(TypeExport { path: name, ty }) => {
800 target.write_u8(2);
801 name.write_into(target);
802 TypeSerializer(ty).write_into(target);
803 },
804 }
805 }
806}
807
808pub struct FunctionTypeSerializer<'a>(pub &'a FunctionType);
815
816impl Serializable for FunctionTypeSerializer<'_> {
817 fn write_into<W: ByteWriter>(&self, target: &mut W) {
818 target.write_u8(self.0.abi as u8);
819 target.write_usize(self.0.params().len());
820 target.write_many(self.0.params().iter().map(TypeSerializer));
821 target.write_usize(self.0.results().len());
822 target.write_many(self.0.results().iter().map(TypeSerializer));
823 }
824}
825
826pub struct FunctionTypeDeserializer(pub FunctionType);
833
834impl Deserializable for FunctionTypeDeserializer {
835 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
836 use midenc_hir_type::CallConv;
837
838 let abi = match source.read_u8()? {
839 0 => CallConv::Fast,
840 1 => CallConv::SystemV,
841 2 => CallConv::Wasm,
842 3 => CallConv::CanonLift,
843 4 => CallConv::CanonLower,
844 5 => CallConv::Kernel,
845 invalid => {
846 return Err(DeserializationError::InvalidValue(format!(
847 "invalid CallConv tag: {invalid}"
848 )));
849 },
850 };
851
852 let arity = source.read_usize()?;
853 let mut params = SmallVec::<[Type; 4]>::with_capacity(arity);
854 for _ in 0..arity {
855 let ty = TypeDeserializer::read_from(source)?.0;
856 params.push(ty);
857 }
858
859 let num_results = source.read_usize()?;
860 let mut results = SmallVec::<[Type; 1]>::with_capacity(num_results);
861 for _ in 0..num_results {
862 let ty = TypeDeserializer::read_from(source)?.0;
863 results.push(ty);
864 }
865
866 Ok(Self(FunctionType { abi, params, results }))
867 }
868}
869
870pub struct TypeSerializer<'a>(pub &'a Type);
876
877impl Serializable for TypeSerializer<'_> {
878 fn write_into<W: ByteWriter>(&self, target: &mut W) {
879 use midenc_hir_type::{AddressSpace, TypeRepr};
880
881 match self.0 {
882 Type::Unknown => target.write_u8(0),
883 Type::Never => target.write_u8(1),
884 Type::I1 => target.write_u8(2),
885 Type::I8 => target.write_u8(3),
886 Type::U8 => target.write_u8(4),
887 Type::I16 => target.write_u8(5),
888 Type::U16 => target.write_u8(6),
889 Type::I32 => target.write_u8(7),
890 Type::U32 => target.write_u8(8),
891 Type::I64 => target.write_u8(9),
892 Type::U64 => target.write_u8(10),
893 Type::I128 => target.write_u8(11),
894 Type::U128 => target.write_u8(12),
895 Type::U256 => target.write_u8(13),
896 Type::F64 => target.write_u8(14),
897 Type::Felt => target.write_u8(15),
898 Type::Ptr(ty) => {
899 target.write_u8(16);
900 match ty.addrspace {
901 AddressSpace::Byte => target.write_u8(0),
902 AddressSpace::Element => target.write_u8(1),
903 }
904 TypeSerializer(&ty.pointee).write_into(target);
905 },
906 Type::Struct(ty) => {
907 target.write_u8(17);
908 match ty.repr() {
909 TypeRepr::Default => target.write_u8(0),
910 TypeRepr::Align(align) => {
911 target.write_u8(1);
912 target.write_u16(align.get());
913 },
914 TypeRepr::Packed(align) => {
915 target.write_u8(2);
916 target.write_u16(align.get());
917 },
918 TypeRepr::Transparent => target.write_u8(3),
919 TypeRepr::BigEndian => target.write_u8(4),
920 }
921 target.write_u8(ty.len() as u8);
922 for field in ty.fields() {
923 TypeSerializer(&field.ty).write_into(target);
924 }
925 },
926 Type::Array(ty) => {
927 target.write_u8(18);
928 target.write_usize(ty.len);
929 TypeSerializer(&ty.ty).write_into(target);
930 },
931 Type::List(ty) => {
932 target.write_u8(19);
933 TypeSerializer(ty).write_into(target);
934 },
935 Type::Function(ty) => {
936 target.write_u8(20);
937 FunctionTypeSerializer(ty).write_into(target);
938 },
939 }
940 }
941}
942
943pub struct TypeDeserializer(pub Type);
949
950impl Deserializable for TypeDeserializer {
951 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
952 use alloc::string::ToString;
953 use core::num::NonZeroU16;
954
955 use midenc_hir_type::{AddressSpace, ArrayType, PointerType, StructType, TypeRepr};
956
957 let ty = match source.read_u8()? {
958 0 => Type::Unknown,
959 1 => Type::Never,
960 2 => Type::I1,
961 3 => Type::I8,
962 4 => Type::U8,
963 5 => Type::I16,
964 6 => Type::U16,
965 7 => Type::I32,
966 8 => Type::U32,
967 9 => Type::I64,
968 10 => Type::U64,
969 11 => Type::I128,
970 12 => Type::U128,
971 13 => Type::U256,
972 14 => Type::F64,
973 15 => Type::Felt,
974 16 => {
975 let addrspace = match source.read_u8()? {
976 0 => AddressSpace::Byte,
977 1 => AddressSpace::Element,
978 invalid => {
979 return Err(DeserializationError::InvalidValue(format!(
980 "invalid AddressSpace tag: {invalid}"
981 )));
982 },
983 };
984 let pointee = TypeDeserializer::read_from(source)?.0;
985 Type::Ptr(Arc::new(PointerType { addrspace, pointee }))
986 },
987 17 => {
988 let repr = match source.read_u8()? {
989 0 => TypeRepr::Default,
990 1 => {
991 let align = NonZeroU16::new(source.read_u16()?).ok_or_else(|| {
992 DeserializationError::InvalidValue(
993 "invalid type repr: alignment must be a non-zero value".to_string(),
994 )
995 })?;
996 TypeRepr::Align(align)
997 },
998 2 => {
999 let align = NonZeroU16::new(source.read_u16()?).ok_or_else(|| {
1000 DeserializationError::InvalidValue(
1001 "invalid type repr: packed alignment must be a non-zero value"
1002 .to_string(),
1003 )
1004 })?;
1005 TypeRepr::Packed(align)
1006 },
1007 3 => TypeRepr::Transparent,
1008 invalid => {
1009 return Err(DeserializationError::InvalidValue(format!(
1010 "invalid TypeRepr tag: {invalid}"
1011 )));
1012 },
1013 };
1014 let num_fields = source.read_u8()?;
1015 let mut fields = SmallVec::<[Type; 4]>::with_capacity(num_fields as usize);
1016 for _ in 0..num_fields {
1017 let ty = TypeDeserializer::read_from(source)?.0;
1018 fields.push(ty);
1019 }
1020 Type::Struct(Arc::new(StructType::new_with_repr(repr, fields)))
1021 },
1022 18 => {
1023 let arity = source.read_usize()?;
1024 let ty = TypeDeserializer::read_from(source)?.0;
1025 Type::Array(Arc::new(ArrayType { ty, len: arity }))
1026 },
1027 19 => {
1028 let ty = TypeDeserializer::read_from(source)?.0;
1029 Type::List(Arc::new(ty))
1030 },
1031 20 => Type::Function(Arc::new(FunctionTypeDeserializer::read_from(source)?.0)),
1032 invalid => {
1033 return Err(DeserializationError::InvalidValue(format!(
1034 "invalid Type tag: {invalid}"
1035 )));
1036 },
1037 };
1038 Ok(Self(ty))
1039 }
1040}
1041
1042#[cfg(feature = "arbitrary")]
1043impl proptest::prelude::Arbitrary for Library {
1044 type Parameters = ();
1045
1046 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
1047 use miden_core::{
1048 mast::{BasicBlockNodeBuilder, MastForestContributor},
1049 operations::Operation,
1050 };
1051 use proptest::prelude::*;
1052
1053 prop::collection::vec(any::<LibraryExport>(), 1..5)
1054 .prop_map(|exports| {
1055 let mut exports =
1056 BTreeMap::from_iter(exports.into_iter().map(|export| (export.path(), export)));
1057 let mut mast_forest = MastForest::new();
1059 let mut nodes = Vec::new();
1060
1061 for export in exports.values() {
1062 if let LibraryExport::Procedure(export) = export {
1063 let node_id = BasicBlockNodeBuilder::new(
1064 vec![Operation::Add, Operation::Mul],
1065 Vec::new(),
1066 )
1067 .add_to_forest(&mut mast_forest)
1068 .unwrap();
1069 nodes.push((export.node, node_id));
1070 }
1071 }
1072
1073 let mut procedure_exports = 0;
1075 for export in exports.values_mut() {
1076 match export {
1077 LibraryExport::Procedure(export) => {
1078 procedure_exports += 1;
1079 if let Some(&(_, actual_node_id)) =
1081 nodes.iter().find(|(original_id, _)| *original_id == export.node)
1082 {
1083 export.node = actual_node_id;
1084 } else {
1085 if let Some(&(_, first_node_id)) = nodes.first() {
1088 export.node = first_node_id;
1089 } else {
1090 panic!("No nodes created for exports");
1093 }
1094 }
1095 },
1096 LibraryExport::Constant(_) | LibraryExport::Type(_) => (),
1097 }
1098 }
1099
1100 let mut node_ids = Vec::with_capacity(procedure_exports);
1101 for export in exports.values() {
1102 if let LibraryExport::Procedure(export) = export {
1103 mast_forest.make_root(export.node);
1105 node_ids.push(export.node);
1107 }
1108 }
1109
1110 let digest = mast_forest.compute_nodes_commitment(&node_ids);
1112
1113 let mast_forest = Arc::new(mast_forest);
1114 Library { digest, exports, mast_forest }
1115 })
1116 .boxed()
1117 }
1118
1119 type Strategy = proptest::prelude::BoxedStrategy<Self>;
1120}