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(mut self, advice_map: AdviceMap) -> Self {
297 self.extend_advice_map(advice_map);
298 self
299 }
300
301 pub fn extend_advice_map(&mut self, advice_map: AdviceMap) {
303 let mast_forest = Arc::make_mut(&mut self.mast_forest);
304 mast_forest.advice_map_mut().extend(advice_map);
305 }
306}
307
308impl Library {
311 pub fn digest(&self) -> &Word {
313 &self.digest
314 }
315
316 pub fn exports(&self) -> impl Iterator<Item = &LibraryExport> {
318 self.exports.values()
319 }
320
321 pub fn num_exports(&self) -> usize {
323 self.exports.len()
324 }
325
326 pub fn get_export_node_id(&self, path: impl AsRef<Path>) -> MastNodeId {
331 let path = path.as_ref().to_absolute();
332 self.exports
333 .get(path.as_ref())
334 .expect("procedure not exported from the library")
335 .unwrap_procedure()
336 .node
337 }
338
339 pub fn is_reexport(&self, path: impl AsRef<Path>) -> bool {
341 let path = path.as_ref().to_absolute();
342 self.exports
343 .get(path.as_ref())
344 .and_then(LibraryExport::as_procedure)
345 .map(|export| self.mast_forest[export.node].is_external())
346 .unwrap_or(false)
347 }
348
349 pub fn mast_forest(&self) -> &Arc<MastForest> {
351 &self.mast_forest
352 }
353
354 pub fn get_procedure_root_by_path(&self, path: impl AsRef<Path>) -> Option<Word> {
357 let path = path.as_ref().to_absolute();
358 let export = self.exports.get(path.as_ref()).and_then(LibraryExport::as_procedure);
359 export.map(|e| self.mast_forest()[e.node].digest())
360 }
361}
362
363impl Library {
365 pub fn module_infos(&self) -> impl Iterator<Item = ModuleInfo> {
367 let mut modules_by_path: BTreeMap<Arc<Path>, ModuleInfo> = BTreeMap::new();
368
369 for export in self.exports.values() {
370 let module_name =
371 Arc::from(export.path().parent().unwrap().to_path_buf().into_boxed_path());
372 let module = modules_by_path
373 .entry(Arc::clone(&module_name))
374 .or_insert_with(|| ModuleInfo::new(module_name, None));
375 match export {
376 LibraryExport::Procedure(ProcedureExport { node, path, signature, attributes }) => {
377 let proc_digest = self.mast_forest[*node].digest();
378 let name = path.last().unwrap();
379 module.add_procedure(
380 ProcedureName::new(name).expect("valid procedure name"),
381 proc_digest,
382 signature.clone().map(Arc::new),
383 attributes.clone(),
384 );
385 },
386 LibraryExport::Constant(ConstantExport { path, value }) => {
387 let name = Ident::new(path.last().unwrap()).expect("valid identifier");
388 module.add_constant(name, value.clone());
389 },
390 LibraryExport::Type(TypeExport { path, ty }) => {
391 let name = Ident::new(path.last().unwrap()).expect("valid identifier");
392 module.add_type(name, ty.clone());
393 },
394 }
395 }
396
397 modules_by_path.into_values()
398 }
399}
400
401#[cfg(feature = "std")]
402impl Library {
403 pub const LIBRARY_EXTENSION: &'static str = "masl";
405
406 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
412 let path = path.as_ref();
413
414 if let Some(dir) = path.parent() {
415 std::fs::create_dir_all(dir)?;
416 }
417
418 std::panic::catch_unwind(|| {
422 let mut file = std::fs::File::create(path)?;
423 self.write_into(&mut file);
424 Ok(())
425 })
426 .map_err(|p| {
427 match p.downcast::<std::io::Error>() {
428 Ok(err) => unsafe { core::ptr::read(&*err) },
430 Err(err) => std::panic::resume_unwind(err),
431 }
432 })?
433 }
434
435 pub fn deserialize_from_file(
436 path: impl AsRef<std::path::Path>,
437 ) -> Result<Self, DeserializationError> {
438 use miden_core::utils::ReadAdapter;
439
440 let path = path.as_ref();
441 let mut file = std::fs::File::open(path).map_err(|err| {
442 DeserializationError::InvalidValue(format!(
443 "failed to open file at {}: {err}",
444 path.to_string_lossy()
445 ))
446 })?;
447 let mut adapter = ReadAdapter::new(&mut file);
448
449 Self::read_from(&mut adapter)
450 }
451}
452
453#[derive(Debug, Clone, PartialEq, Eq)]
463#[cfg_attr(feature = "serde", derive(Deserialize))]
464#[cfg_attr(feature = "serde", serde(try_from = "Arc<Library>"))]
465pub struct KernelLibrary {
466 #[cfg_attr(feature = "serde", serde(skip))]
467 kernel: Kernel,
468 #[cfg_attr(feature = "serde", serde(skip))]
469 kernel_info: ModuleInfo,
470 library: Arc<Library>,
471}
472
473#[cfg(feature = "serde")]
474impl serde::Serialize for KernelLibrary {
475 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
476 where
477 S: serde::Serializer,
478 {
479 Library::serialize(&self.library, serializer)
480 }
481}
482
483impl AsRef<Library> for KernelLibrary {
484 #[inline(always)]
485 fn as_ref(&self) -> &Library {
486 &self.library
487 }
488}
489
490impl KernelLibrary {
491 pub fn kernel(&self) -> &Kernel {
493 &self.kernel
494 }
495
496 pub fn mast_forest(&self) -> &Arc<MastForest> {
498 self.library.mast_forest()
499 }
500
501 pub fn into_parts(self) -> (Kernel, ModuleInfo, Arc<MastForest>) {
503 (self.kernel, self.kernel_info, self.library.mast_forest().clone())
504 }
505}
506
507impl TryFrom<Arc<Library>> for KernelLibrary {
508 type Error = LibraryError;
509
510 fn try_from(library: Arc<Library>) -> Result<Self, Self::Error> {
511 let kernel_path = Arc::from(Path::kernel_path().to_path_buf().into_boxed_path());
512 let mut proc_digests = Vec::with_capacity(library.exports.len());
513
514 let mut kernel_module = ModuleInfo::new(Arc::clone(&kernel_path), None);
515
516 for export in library.exports.values() {
517 match export {
518 LibraryExport::Procedure(export) => {
519 if !export.path.is_in_kernel() {
521 return Err(LibraryError::InvalidKernelExport {
522 procedure_path: export.path.clone(),
523 });
524 }
525
526 let proc_digest = library.mast_forest[export.node].digest();
527 proc_digests.push(proc_digest);
528 kernel_module.add_procedure(
529 ProcedureName::new(export.path.last().unwrap())
530 .expect("valid procedure name"),
531 proc_digest,
532 export.signature.clone().map(Arc::new),
533 export.attributes.clone(),
534 );
535 },
536 LibraryExport::Constant(export) => {
537 if export.path.is_in_kernel() {
539 let name =
540 Ident::new(export.path.last().unwrap()).expect("valid identifier");
541 kernel_module.add_constant(name, export.value.clone());
542 }
543 },
544 LibraryExport::Type(export) => {
545 if export.path.is_in_kernel() {
547 let name =
548 Ident::new(export.path.last().unwrap()).expect("valid identifier");
549 kernel_module.add_type(name, export.ty.clone());
550 }
551 },
552 }
553 }
554
555 if proc_digests.is_empty() {
556 return Err(LibraryError::NoExport);
557 }
558
559 let kernel = Kernel::new(&proc_digests).map_err(LibraryError::KernelConversion)?;
560
561 Ok(Self {
562 kernel,
563 kernel_info: kernel_module,
564 library,
565 })
566 }
567}
568
569#[cfg(feature = "std")]
570impl KernelLibrary {
571 pub fn write_to_file(&self, path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
573 self.library.write_to_file(path)
574 }
575}
576
577impl Serializable for Library {
582 fn write_into<W: ByteWriter>(&self, target: &mut W) {
583 let Self { digest: _, exports, mast_forest } = self;
584
585 mast_forest.write_into(target);
586
587 target.write_usize(exports.len());
588 for export in exports.values() {
589 export.write_into(target);
590 }
591 }
592}
593
594impl Deserializable for Library {
596 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
597 let mast_forest = Arc::new(MastForest::read_from(source)?);
598
599 let num_exports = source.read_usize()?;
600 if num_exports == 0 {
601 return Err(DeserializationError::InvalidValue(String::from("No exported procedures")));
602 };
603 let mut exports = BTreeMap::new();
604 for _ in 0..num_exports {
605 let tag = source.read_u8()?;
606 let path: PathBuf = source.read()?;
607 let path = Arc::<Path>::from(path.into_boxed_path());
608 let export = match tag {
609 0 => {
610 let node = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;
611 let signature = if source.read_bool()? {
612 Some(FunctionType::read_from(source)?)
613 } else {
614 None
615 };
616 let attributes = AttributeSet::read_from(source)?;
617 LibraryExport::Procedure(ProcedureExport {
618 node,
619 path: path.clone(),
620 signature,
621 attributes,
622 })
623 },
624 1 => {
625 let value = crate::ast::ConstantValue::read_from(source)?;
626 LibraryExport::Constant(ConstantExport { path: path.clone(), value })
627 },
628 2 => {
629 let ty = Type::read_from(source)?;
630 LibraryExport::Type(TypeExport { path: path.clone(), ty })
631 },
632 invalid => {
633 return Err(DeserializationError::InvalidValue(format!(
634 "unknown LibraryExport tag: '{invalid}'"
635 )));
636 },
637 };
638 exports.insert(path, export);
639 }
640
641 let digest =
642 mast_forest.compute_nodes_commitment(exports.values().filter_map(|e| match e {
643 LibraryExport::Procedure(e) => Some(&e.node),
644 LibraryExport::Constant(_) | LibraryExport::Type(_) => None,
645 }));
646
647 Ok(Self { digest, exports, mast_forest })
648 }
649}
650
651#[cfg(feature = "serde")]
652impl serde::Serialize for Library {
653 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
654 where
655 S: serde::Serializer,
656 {
657 use serde::ser::SerializeStruct;
658
659 struct LibraryExports<'a>(&'a BTreeMap<Arc<Path>, LibraryExport>);
660 impl serde::Serialize for LibraryExports<'_> {
661 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
662 where
663 S: serde::Serializer,
664 {
665 use serde::ser::SerializeSeq;
666 let mut serializer = serializer.serialize_seq(Some(self.0.len()))?;
667 for elem in self.0.values() {
668 serializer.serialize_element(elem)?;
669 }
670 serializer.end()
671 }
672 }
673
674 let Self { digest: _, exports, mast_forest } = self;
675
676 let mut serializer = serializer.serialize_struct("Library", 2)?;
677 serializer.serialize_field("mast_forest", mast_forest)?;
678 serializer.serialize_field("exports", &LibraryExports(exports))?;
679 serializer.end()
680 }
681}
682
683#[cfg(feature = "serde")]
684impl<'de> serde::Deserialize<'de> for Library {
685 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
686 where
687 D: serde::Deserializer<'de>,
688 {
689 use serde::de::Visitor;
690
691 #[derive(Deserialize)]
692 #[serde(field_identifier, rename_all = "snake_case")]
693 enum Field {
694 MastForest,
695 Exports,
696 }
697
698 struct LibraryVisitor;
699
700 impl<'de> Visitor<'de> for LibraryVisitor {
701 type Value = Library;
702
703 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
704 formatter.write_str("struct Library")
705 }
706
707 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
708 where
709 A: serde::de::SeqAccess<'de>,
710 {
711 let mast_forest = seq
712 .next_element()?
713 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
714 let exports: Vec<LibraryExport> = seq
715 .next_element()?
716 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
717 let exports = exports.into_iter().map(|export| (export.path(), export)).collect();
718 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
719 }
720
721 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
722 where
723 A: serde::de::MapAccess<'de>,
724 {
725 let mut mast_forest = None;
726 let mut exports = None;
727 while let Some(key) = map.next_key()? {
728 match key {
729 Field::MastForest => {
730 if mast_forest.is_some() {
731 return Err(serde::de::Error::duplicate_field("mast_forest"));
732 }
733 mast_forest = Some(map.next_value()?);
734 },
735 Field::Exports => {
736 if exports.is_some() {
737 return Err(serde::de::Error::duplicate_field("exports"));
738 }
739 let items: Vec<LibraryExport> = map.next_value()?;
740 exports = Some(
741 items.into_iter().map(|export| (export.path(), export)).collect(),
742 );
743 },
744 }
745 }
746 let mast_forest =
747 mast_forest.ok_or_else(|| serde::de::Error::missing_field("mast_forest"))?;
748 let exports = exports.ok_or_else(|| serde::de::Error::missing_field("exports"))?;
749 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
750 }
751 }
752
753 deserializer.deserialize_struct("Library", &["mast_forest", "exports"], LibraryVisitor)
754 }
755}
756
757impl Serializable for KernelLibrary {
759 fn write_into<W: ByteWriter>(&self, target: &mut W) {
760 let Self { kernel: _, kernel_info: _, library } = self;
761
762 library.write_into(target);
763 }
764}
765
766impl Deserializable for KernelLibrary {
768 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
769 let library = Arc::new(Library::read_from(source)?);
770
771 Self::try_from(library).map_err(|err| {
772 DeserializationError::InvalidValue(format!(
773 "Failed to deserialize kernel library: {err}"
774 ))
775 })
776 }
777}
778
779impl Serializable for LibraryExport {
781 fn write_into<W: ByteWriter>(&self, target: &mut W) {
782 match self {
783 LibraryExport::Procedure(ProcedureExport {
784 node,
785 path: name,
786 signature,
787 attributes,
788 }) => {
789 target.write_u8(0);
790 name.write_into(target);
791 target.write_u32(u32::from(*node));
792 if let Some(sig) = signature {
793 target.write_bool(true);
794 sig.write_into(target);
795 } else {
796 target.write_bool(false);
797 }
798 attributes.write_into(target);
799 },
800 LibraryExport::Constant(ConstantExport { path: name, value }) => {
801 target.write_u8(1);
802 name.write_into(target);
803 value.write_into(target);
804 },
805 LibraryExport::Type(TypeExport { path: name, ty }) => {
806 target.write_u8(2);
807 name.write_into(target);
808 ty.write_into(target);
809 },
810 }
811 }
812}
813
814#[cfg(feature = "arbitrary")]
815impl proptest::prelude::Arbitrary for Library {
816 type Parameters = ();
817
818 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
819 use miden_core::{
820 mast::{BasicBlockNodeBuilder, MastForestContributor},
821 operations::Operation,
822 };
823 use proptest::prelude::*;
824
825 prop::collection::vec(any::<LibraryExport>(), 1..5)
826 .prop_map(|exports| {
827 let mut exports =
828 BTreeMap::from_iter(exports.into_iter().map(|export| (export.path(), export)));
829 let mut mast_forest = MastForest::new();
831 let mut nodes = Vec::new();
832
833 for export in exports.values() {
834 if let LibraryExport::Procedure(export) = export {
835 let node_id = BasicBlockNodeBuilder::new(
836 vec![Operation::Add, Operation::Mul],
837 Vec::new(),
838 )
839 .add_to_forest(&mut mast_forest)
840 .unwrap();
841 nodes.push((export.node, node_id));
842 }
843 }
844
845 let mut procedure_exports = 0;
847 for export in exports.values_mut() {
848 match export {
849 LibraryExport::Procedure(export) => {
850 procedure_exports += 1;
851 if let Some(&(_, actual_node_id)) =
853 nodes.iter().find(|(original_id, _)| *original_id == export.node)
854 {
855 export.node = actual_node_id;
856 } else {
857 if let Some(&(_, first_node_id)) = nodes.first() {
860 export.node = first_node_id;
861 } else {
862 panic!("No nodes created for exports");
865 }
866 }
867 },
868 LibraryExport::Constant(_) | LibraryExport::Type(_) => (),
869 }
870 }
871
872 let mut node_ids = Vec::with_capacity(procedure_exports);
873 for export in exports.values() {
874 if let LibraryExport::Procedure(export) = export {
875 mast_forest.make_root(export.node);
877 node_ids.push(export.node);
879 }
880 }
881
882 let digest = mast_forest.compute_nodes_commitment(&node_ids);
884
885 let mast_forest = Arc::new(mast_forest);
886 Library { digest, exports, mast_forest }
887 })
888 .boxed()
889 }
890
891 type Strategy = proptest::prelude::BoxedStrategy<Self>;
892}