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