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