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 let attributes = AttributeSet::read_from(source)?;
609 LibraryExport::Procedure(ProcedureExport {
610 node,
611 path: path.clone(),
612 signature,
613 attributes,
614 })
615 },
616 1 => {
617 let value = crate::ast::ConstantValue::read_from(source)?;
618 LibraryExport::Constant(ConstantExport { path: path.clone(), value })
619 },
620 2 => {
621 let ty = TypeDeserializer::read_from(source)?.0;
622 LibraryExport::Type(TypeExport { path: path.clone(), ty })
623 },
624 invalid => {
625 return Err(DeserializationError::InvalidValue(format!(
626 "unknown LibraryExport tag: '{invalid}'"
627 )));
628 },
629 };
630 exports.insert(path, export);
631 }
632
633 let digest =
634 mast_forest.compute_nodes_commitment(exports.values().filter_map(|e| match e {
635 LibraryExport::Procedure(e) => Some(&e.node),
636 LibraryExport::Constant(_) | LibraryExport::Type(_) => None,
637 }));
638
639 Ok(Self { digest, exports, mast_forest })
640 }
641}
642
643#[cfg(feature = "serde")]
644impl serde::Serialize for Library {
645 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
646 where
647 S: serde::Serializer,
648 {
649 use serde::ser::SerializeStruct;
650
651 struct LibraryExports<'a>(&'a BTreeMap<Arc<Path>, LibraryExport>);
652 impl serde::Serialize for LibraryExports<'_> {
653 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
654 where
655 S: serde::Serializer,
656 {
657 use serde::ser::SerializeSeq;
658 let mut serializer = serializer.serialize_seq(Some(self.0.len()))?;
659 for elem in self.0.values() {
660 serializer.serialize_element(elem)?;
661 }
662 serializer.end()
663 }
664 }
665
666 let Self { digest: _, exports, mast_forest } = self;
667
668 let mut serializer = serializer.serialize_struct("Library", 2)?;
669 serializer.serialize_field("mast_forest", mast_forest)?;
670 serializer.serialize_field("exports", &LibraryExports(exports))?;
671 serializer.end()
672 }
673}
674
675#[cfg(feature = "serde")]
676impl<'de> serde::Deserialize<'de> for Library {
677 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
678 where
679 D: serde::Deserializer<'de>,
680 {
681 use serde::de::Visitor;
682
683 #[derive(Deserialize)]
684 #[serde(field_identifier, rename_all = "snake_case")]
685 enum Field {
686 MastForest,
687 Exports,
688 }
689
690 struct LibraryVisitor;
691
692 impl<'de> Visitor<'de> for LibraryVisitor {
693 type Value = Library;
694
695 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
696 formatter.write_str("struct Library")
697 }
698
699 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
700 where
701 A: serde::de::SeqAccess<'de>,
702 {
703 let mast_forest = seq
704 .next_element()?
705 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
706 let exports: Vec<LibraryExport> = seq
707 .next_element()?
708 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
709 let exports = exports.into_iter().map(|export| (export.path(), export)).collect();
710 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
711 }
712
713 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
714 where
715 A: serde::de::MapAccess<'de>,
716 {
717 let mut mast_forest = None;
718 let mut exports = None;
719 while let Some(key) = map.next_key()? {
720 match key {
721 Field::MastForest => {
722 if mast_forest.is_some() {
723 return Err(serde::de::Error::duplicate_field("mast_forest"));
724 }
725 mast_forest = Some(map.next_value()?);
726 },
727 Field::Exports => {
728 if exports.is_some() {
729 return Err(serde::de::Error::duplicate_field("exports"));
730 }
731 let items: Vec<LibraryExport> = map.next_value()?;
732 exports = Some(
733 items.into_iter().map(|export| (export.path(), export)).collect(),
734 );
735 },
736 }
737 }
738 let mast_forest =
739 mast_forest.ok_or_else(|| serde::de::Error::missing_field("mast_forest"))?;
740 let exports = exports.ok_or_else(|| serde::de::Error::missing_field("exports"))?;
741 Library::new(mast_forest, exports).map_err(serde::de::Error::custom)
742 }
743 }
744
745 deserializer.deserialize_struct("Library", &["mast_forest", "exports"], LibraryVisitor)
746 }
747}
748
749impl Serializable for KernelLibrary {
751 fn write_into<W: ByteWriter>(&self, target: &mut W) {
752 let Self { kernel: _, kernel_info: _, library } = self;
753
754 library.write_into(target);
755 }
756}
757
758impl Deserializable for KernelLibrary {
760 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
761 let library = Library::read_from(source)?;
762
763 Self::try_from(library).map_err(|err| {
764 DeserializationError::InvalidValue(format!(
765 "Failed to deserialize kernel library: {err}"
766 ))
767 })
768 }
769}
770
771impl Serializable for LibraryExport {
773 fn write_into<W: ByteWriter>(&self, target: &mut W) {
774 match self {
775 LibraryExport::Procedure(ProcedureExport {
776 node,
777 path: name,
778 signature,
779 attributes,
780 }) => {
781 target.write_u8(0);
782 name.write_into(target);
783 target.write_u32(u32::from(*node));
784 if let Some(sig) = signature {
785 target.write_bool(true);
786 FunctionTypeSerializer(sig).write_into(target);
787 } else {
788 target.write_bool(false);
789 }
790 attributes.write_into(target);
791 },
792 LibraryExport::Constant(ConstantExport { path: name, value }) => {
793 target.write_u8(1);
794 name.write_into(target);
795 value.write_into(target);
796 },
797 LibraryExport::Type(TypeExport { path: name, ty }) => {
798 target.write_u8(2);
799 name.write_into(target);
800 TypeSerializer(ty).write_into(target);
801 },
802 }
803 }
804}
805
806pub struct FunctionTypeSerializer<'a>(pub &'a FunctionType);
813
814impl Serializable for FunctionTypeSerializer<'_> {
815 fn write_into<W: ByteWriter>(&self, target: &mut W) {
816 target.write_u8(self.0.abi as u8);
817 target.write_usize(self.0.params().len());
818 target.write_many(self.0.params().iter().map(TypeSerializer));
819 target.write_usize(self.0.results().len());
820 target.write_many(self.0.results().iter().map(TypeSerializer));
821 }
822}
823
824pub struct FunctionTypeDeserializer(pub FunctionType);
831
832impl Deserializable for FunctionTypeDeserializer {
833 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
834 use midenc_hir_type::CallConv;
835
836 let abi = match source.read_u8()? {
837 0 => CallConv::Fast,
838 1 => CallConv::SystemV,
839 2 => CallConv::Wasm,
840 3 => CallConv::CanonLift,
841 4 => CallConv::CanonLower,
842 5 => CallConv::Kernel,
843 invalid => {
844 return Err(DeserializationError::InvalidValue(format!(
845 "invalid CallConv tag: {invalid}"
846 )));
847 },
848 };
849
850 let arity = source.read_usize()?;
851 let mut params = SmallVec::<[Type; 4]>::with_capacity(arity);
852 for _ in 0..arity {
853 let ty = TypeDeserializer::read_from(source)?.0;
854 params.push(ty);
855 }
856
857 let num_results = source.read_usize()?;
858 let mut results = SmallVec::<[Type; 1]>::with_capacity(num_results);
859 for _ in 0..num_results {
860 let ty = TypeDeserializer::read_from(source)?.0;
861 results.push(ty);
862 }
863
864 Ok(Self(FunctionType { abi, params, results }))
865 }
866}
867
868pub struct TypeSerializer<'a>(pub &'a Type);
874
875impl Serializable for TypeSerializer<'_> {
876 fn write_into<W: ByteWriter>(&self, target: &mut W) {
877 use midenc_hir_type::{AddressSpace, TypeRepr};
878
879 match self.0 {
880 Type::Unknown => target.write_u8(0),
881 Type::Never => target.write_u8(1),
882 Type::I1 => target.write_u8(2),
883 Type::I8 => target.write_u8(3),
884 Type::U8 => target.write_u8(4),
885 Type::I16 => target.write_u8(5),
886 Type::U16 => target.write_u8(6),
887 Type::I32 => target.write_u8(7),
888 Type::U32 => target.write_u8(8),
889 Type::I64 => target.write_u8(9),
890 Type::U64 => target.write_u8(10),
891 Type::I128 => target.write_u8(11),
892 Type::U128 => target.write_u8(12),
893 Type::U256 => target.write_u8(13),
894 Type::F64 => target.write_u8(14),
895 Type::Felt => target.write_u8(15),
896 Type::Ptr(ty) => {
897 target.write_u8(16);
898 match ty.addrspace {
899 AddressSpace::Byte => target.write_u8(0),
900 AddressSpace::Element => target.write_u8(1),
901 }
902 TypeSerializer(&ty.pointee).write_into(target);
903 },
904 Type::Struct(ty) => {
905 target.write_u8(17);
906 match ty.repr() {
907 TypeRepr::Default => target.write_u8(0),
908 TypeRepr::Align(align) => {
909 target.write_u8(1);
910 target.write_u16(align.get());
911 },
912 TypeRepr::Packed(align) => {
913 target.write_u8(2);
914 target.write_u16(align.get());
915 },
916 TypeRepr::Transparent => target.write_u8(3),
917 TypeRepr::BigEndian => target.write_u8(4),
918 }
919 target.write_u8(ty.len() as u8);
920 for field in ty.fields() {
921 TypeSerializer(&field.ty).write_into(target);
922 }
923 },
924 Type::Array(ty) => {
925 target.write_u8(18);
926 target.write_usize(ty.len);
927 TypeSerializer(&ty.ty).write_into(target);
928 },
929 Type::List(ty) => {
930 target.write_u8(19);
931 TypeSerializer(ty).write_into(target);
932 },
933 Type::Function(ty) => {
934 target.write_u8(20);
935 FunctionTypeSerializer(ty).write_into(target);
936 },
937 }
938 }
939}
940
941pub struct TypeDeserializer(pub Type);
947
948impl Deserializable for TypeDeserializer {
949 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
950 use alloc::string::ToString;
951 use core::num::NonZeroU16;
952
953 use midenc_hir_type::{AddressSpace, ArrayType, PointerType, StructType, TypeRepr};
954
955 let ty = match source.read_u8()? {
956 0 => Type::Unknown,
957 1 => Type::Never,
958 2 => Type::I1,
959 3 => Type::I8,
960 4 => Type::U8,
961 5 => Type::I16,
962 6 => Type::U16,
963 7 => Type::I32,
964 8 => Type::U32,
965 9 => Type::I64,
966 10 => Type::U64,
967 11 => Type::I128,
968 12 => Type::U128,
969 13 => Type::U256,
970 14 => Type::F64,
971 15 => Type::Felt,
972 16 => {
973 let addrspace = match source.read_u8()? {
974 0 => AddressSpace::Byte,
975 1 => AddressSpace::Element,
976 invalid => {
977 return Err(DeserializationError::InvalidValue(format!(
978 "invalid AddressSpace tag: {invalid}"
979 )));
980 },
981 };
982 let pointee = TypeDeserializer::read_from(source)?.0;
983 Type::Ptr(Arc::new(PointerType { addrspace, pointee }))
984 },
985 17 => {
986 let repr = match source.read_u8()? {
987 0 => TypeRepr::Default,
988 1 => {
989 let align = NonZeroU16::new(source.read_u16()?).ok_or_else(|| {
990 DeserializationError::InvalidValue(
991 "invalid type repr: alignment must be a non-zero value".to_string(),
992 )
993 })?;
994 TypeRepr::Align(align)
995 },
996 2 => {
997 let align = NonZeroU16::new(source.read_u16()?).ok_or_else(|| {
998 DeserializationError::InvalidValue(
999 "invalid type repr: packed alignment must be a non-zero value"
1000 .to_string(),
1001 )
1002 })?;
1003 TypeRepr::Packed(align)
1004 },
1005 3 => TypeRepr::Transparent,
1006 invalid => {
1007 return Err(DeserializationError::InvalidValue(format!(
1008 "invalid TypeRepr tag: {invalid}"
1009 )));
1010 },
1011 };
1012 let num_fields = source.read_u8()?;
1013 let mut fields = SmallVec::<[Type; 4]>::with_capacity(num_fields as usize);
1014 for _ in 0..num_fields {
1015 let ty = TypeDeserializer::read_from(source)?.0;
1016 fields.push(ty);
1017 }
1018 Type::Struct(Arc::new(StructType::new_with_repr(repr, fields)))
1019 },
1020 18 => {
1021 let arity = source.read_usize()?;
1022 let ty = TypeDeserializer::read_from(source)?.0;
1023 Type::Array(Arc::new(ArrayType { ty, len: arity }))
1024 },
1025 19 => {
1026 let ty = TypeDeserializer::read_from(source)?.0;
1027 Type::List(Arc::new(ty))
1028 },
1029 20 => Type::Function(Arc::new(FunctionTypeDeserializer::read_from(source)?.0)),
1030 invalid => {
1031 return Err(DeserializationError::InvalidValue(format!(
1032 "invalid Type tag: {invalid}"
1033 )));
1034 },
1035 };
1036 Ok(Self(ty))
1037 }
1038}
1039
1040#[cfg(feature = "arbitrary")]
1041impl proptest::prelude::Arbitrary for Library {
1042 type Parameters = ();
1043
1044 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
1045 use miden_core::{
1046 Operation,
1047 mast::{BasicBlockNodeBuilder, MastForestContributor},
1048 };
1049 use proptest::prelude::*;
1050
1051 prop::collection::vec(any::<LibraryExport>(), 1..5)
1052 .prop_map(|exports| {
1053 let mut exports =
1054 BTreeMap::from_iter(exports.into_iter().map(|export| (export.path(), export)));
1055 let mut mast_forest = MastForest::new();
1057 let mut nodes = Vec::new();
1058
1059 for export in exports.values() {
1060 if let LibraryExport::Procedure(export) = export {
1061 let node_id = BasicBlockNodeBuilder::new(
1062 vec![Operation::Add, Operation::Mul],
1063 Vec::new(),
1064 )
1065 .add_to_forest(&mut mast_forest)
1066 .unwrap();
1067 nodes.push((export.node, node_id));
1068 }
1069 }
1070
1071 let mut procedure_exports = 0;
1073 for export in exports.values_mut() {
1074 match export {
1075 LibraryExport::Procedure(export) => {
1076 procedure_exports += 1;
1077 if let Some(&(_, actual_node_id)) =
1079 nodes.iter().find(|(original_id, _)| *original_id == export.node)
1080 {
1081 export.node = actual_node_id;
1082 } else {
1083 if let Some(&(_, first_node_id)) = nodes.first() {
1086 export.node = first_node_id;
1087 } else {
1088 panic!("No nodes created for exports");
1091 }
1092 }
1093 },
1094 LibraryExport::Constant(_) | LibraryExport::Type(_) => (),
1095 }
1096 }
1097
1098 let mut node_ids = Vec::with_capacity(procedure_exports);
1099 for export in exports.values() {
1100 if let LibraryExport::Procedure(export) = export {
1101 mast_forest.make_root(export.node);
1103 node_ids.push(export.node);
1105 }
1106 }
1107
1108 let digest = mast_forest.compute_nodes_commitment(&node_ids);
1110
1111 let mast_forest = Arc::new(mast_forest);
1112 Library { digest, exports, mast_forest }
1113 })
1114 .boxed()
1115 }
1116
1117 type Strategy = proptest::prelude::BoxedStrategy<Self>;
1118}