1use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
2
3use miden_core::{
4 AdviceMap, Kernel, Word,
5 mast::{MastForest, MastNodeExt, MastNodeId},
6 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8use midenc_hir_type::{FunctionType, Type};
9#[cfg(feature = "arbitrary")]
10use proptest::prelude::*;
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13use smallvec::SmallVec;
14
15use crate::ast::{AttributeSet, QualifiedProcedureName};
16
17mod error;
18mod module;
19mod namespace;
20mod path;
21
22pub use module::{ModuleInfo, ProcedureInfo};
23pub use semver::{Error as VersionError, Version};
24
25pub use self::{
26 error::LibraryError,
27 namespace::{LibraryNamespace, LibraryNamespaceError},
28 path::{LibraryPath, LibraryPathComponent, PathError},
29};
30
31#[derive(Debug, Clone, PartialEq, Eq)]
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
37#[cfg_attr(
38 all(feature = "serde", feature = "arbitrary", test),
39 miden_serde_test_macros::serde_test
40)]
41pub struct LibraryExport {
42 pub node: MastNodeId,
44 pub name: QualifiedProcedureName,
46 #[cfg_attr(feature = "serde", serde(default))]
48 pub signature: Option<FunctionType>,
49 #[cfg_attr(feature = "serde", serde(default))]
50 pub attributes: AttributeSet,
51}
52
53impl LibraryExport {
54 pub fn new(node: MastNodeId, name: QualifiedProcedureName) -> Self {
56 Self {
57 node,
58 name,
59 signature: None,
60 attributes: Default::default(),
61 }
62 }
63
64 pub fn with_signature(mut self, signature: FunctionType) -> Self {
66 self.signature = Some(signature);
67 self
68 }
69
70 pub fn with_attributes(mut self, attrs: AttributeSet) -> Self {
72 self.attributes = attrs;
73 self
74 }
75}
76
77#[cfg(feature = "arbitrary")]
79impl Arbitrary for LibraryExport {
80 type Parameters = ();
81
82 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
83 let nid = any::<MastNodeId>();
84 let name = any::<QualifiedProcedureName>();
85 (nid, name)
86 .prop_map(|(nodeid, procname)| LibraryExport {
87 node: nodeid,
88 name: procname,
89 signature: None,
90 attributes: Default::default(),
91 })
92 .boxed()
93 }
94
95 type Strategy = BoxedStrategy<Self>;
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
106#[cfg_attr(
107 all(feature = "serde", feature = "arbitrary", test),
108 miden_serde_test_macros::serde_test
109)]
110pub struct Library {
111 digest: Word,
114 exports: BTreeMap<QualifiedProcedureName, LibraryExport>,
124 mast_forest: Arc<MastForest>,
126}
127
128impl AsRef<Library> for Library {
129 #[inline(always)]
130 fn as_ref(&self) -> &Library {
131 self
132 }
133}
134
135impl Library {
138 pub fn new(
145 mast_forest: Arc<MastForest>,
146 exports: BTreeMap<QualifiedProcedureName, LibraryExport>,
147 ) -> Result<Self, LibraryError> {
148 if exports.is_empty() {
149 return Err(LibraryError::NoExport);
150 }
151 for LibraryExport { name, node, .. } in exports.values() {
152 if !mast_forest.is_procedure_root(*node) {
153 return Err(LibraryError::NoProcedureRootForExport {
154 procedure_path: name.clone(),
155 });
156 }
157 }
158
159 let digest =
160 mast_forest.compute_nodes_commitment(exports.values().map(|export| &export.node));
161
162 Ok(Self { digest, exports, mast_forest })
163 }
164
165 pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
168 let mut mast_forest = (*self.mast_forest).clone();
169 mast_forest.advice_map_mut().extend(advice_map);
170 Self {
171 mast_forest: Arc::new(mast_forest),
172 ..self
173 }
174 }
175}
176
177impl Library {
180 pub fn digest(&self) -> &Word {
182 &self.digest
183 }
184
185 pub fn exports(&self) -> impl Iterator<Item = &LibraryExport> {
187 self.exports.values()
188 }
189
190 pub fn num_exports(&self) -> usize {
192 self.exports.len()
193 }
194
195 pub fn get_export_node_id(&self, proc_name: &QualifiedProcedureName) -> MastNodeId {
200 self.exports
201 .get(proc_name)
202 .expect("procedure not exported from the library")
203 .node
204 }
205
206 pub fn is_reexport(&self, proc_name: &QualifiedProcedureName) -> bool {
208 self.exports
209 .get(proc_name)
210 .map(|export| self.mast_forest[export.node].is_external())
211 .unwrap_or(false)
212 }
213
214 pub fn mast_forest(&self) -> &Arc<MastForest> {
216 &self.mast_forest
217 }
218
219 pub fn get_procedure_root_by_name(
222 &self,
223 proc_name: impl TryInto<QualifiedProcedureName>,
224 ) -> Option<Word> {
225 if let Ok(qualified_proc_name) = proc_name.try_into() {
226 let export = self.exports.get(&qualified_proc_name);
227 export.map(|e| self.mast_forest()[e.node].digest())
228 } else {
229 None
230 }
231 }
232}
233
234impl Library {
236 pub fn module_infos(&self) -> impl Iterator<Item = ModuleInfo> {
238 let mut modules_by_path: BTreeMap<LibraryPath, ModuleInfo> = BTreeMap::new();
239
240 for LibraryExport { node, name, signature, attributes } in self.exports.values() {
241 modules_by_path
242 .entry(name.module.clone())
243 .and_modify(|compiled_module| {
244 let proc_digest = self.mast_forest[*node].digest();
245 compiled_module.add_procedure(
246 name.name.clone(),
247 proc_digest,
248 signature.clone().map(Arc::new),
249 attributes.clone(),
250 );
251 })
252 .or_insert_with(|| {
253 let mut module_info = ModuleInfo::new(name.module.clone());
254
255 let proc_digest = self.mast_forest[*node].digest();
256 module_info.add_procedure(
257 name.name.clone(),
258 proc_digest,
259 signature.clone().map(Arc::new),
260 attributes.clone(),
261 );
262
263 module_info
264 });
265 }
266
267 modules_by_path.into_values()
268 }
269}
270
271#[cfg(feature = "std")]
272impl Library {
273 pub const LIBRARY_EXTENSION: &'static str = "masl";
275
276 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
282 let path = path.as_ref();
283
284 if let Some(dir) = path.parent() {
285 std::fs::create_dir_all(dir)?;
286 }
287
288 std::panic::catch_unwind(|| {
292 let mut file = std::fs::File::create(path)?;
293 self.write_into(&mut file);
294 Ok(())
295 })
296 .map_err(|p| {
297 match p.downcast::<std::io::Error>() {
298 Ok(err) => unsafe { core::ptr::read(&*err) },
300 Err(err) => std::panic::resume_unwind(err),
301 }
302 })?
303 }
304
305 pub fn deserialize_from_file(
306 path: impl AsRef<std::path::Path>,
307 ) -> Result<Self, DeserializationError> {
308 use miden_core::utils::ReadAdapter;
309
310 let path = path.as_ref();
311 let mut file = std::fs::File::open(path).map_err(|err| {
312 DeserializationError::InvalidValue(format!(
313 "failed to open file at {}: {err}",
314 path.to_string_lossy()
315 ))
316 })?;
317 let mut adapter = ReadAdapter::new(&mut file);
318
319 Self::read_from(&mut adapter)
320 }
321}
322
323#[derive(Debug, Clone, PartialEq, Eq)]
333#[cfg_attr(feature = "serde", derive(Deserialize))]
334#[cfg_attr(feature = "serde", serde(try_from = "Library"))]
335pub struct KernelLibrary {
336 #[cfg_attr(feature = "serde", serde(skip))]
337 kernel: Kernel,
338 #[cfg_attr(feature = "serde", serde(skip))]
339 kernel_info: ModuleInfo,
340 library: Library,
341}
342
343#[cfg(feature = "serde")]
344impl serde::Serialize for KernelLibrary {
345 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
346 where
347 S: serde::Serializer,
348 {
349 Library::serialize(&self.library, serializer)
350 }
351}
352
353impl AsRef<Library> for KernelLibrary {
354 #[inline(always)]
355 fn as_ref(&self) -> &Library {
356 &self.library
357 }
358}
359
360impl KernelLibrary {
361 pub fn kernel(&self) -> &Kernel {
363 &self.kernel
364 }
365
366 pub fn mast_forest(&self) -> &Arc<MastForest> {
368 self.library.mast_forest()
369 }
370
371 pub fn into_parts(self) -> (Kernel, ModuleInfo, Arc<MastForest>) {
373 (self.kernel, self.kernel_info, self.library.mast_forest)
374 }
375}
376
377impl TryFrom<Library> for KernelLibrary {
378 type Error = LibraryError;
379
380 fn try_from(library: Library) -> Result<Self, Self::Error> {
381 let kernel_path = LibraryPath::from(LibraryNamespace::Kernel);
382 let mut proc_digests = Vec::with_capacity(library.exports.len());
383
384 let mut kernel_module = ModuleInfo::new(kernel_path.clone());
385
386 for export in library.exports.values() {
387 if export.name.module != kernel_path {
389 return Err(LibraryError::InvalidKernelExport {
390 procedure_path: export.name.clone(),
391 });
392 }
393
394 let proc_digest = library.mast_forest[export.node].digest();
395 proc_digests.push(proc_digest);
396 kernel_module.add_procedure(
397 export.name.name.clone(),
398 proc_digest,
399 export.signature.clone().map(Arc::new),
400 export.attributes.clone(),
401 );
402 }
403
404 let kernel = Kernel::new(&proc_digests).map_err(LibraryError::KernelConversion)?;
405
406 Ok(Self {
407 kernel,
408 kernel_info: kernel_module,
409 library,
410 })
411 }
412}
413
414#[cfg(feature = "std")]
415impl KernelLibrary {
416 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
418 self.library.write_to_file(path)
419 }
420}
421
422impl Serializable for Library {
427 fn write_into<W: ByteWriter>(&self, target: &mut W) {
428 let Self { digest: _, exports, mast_forest } = self;
429
430 mast_forest.write_into(target);
431
432 target.write_usize(exports.len());
433 for LibraryExport { node, name, signature, attributes: _ } in exports.values() {
434 name.module.write_into(target);
435 name.name.write_into(target);
436 target.write_u32(node.as_u32());
437 if let Some(sig) = signature {
438 target.write_bool(true);
439 FunctionTypeSerializer(sig).write_into(target);
440 } else {
441 target.write_bool(false);
442 }
443 }
444 }
445}
446
447impl Deserializable for Library {
449 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
450 let mast_forest = Arc::new(MastForest::read_from(source)?);
451
452 let num_exports = source.read_usize()?;
453 if num_exports == 0 {
454 return Err(DeserializationError::InvalidValue(String::from("No exported procedures")));
455 };
456 let mut exports = BTreeMap::new();
457 for _ in 0..num_exports {
458 let proc_module = source.read()?;
459 let proc_name = source.read()?;
460 let proc_name = QualifiedProcedureName::new(proc_module, proc_name);
461 let node = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
462 let signature = if source.read_bool()? {
463 Some(FunctionTypeDeserializer::read_from(source)?.0)
464 } else {
465 None
466 };
467 let export = LibraryExport {
468 node,
469 name: proc_name.clone(),
470 signature,
471 attributes: Default::default(),
472 };
473
474 exports.insert(proc_name, export);
475 }
476
477 let digest = mast_forest.compute_nodes_commitment(exports.values().map(|e| &e.node));
478
479 Ok(Self { digest, exports, mast_forest })
480 }
481}
482
483#[cfg(feature = "serde")]
484impl serde::Serialize for Library {
485 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
486 where
487 S: serde::Serializer,
488 {
489 use serde::ser::SerializeStruct;
490
491 struct LibraryExports<'a>(&'a BTreeMap<QualifiedProcedureName, LibraryExport>);
492 impl serde::Serialize for LibraryExports<'_> {
493 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
494 where
495 S: serde::Serializer,
496 {
497 use serde::ser::SerializeSeq;
498 let mut serializer = serializer.serialize_seq(Some(self.0.len()))?;
499 for elem in self.0.values() {
500 serializer.serialize_element(elem)?;
501 }
502 serializer.end()
503 }
504 }
505
506 let Self { digest: _, exports, mast_forest } = self;
507
508 let mut serializer = serializer.serialize_struct("Library", 2)?;
509 serializer.serialize_field("mast_forest", mast_forest)?;
510 serializer.serialize_field("exports", &LibraryExports(exports))?;
511 serializer.end()
512 }
513}
514
515#[cfg(feature = "serde")]
516impl<'de> serde::Deserialize<'de> for Library {
517 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
518 where
519 D: serde::Deserializer<'de>,
520 {
521 use serde::de::Visitor;
522
523 #[derive(Deserialize)]
524 #[serde(field_identifier, rename_all = "snake_case")]
525 enum Field {
526 MastForest,
527 Exports,
528 }
529
530 struct LibraryVisitor;
531
532 impl<'de> Visitor<'de> for LibraryVisitor {
533 type Value = Library;
534
535 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
536 formatter.write_str("struct Library")
537 }
538
539 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
540 where
541 A: serde::de::SeqAccess<'de>,
542 {
543 let mast_forest = seq
544 .next_element()?
545 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
546 let exports: Vec<LibraryExport> = seq
547 .next_element()?
548 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
549 let exports =
550 exports.into_iter().map(|export| (export.name.clone(), export)).collect();
551 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
552 }
553
554 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
555 where
556 A: serde::de::MapAccess<'de>,
557 {
558 let mut mast_forest = None;
559 let mut exports = None;
560 while let Some(key) = map.next_key()? {
561 match key {
562 Field::MastForest => {
563 if mast_forest.is_some() {
564 return Err(serde::de::Error::duplicate_field("mast_forest"));
565 }
566 mast_forest = Some(map.next_value()?);
567 },
568 Field::Exports => {
569 if exports.is_some() {
570 return Err(serde::de::Error::duplicate_field("exports"));
571 }
572 let items: Vec<LibraryExport> = map.next_value()?;
573 exports = Some(
574 items
575 .into_iter()
576 .map(|export| (export.name.clone(), export))
577 .collect(),
578 );
579 },
580 }
581 }
582 let mast_forest =
583 mast_forest.ok_or_else(|| serde::de::Error::missing_field("mast_forest"))?;
584 let exports = exports.ok_or_else(|| serde::de::Error::missing_field("exports"))?;
585 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
586 }
587 }
588
589 deserializer.deserialize_struct("Library", &["mast_forest", "exports"], LibraryVisitor)
590 }
591}
592
593impl Serializable for KernelLibrary {
595 fn write_into<W: ByteWriter>(&self, target: &mut W) {
596 let Self { kernel: _, kernel_info: _, library } = self;
597
598 library.write_into(target);
599 }
600}
601
602impl Deserializable for KernelLibrary {
604 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
605 let library = Library::read_from(source)?;
606
607 Self::try_from(library).map_err(|err| {
608 DeserializationError::InvalidValue(format!(
609 "Failed to deserialize kernel library: {err}"
610 ))
611 })
612 }
613}
614
615pub struct FunctionTypeSerializer<'a>(pub &'a FunctionType);
622
623impl Serializable for FunctionTypeSerializer<'_> {
624 fn write_into<W: ByteWriter>(&self, target: &mut W) {
625 target.write_u8(self.0.abi as u8);
626 target.write_usize(self.0.params().len());
627 target.write_many(self.0.params().iter().map(TypeSerializer));
628 target.write_usize(self.0.results().len());
629 target.write_many(self.0.results().iter().map(TypeSerializer));
630 }
631}
632
633pub struct FunctionTypeDeserializer(pub FunctionType);
640
641impl Deserializable for FunctionTypeDeserializer {
642 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
643 use midenc_hir_type::CallConv;
644
645 let abi = match source.read_u8()? {
646 0 => CallConv::Fast,
647 1 => CallConv::SystemV,
648 2 => CallConv::Wasm,
649 3 => CallConv::CanonLift,
650 4 => CallConv::CanonLower,
651 5 => CallConv::Kernel,
652 invalid => {
653 return Err(DeserializationError::InvalidValue(format!(
654 "invalid CallConv tag: {invalid}"
655 )));
656 },
657 };
658
659 let arity = source.read_usize()?;
660 let mut params = SmallVec::<[Type; 4]>::with_capacity(arity);
661 for _ in 0..arity {
662 let ty = TypeDeserializer::read_from(source)?.0;
663 params.push(ty);
664 }
665
666 let num_results = source.read_usize()?;
667 let mut results = SmallVec::<[Type; 1]>::with_capacity(num_results);
668 for _ in 0..num_results {
669 let ty = TypeDeserializer::read_from(source)?.0;
670 results.push(ty);
671 }
672
673 Ok(Self(FunctionType { abi, params, results }))
674 }
675}
676
677pub struct TypeSerializer<'a>(pub &'a Type);
683
684impl Serializable for TypeSerializer<'_> {
685 fn write_into<W: ByteWriter>(&self, target: &mut W) {
686 use midenc_hir_type::{AddressSpace, TypeRepr};
687
688 match self.0 {
689 Type::Unknown => target.write_u8(0),
690 Type::Never => target.write_u8(1),
691 Type::I1 => target.write_u8(2),
692 Type::I8 => target.write_u8(3),
693 Type::U8 => target.write_u8(4),
694 Type::I16 => target.write_u8(5),
695 Type::U16 => target.write_u8(6),
696 Type::I32 => target.write_u8(7),
697 Type::U32 => target.write_u8(8),
698 Type::I64 => target.write_u8(9),
699 Type::U64 => target.write_u8(10),
700 Type::I128 => target.write_u8(11),
701 Type::U128 => target.write_u8(12),
702 Type::U256 => target.write_u8(13),
703 Type::F64 => target.write_u8(14),
704 Type::Felt => target.write_u8(15),
705 Type::Ptr(ty) => {
706 target.write_u8(16);
707 match ty.addrspace {
708 AddressSpace::Byte => target.write_u8(0),
709 AddressSpace::Element => target.write_u8(1),
710 }
711 TypeSerializer(&ty.pointee).write_into(target);
712 },
713 Type::Struct(ty) => {
714 target.write_u8(17);
715 match ty.repr() {
716 TypeRepr::Default => target.write_u8(0),
717 TypeRepr::Align(align) => {
718 target.write_u8(1);
719 target.write_u16(align.get());
720 },
721 TypeRepr::Packed(align) => {
722 target.write_u8(2);
723 target.write_u16(align.get());
724 },
725 TypeRepr::Transparent => target.write_u8(3),
726 TypeRepr::BigEndian => target.write_u8(4),
727 }
728 target.write_u8(ty.len() as u8);
729 for field in ty.fields() {
730 TypeSerializer(&field.ty).write_into(target);
731 }
732 },
733 Type::Array(ty) => {
734 target.write_u8(18);
735 target.write_usize(ty.len);
736 TypeSerializer(&ty.ty).write_into(target);
737 },
738 Type::List(ty) => {
739 target.write_u8(19);
740 TypeSerializer(ty).write_into(target);
741 },
742 Type::Function(ty) => {
743 target.write_u8(20);
744 FunctionTypeSerializer(ty).write_into(target);
745 },
746 }
747 }
748}
749
750pub struct TypeDeserializer(pub Type);
756
757impl Deserializable for TypeDeserializer {
758 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
759 use alloc::string::ToString;
760 use core::num::NonZeroU16;
761
762 use midenc_hir_type::{AddressSpace, ArrayType, PointerType, StructType, TypeRepr};
763
764 let ty = match source.read_u8()? {
765 0 => Type::Unknown,
766 1 => Type::Never,
767 2 => Type::I1,
768 3 => Type::I8,
769 4 => Type::U8,
770 5 => Type::I16,
771 6 => Type::U16,
772 7 => Type::I32,
773 8 => Type::U32,
774 9 => Type::I64,
775 10 => Type::U64,
776 11 => Type::I128,
777 12 => Type::U128,
778 13 => Type::U256,
779 14 => Type::F64,
780 15 => Type::Felt,
781 16 => {
782 let addrspace = match source.read_u8()? {
783 0 => AddressSpace::Byte,
784 1 => AddressSpace::Element,
785 invalid => {
786 return Err(DeserializationError::InvalidValue(format!(
787 "invalid AddressSpace tag: {invalid}"
788 )));
789 },
790 };
791 let pointee = TypeDeserializer::read_from(source)?.0;
792 Type::Ptr(Arc::new(PointerType { addrspace, pointee }))
793 },
794 17 => {
795 let repr = match source.read_u8()? {
796 0 => TypeRepr::Default,
797 1 => {
798 let align = NonZeroU16::new(source.read_u16()?).ok_or_else(|| {
799 DeserializationError::InvalidValue(
800 "invalid type repr: alignment must be a non-zero value".to_string(),
801 )
802 })?;
803 TypeRepr::Align(align)
804 },
805 2 => {
806 let align = NonZeroU16::new(source.read_u16()?).ok_or_else(|| {
807 DeserializationError::InvalidValue(
808 "invalid type repr: packed alignment must be a non-zero value"
809 .to_string(),
810 )
811 })?;
812 TypeRepr::Packed(align)
813 },
814 3 => TypeRepr::Transparent,
815 invalid => {
816 return Err(DeserializationError::InvalidValue(format!(
817 "invalid TypeRepr tag: {invalid}"
818 )));
819 },
820 };
821 let num_fields = source.read_u8()?;
822 let mut fields = SmallVec::<[Type; 4]>::with_capacity(num_fields as usize);
823 for _ in 0..num_fields {
824 let ty = TypeDeserializer::read_from(source)?.0;
825 fields.push(ty);
826 }
827 Type::Struct(Arc::new(StructType::new_with_repr(repr, fields)))
828 },
829 18 => {
830 let arity = source.read_usize()?;
831 let ty = TypeDeserializer::read_from(source)?.0;
832 Type::Array(Arc::new(ArrayType { ty, len: arity }))
833 },
834 19 => {
835 let ty = TypeDeserializer::read_from(source)?.0;
836 Type::List(Arc::new(ty))
837 },
838 20 => Type::Function(Arc::new(FunctionTypeDeserializer::read_from(source)?.0)),
839 invalid => {
840 return Err(DeserializationError::InvalidValue(format!(
841 "invalid Type tag: {invalid}"
842 )));
843 },
844 };
845 Ok(Self(ty))
846 }
847}
848
849#[cfg(any(test, feature = "arbitrary"))]
850impl proptest::prelude::Arbitrary for Library {
851 type Parameters = ();
852
853 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
854 use proptest::prelude::*;
855 prop::collection::btree_map(any::<QualifiedProcedureName>(), any::<LibraryExport>(), 1..5)
856 .prop_flat_map(|mut exports| {
857 let mut mast_forest = MastForest::new();
859 let mut nodes = Vec::new();
860
861 for (export_name, export) in exports.iter_mut() {
863 use miden_core::Operation;
864
865 export.name = export_name.clone();
868
869 let node_id =
870 mast_forest.add_block(vec![Operation::Add, Operation::Mul], None).unwrap();
871 nodes.push((export.node, node_id));
872 }
873
874 (Just(mast_forest), Just(nodes), Just(exports))
875 })
876 .prop_map(|(mut mast_forest, nodes, exports)| {
877 let mut adjusted_exports = BTreeMap::new();
879
880 for (proc_name, mut export) in exports {
881 if let Some(&(_, actual_node_id)) =
883 nodes.iter().find(|(original_id, _)| *original_id == export.node)
884 {
885 export.node = actual_node_id;
886 } else {
887 if let Some(&(_, first_node_id)) = nodes.first() {
890 export.node = first_node_id;
891 } else {
892 panic!("No nodes created for exports");
894 }
895 }
896
897 adjusted_exports.insert(proc_name, export);
898 }
899
900 let mut node_ids = Vec::with_capacity(adjusted_exports.len());
901 for export in adjusted_exports.values() {
902 mast_forest.make_root(export.node);
904 node_ids.push(export.node);
906 }
907
908 let digest = mast_forest.compute_nodes_commitment(&node_ids);
910
911 let mast_forest = Arc::new(mast_forest);
912 Library {
913 digest,
914 exports: adjusted_exports,
915 mast_forest,
916 }
917 })
918 .boxed()
919 }
920
921 type Strategy = proptest::prelude::BoxedStrategy<Self>;
922}