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};
15
16use crate::ast::{AttributeSet, Ident, Path, PathBuf, ProcedureName};
17
18mod error;
19mod module;
20
21pub use module::{ConstantInfo, ItemInfo, ModuleInfo, ProcedureInfo, TypeInfo};
22pub use semver::{Error as VersionError, Version};
23
24pub use self::error::LibraryError;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
33pub enum LibraryExport {
34 Procedure(ProcedureExport),
35 Constant(ConstantExport),
36 Type(TypeExport),
37}
38
39impl LibraryExport {
40 pub fn path(&self) -> Arc<Path> {
41 match self {
42 Self::Procedure(export) => export.path.clone(),
43 Self::Constant(export) => export.path.clone(),
44 Self::Type(export) => export.path.clone(),
45 }
46 }
47
48 pub fn as_procedure(&self) -> Option<&ProcedureExport> {
49 match self {
50 Self::Procedure(proc) => Some(proc),
51 Self::Constant(_) | Self::Type(_) => None,
52 }
53 }
54
55 pub fn unwrap_procedure(&self) -> &ProcedureExport {
56 match self {
57 Self::Procedure(proc) => proc,
58 Self::Constant(_) | Self::Type(_) => panic!("expected export to be a procedure"),
59 }
60 }
61}
62
63impl From<ProcedureExport> for LibraryExport {
64 fn from(value: ProcedureExport) -> Self {
65 Self::Procedure(value)
66 }
67}
68
69impl From<ConstantExport> for LibraryExport {
70 fn from(value: ConstantExport) -> Self {
71 Self::Constant(value)
72 }
73}
74
75impl From<TypeExport> for LibraryExport {
76 fn from(value: TypeExport) -> Self {
77 Self::Type(value)
78 }
79}
80
81#[cfg(feature = "arbitrary")]
82impl Arbitrary for LibraryExport {
83 type Parameters = ();
84
85 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
86 use proptest::{arbitrary::any, prop_oneof, strategy::Strategy};
87
88 prop_oneof![
89 any::<ProcedureExport>().prop_map(Self::Procedure),
90 any::<ConstantExport>().prop_map(Self::Constant),
91 any::<TypeExport>().prop_map(Self::Type),
92 ]
93 .boxed()
94 }
95
96 type Strategy = BoxedStrategy<Self>;
97}
98
99#[derive(Debug, Clone, PartialEq, Eq)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
102pub struct ProcedureExport {
103 pub node: MastNodeId,
105 #[cfg_attr(feature = "serde", serde(with = "crate::ast::path"))]
107 pub path: Arc<Path>,
108 #[cfg_attr(feature = "serde", serde(default))]
110 pub signature: Option<FunctionType>,
111 #[cfg_attr(feature = "serde", serde(default))]
112 pub attributes: AttributeSet,
113}
114
115impl ProcedureExport {
116 pub fn new(node: MastNodeId, path: Arc<Path>) -> Self {
118 Self {
119 node,
120 path,
121 signature: None,
122 attributes: Default::default(),
123 }
124 }
125
126 pub fn with_signature(mut self, signature: FunctionType) -> Self {
128 self.signature = Some(signature);
129 self
130 }
131
132 pub fn with_attributes(mut self, attrs: AttributeSet) -> Self {
134 self.attributes = attrs;
135 self
136 }
137}
138
139#[cfg(feature = "arbitrary")]
140impl Arbitrary for ProcedureExport {
141 type Parameters = ();
142
143 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
144 use proptest::collection::vec as prop_vec;
145 use smallvec::SmallVec;
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 if proc_digests.is_empty() {
554 return Err(LibraryError::NoExport);
555 }
556
557 let kernel = Kernel::new(&proc_digests).map_err(LibraryError::KernelConversion)?;
558
559 Ok(Self {
560 kernel,
561 kernel_info: kernel_module,
562 library,
563 })
564 }
565}
566
567#[cfg(feature = "std")]
568impl KernelLibrary {
569 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
571 self.library.write_to_file(path)
572 }
573}
574
575impl Serializable for Library {
580 fn write_into<W: ByteWriter>(&self, target: &mut W) {
581 let Self { digest: _, exports, mast_forest } = self;
582
583 mast_forest.write_into(target);
584
585 target.write_usize(exports.len());
586 for export in exports.values() {
587 export.write_into(target);
588 }
589 }
590}
591
592impl Deserializable for Library {
594 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
595 let mast_forest = Arc::new(MastForest::read_from(source)?);
596
597 let num_exports = source.read_usize()?;
598 if num_exports == 0 {
599 return Err(DeserializationError::InvalidValue(String::from("No exported procedures")));
600 };
601 let mut exports = BTreeMap::new();
602 for _ in 0..num_exports {
603 let tag = source.read_u8()?;
604 let path: PathBuf = source.read()?;
605 let path = Arc::<Path>::from(path.into_boxed_path());
606 let export = match tag {
607 0 => {
608 let node = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
609 let signature = if source.read_bool()? {
610 Some(FunctionType::read_from(source)?)
611 } else {
612 None
613 };
614 let attributes = AttributeSet::read_from(source)?;
615 LibraryExport::Procedure(ProcedureExport {
616 node,
617 path: path.clone(),
618 signature,
619 attributes,
620 })
621 },
622 1 => {
623 let value = crate::ast::ConstantValue::read_from(source)?;
624 LibraryExport::Constant(ConstantExport { path: path.clone(), value })
625 },
626 2 => {
627 let ty = Type::read_from(source)?;
628 LibraryExport::Type(TypeExport { path: path.clone(), ty })
629 },
630 invalid => {
631 return Err(DeserializationError::InvalidValue(format!(
632 "unknown LibraryExport tag: '{invalid}'"
633 )));
634 },
635 };
636 exports.insert(path, export);
637 }
638
639 let digest =
640 mast_forest.compute_nodes_commitment(exports.values().filter_map(|e| match e {
641 LibraryExport::Procedure(e) => Some(&e.node),
642 LibraryExport::Constant(_) | LibraryExport::Type(_) => None,
643 }));
644
645 Ok(Self { digest, exports, mast_forest })
646 }
647}
648
649#[cfg(feature = "serde")]
650impl serde::Serialize for Library {
651 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
652 where
653 S: serde::Serializer,
654 {
655 use serde::ser::SerializeStruct;
656
657 struct LibraryExports<'a>(&'a BTreeMap<Arc<Path>, LibraryExport>);
658 impl serde::Serialize for LibraryExports<'_> {
659 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
660 where
661 S: serde::Serializer,
662 {
663 use serde::ser::SerializeSeq;
664 let mut serializer = serializer.serialize_seq(Some(self.0.len()))?;
665 for elem in self.0.values() {
666 serializer.serialize_element(elem)?;
667 }
668 serializer.end()
669 }
670 }
671
672 let Self { digest: _, exports, mast_forest } = self;
673
674 let mut serializer = serializer.serialize_struct("Library", 2)?;
675 serializer.serialize_field("mast_forest", mast_forest)?;
676 serializer.serialize_field("exports", &LibraryExports(exports))?;
677 serializer.end()
678 }
679}
680
681#[cfg(feature = "serde")]
682impl<'de> serde::Deserialize<'de> for Library {
683 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
684 where
685 D: serde::Deserializer<'de>,
686 {
687 use serde::de::Visitor;
688
689 #[derive(Deserialize)]
690 #[serde(field_identifier, rename_all = "snake_case")]
691 enum Field {
692 MastForest,
693 Exports,
694 }
695
696 struct LibraryVisitor;
697
698 impl<'de> Visitor<'de> for LibraryVisitor {
699 type Value = Library;
700
701 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
702 formatter.write_str("struct Library")
703 }
704
705 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
706 where
707 A: serde::de::SeqAccess<'de>,
708 {
709 let mast_forest = seq
710 .next_element()?
711 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
712 let exports: Vec<LibraryExport> = seq
713 .next_element()?
714 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
715 let exports = exports.into_iter().map(|export| (export.path(), export)).collect();
716 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
717 }
718
719 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
720 where
721 A: serde::de::MapAccess<'de>,
722 {
723 let mut mast_forest = None;
724 let mut exports = None;
725 while let Some(key) = map.next_key()? {
726 match key {
727 Field::MastForest => {
728 if mast_forest.is_some() {
729 return Err(serde::de::Error::duplicate_field("mast_forest"));
730 }
731 mast_forest = Some(map.next_value()?);
732 },
733 Field::Exports => {
734 if exports.is_some() {
735 return Err(serde::de::Error::duplicate_field("exports"));
736 }
737 let items: Vec<LibraryExport> = map.next_value()?;
738 exports = Some(
739 items.into_iter().map(|export| (export.path(), export)).collect(),
740 );
741 },
742 }
743 }
744 let mast_forest =
745 mast_forest.ok_or_else(|| serde::de::Error::missing_field("mast_forest"))?;
746 let exports = exports.ok_or_else(|| serde::de::Error::missing_field("exports"))?;
747 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
748 }
749 }
750
751 deserializer.deserialize_struct("Library", &["mast_forest", "exports"], LibraryVisitor)
752 }
753}
754
755impl Serializable for KernelLibrary {
757 fn write_into<W: ByteWriter>(&self, target: &mut W) {
758 let Self { kernel: _, kernel_info: _, library } = self;
759
760 library.write_into(target);
761 }
762}
763
764impl Deserializable for KernelLibrary {
766 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
767 let library = Library::read_from(source)?;
768
769 Self::try_from(library).map_err(|err| {
770 DeserializationError::InvalidValue(format!(
771 "Failed to deserialize kernel library: {err}"
772 ))
773 })
774 }
775}
776
777impl Serializable for LibraryExport {
779 fn write_into<W: ByteWriter>(&self, target: &mut W) {
780 match self {
781 LibraryExport::Procedure(ProcedureExport {
782 node,
783 path: name,
784 signature,
785 attributes,
786 }) => {
787 target.write_u8(0);
788 name.write_into(target);
789 target.write_u32(u32::from(*node));
790 if let Some(sig) = signature {
791 target.write_bool(true);
792 sig.write_into(target);
793 } else {
794 target.write_bool(false);
795 }
796 attributes.write_into(target);
797 },
798 LibraryExport::Constant(ConstantExport { path: name, value }) => {
799 target.write_u8(1);
800 name.write_into(target);
801 value.write_into(target);
802 },
803 LibraryExport::Type(TypeExport { path: name, ty }) => {
804 target.write_u8(2);
805 name.write_into(target);
806 ty.write_into(target);
807 },
808 }
809 }
810}
811
812#[cfg(feature = "arbitrary")]
813impl proptest::prelude::Arbitrary for Library {
814 type Parameters = ();
815
816 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
817 use miden_core::{
818 mast::{BasicBlockNodeBuilder, MastForestContributor},
819 operations::Operation,
820 };
821 use proptest::prelude::*;
822
823 prop::collection::vec(any::<LibraryExport>(), 1..5)
824 .prop_map(|exports| {
825 let mut exports =
826 BTreeMap::from_iter(exports.into_iter().map(|export| (export.path(), export)));
827 let mut mast_forest = MastForest::new();
829 let mut nodes = Vec::new();
830
831 for export in exports.values() {
832 if let LibraryExport::Procedure(export) = export {
833 let node_id = BasicBlockNodeBuilder::new(
834 vec![Operation::Add, Operation::Mul],
835 Vec::new(),
836 )
837 .add_to_forest(&mut mast_forest)
838 .unwrap();
839 nodes.push((export.node, node_id));
840 }
841 }
842
843 let mut procedure_exports = 0;
845 for export in exports.values_mut() {
846 match export {
847 LibraryExport::Procedure(export) => {
848 procedure_exports += 1;
849 if let Some(&(_, actual_node_id)) =
851 nodes.iter().find(|(original_id, _)| *original_id == export.node)
852 {
853 export.node = actual_node_id;
854 } else {
855 if let Some(&(_, first_node_id)) = nodes.first() {
858 export.node = first_node_id;
859 } else {
860 panic!("No nodes created for exports");
863 }
864 }
865 },
866 LibraryExport::Constant(_) | LibraryExport::Type(_) => (),
867 }
868 }
869
870 let mut node_ids = Vec::with_capacity(procedure_exports);
871 for export in exports.values() {
872 if let LibraryExport::Procedure(export) = export {
873 mast_forest.make_root(export.node);
875 node_ids.push(export.node);
877 }
878 }
879
880 let digest = mast_forest.compute_nodes_commitment(&node_ids);
882
883 let mast_forest = Arc::new(mast_forest);
884 Library { digest, exports, mast_forest }
885 })
886 .boxed()
887 }
888
889 type Strategy = proptest::prelude::BoxedStrategy<Self>;
890}