Skip to main content

miden_project/
linkage.rs

1use alloc::string::{String, ToString};
2use core::{fmt, str::FromStr};
3
4/// This represents the way in which a dependent will link against a dependency during assembly.
5#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
6#[repr(u8)]
7pub enum Linkage {
8    /// Link against the target package dynamically, i.e. it is expected that the package will be
9    /// provided to the VM at runtime so that it is available for the dependent.
10    #[default]
11    Dynamic = 0,
12    /// Link the contents of the target package into the dependent package, as if they were defined
13    /// as part of the dependent.
14    ///
15    /// This linkage mode ensures that the dependency does not have to be provided to the VM
16    /// separately in order to execute code from the dependent.
17    Static,
18}
19
20impl Linkage {
21    /// Get the string representation of this linkage
22    pub const fn as_str(&self) -> &'static str {
23        match self {
24            Self::Dynamic => "dynamic",
25            Self::Static => "static",
26        }
27    }
28}
29
30impl fmt::Display for Linkage {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        f.write_str(self.as_str())
33    }
34}
35
36/// The error produced when parsing [Linkage] from a string value
37#[derive(Debug, thiserror::Error)]
38#[error("unknown linkage '{0}': expected either 'dynamic' or 'static'")]
39pub struct UnknownLinkageError(String);
40
41impl FromStr for Linkage {
42    type Err = UnknownLinkageError;
43
44    fn from_str(s: &str) -> Result<Self, Self::Err> {
45        match s {
46            "default" | "dynamic" => Ok(Self::Dynamic),
47            "static" => Ok(Self::Static),
48            other => Err(UnknownLinkageError(other.to_string())),
49        }
50    }
51}
52
53#[cfg(feature = "serde")]
54mod serialization {
55    use alloc::format;
56
57    use miden_core::serde::{
58        ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
59    };
60
61    use super::Linkage;
62
63    impl serde::Serialize for Linkage {
64        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
65        where
66            S: serde::Serializer,
67        {
68            if serializer.is_human_readable() {
69                self.as_str().serialize(serializer)
70            } else {
71                (*self as u8).serialize(serializer)
72            }
73        }
74    }
75
76    impl<'de> serde::Deserialize<'de> for Linkage {
77        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78        where
79            D: serde::Deserializer<'de>,
80        {
81            if deserializer.is_human_readable() {
82                <&'de str>::deserialize(deserializer)?
83                    .parse::<Linkage>()
84                    .map_err(serde::de::Error::custom)
85            } else {
86                match u8::deserialize(deserializer)? {
87                    0 => Ok(Self::Dynamic),
88                    1 => Ok(Self::Static),
89                    other => {
90                        Err(serde::de::Error::custom(format!("invalid Linkage tag '{other}'")))
91                    },
92                }
93            }
94        }
95    }
96
97    impl Serializable for Linkage {
98        fn write_into<W: ByteWriter>(&self, target: &mut W) {
99            target.write_u8(*self as u8);
100        }
101    }
102
103    impl Deserializable for Linkage {
104        fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
105            match source.read_u8()? {
106                0 => Ok(Self::Dynamic),
107                1 => Ok(Self::Static),
108                other => Err(DeserializationError::InvalidValue(format!(
109                    "unknown Linkage tag '{other}'"
110                ))),
111            }
112        }
113    }
114}