Skip to main content

miden_project/
target_type.rs

1#[cfg(feature = "serde")]
2use alloc::string::String;
3use alloc::{boxed::Box, string::ToString};
4use core::fmt;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
8
9// TARGET TYPE
10// ================================================================================================
11
12/// The type of a specific target provided by the current project
13///
14/// This describes how a package produced from this project can be used (e.g. as an account
15/// component, a note script, etc.).
16#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
17#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
18#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)]
19#[non_exhaustive]
20#[repr(u8)]
21pub enum TargetType {
22    /// A generic code library
23    #[default]
24    Library = 0,
25    /// An executable program
26    Executable = 1,
27    /// A kernel library
28    Kernel = 2,
29    /// An account component
30    AccountComponent = 3,
31    /// A note script
32    NoteScript = 4,
33    /// A transaction script
34    TransactionScript = 5,
35}
36
37impl TargetType {
38    /// Returns true if the target is an executable artifact
39    pub const fn is_executable(&self) -> bool {
40        matches!(self, Self::Executable)
41    }
42
43    /// Returns true if the target is a library-like artifact
44    pub const fn is_library(&self) -> bool {
45        !self.is_executable()
46    }
47
48    /// Returns the string representation of this package kind.
49    pub const fn as_str(&self) -> &'static str {
50        match self {
51            Self::Library => "library",
52            Self::Executable => "executable",
53            Self::Kernel => "kernel",
54            Self::AccountComponent => "account-component",
55            Self::NoteScript => "note",
56            Self::TransactionScript => "transaction-script",
57        }
58    }
59}
60
61// CONVERSIONS
62// ================================================================================================
63
64impl TryFrom<u8> for TargetType {
65    type Error = InvalidTargetTypeError;
66
67    fn try_from(value: u8) -> Result<Self, Self::Error> {
68        match value {
69            0 => Ok(Self::Library),
70            1 => Ok(Self::Executable),
71            2 => Ok(Self::Kernel),
72            3 => Ok(Self::AccountComponent),
73            4 => Ok(Self::NoteScript),
74            5 => Ok(Self::TransactionScript),
75            _ => Err(InvalidTargetTypeError::Tag(value)),
76        }
77    }
78}
79
80impl From<TargetType> for u8 {
81    #[inline(always)]
82    fn from(kind: TargetType) -> Self {
83        kind as u8
84    }
85}
86
87impl fmt::Display for TargetType {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.write_str(self.as_str())
90    }
91}
92
93impl core::str::FromStr for TargetType {
94    type Err = InvalidTargetTypeError;
95
96    fn from_str(s: &str) -> Result<Self, Self::Err> {
97        match s {
98            "lib" | "library" => Ok(Self::Library),
99            "bin" | "program" | "executable" => Ok(Self::Executable),
100            "kernel" => Ok(Self::Kernel),
101            "account" | "account-component" => Ok(Self::AccountComponent),
102            "note" => Ok(Self::NoteScript),
103            "tx-script" | "transaction-script" => Ok(Self::TransactionScript),
104            s => Err(InvalidTargetTypeError::Name(s.to_string().into_boxed_str())),
105        }
106    }
107}
108
109// SERIALIZATION
110// ================================================================================================
111
112#[cfg(feature = "serde")]
113impl Serialize for TargetType {
114    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115    where
116        S: Serializer,
117    {
118        if serializer.is_human_readable() {
119            serializer.serialize_str(self.as_str())
120        } else {
121            serializer.serialize_u8(*self as u8)
122        }
123    }
124}
125
126#[cfg(feature = "serde")]
127impl<'de> Deserialize<'de> for TargetType {
128    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
129    where
130        D: Deserializer<'de>,
131    {
132        if deserializer.is_human_readable() {
133            let s = String::deserialize(deserializer)?;
134            s.parse::<TargetType>().map_err(|err| DeError::custom(err.to_string()))
135        } else {
136            let tag = u8::deserialize(deserializer)?;
137            Self::try_from(tag).map_err(|err| DeError::custom(err.to_string()))
138        }
139    }
140}
141
142// ERROR
143// ================================================================================================
144
145/// Error returned when trying to convert an integer/string to a valid [TargetType]
146#[derive(Debug, Clone, PartialEq, Eq)]
147pub enum InvalidTargetTypeError {
148    /// Invalid project type tag (binary representation)
149    Tag(u8),
150    /// Invalid project type name (human-readable representation)
151    Name(Box<str>),
152}
153
154impl fmt::Display for InvalidTargetTypeError {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        match self {
157            Self::Tag(tag) => write!(f, "invalid target type tag: {tag}"),
158            Self::Name(name) => write!(f, "invalid target type: '{name}'"),
159        }
160    }
161}