strict_types/
util.rs

1// Strict encoding schema library, implementing validation and parsing of strict encoded data
2// against a schema.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Designed in 2019-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
7// Written in 2024-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
8//
9// Copyright (C) 2022-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
10//                         Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
11// Copyright (C) 2022-2025 Dr Maxim Orlovsky.
12// All rights under the above copyrights are reserved.
13//
14// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
15// in compliance with the License. You may obtain a copy of the License at
16//
17//        http://www.apache.org/licenses/LICENSE-2.0
18//
19// Unless required by applicable law or agreed to in writing, software distributed under the License
20// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
21// or implied. See the License for the specific language governing permissions and limitations under
22// the License.
23
24use std::env;
25use std::fmt::{self, Display, Formatter};
26use std::str::FromStr;
27
28use amplify::confinement::TinyVec;
29use strict_encoding::{Ident, STRICT_TYPES_LIB};
30
31use crate::typelib::TypeLibId;
32use crate::SemId;
33
34#[derive(Clone, Eq, PartialEq, Debug, Display, Error)]
35#[display("unknown name for the file format '{0}'")]
36pub struct UnknownFormat(String);
37
38#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
39pub enum StlFormat {
40    #[display("sty")]
41    Source,
42    #[display("stl")]
43    Binary,
44    #[cfg(feature = "armor")]
45    #[display("sta")]
46    Armored,
47}
48
49impl FromStr for StlFormat {
50    type Err = UnknownFormat;
51
52    fn from_str(s: &str) -> Result<Self, Self::Err> {
53        match s {
54            "stl" => Ok(StlFormat::Binary),
55            #[cfg(feature = "armor")]
56            "sta" => Ok(StlFormat::Armored),
57            "sty" => Ok(StlFormat::Source),
58            invalid => Err(UnknownFormat(invalid.to_owned())),
59        }
60    }
61}
62
63pub fn parse_args() -> (StlFormat, Option<String>) {
64    let args: Vec<String> = env::args().collect();
65    let ext = args.get(1).map(String::as_str).map(|s| s.trim_start_matches("--")).unwrap_or("sty");
66    let format = StlFormat::from_str(ext).expect("unrecognized file format argument");
67    let dir = match args.len() {
68        1 => None,
69        2 | 3 => Some(args.get(2).cloned().unwrap_or_else(|| s!("stl"))),
70        _ => panic!("invalid argument count"),
71    };
72    (format, dir)
73}
74
75/* TODO: Move into layout mod
76/// Measure of a type size in bytes
77#[derive(Copy, Clone, PartialEq, Eq, Debug, Display)]
78pub enum Size {
79    /// Type has a fixed size known at compile time
80    #[display(inner)]
81    Fixed(u16),
82
83    /// Type has variable size
84    #[display("variable")]
85    Variable,
86}
87
88impl PartialOrd for Size {
89    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
90}
91
92impl Ord for Size {
93    fn cmp(&self, other: &Self) -> Ordering {
94        match (self, other) {
95            (Size::Variable, Size::Variable) => Ordering::Equal,
96            (Size::Variable, _) => Ordering::Greater,
97            (_, Size::Variable) => Ordering::Less,
98            (Size::Fixed(a), Size::Fixed(b)) => a.cmp(b),
99        }
100    }
101}
102
103impl Add for Size {
104    type Output = Size;
105
106    fn add(self, rhs: Self) -> Self::Output {
107        match (self, rhs) {
108            (Size::Fixed(a), Size::Fixed(b)) => Size::Fixed(a + b),
109            _ => Size::Variable,
110        }
111    }
112}
113
114impl AddAssign for Size {
115    fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; }
116}
117
118impl Sum for Size {
119    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
120        let mut acc = Size::Fixed(0);
121        for item in iter {
122            acc += item;
123        }
124        acc
125    }
126}
127 */
128
129#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, From)]
130#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
131#[strict_type(lib = STRICT_TYPES_LIB, tags = order, dumb = { PreFragment::Digits(1) })]
132#[display(inner)]
133pub enum PreFragment {
134    #[from]
135    Ident(Ident),
136    #[from]
137    Digits(u128),
138}
139
140#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)]
141#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
142#[strict_type(lib = STRICT_TYPES_LIB, tags = order, dumb = { BuildFragment::Ident(Ident::from("alpha")) })]
143#[display(inner)]
144pub enum BuildFragment {
145    Ident(Ident),
146    Digits(Ident),
147}
148
149// TODO: Manually implement Ord, PartialOrd
150#[derive(Clone, Eq, PartialEq, Hash, Debug)]
151#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
152#[strict_type(lib = STRICT_TYPES_LIB)]
153pub struct SemVer {
154    pub major: u16,
155    pub minor: u16,
156    pub patch: u16,
157    pub pre: TinyVec<PreFragment>,
158    pub build: TinyVec<BuildFragment>,
159}
160
161impl SemVer {
162    pub fn new(major: u16, minor: u16, patch: u16) -> Self {
163        SemVer {
164            major,
165            minor,
166            patch,
167            pre: none!(),
168            build: none!(),
169        }
170    }
171}
172
173impl Display for SemVer {
174    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
175        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
176
177        if !self.build.is_empty() {
178            f.write_str("-")?;
179        }
180        let mut len = self.build.len();
181        for item in &self.build {
182            Display::fmt(item, f)?;
183            len -= 1;
184            if len > 0 {
185                f.write_str(".")?;
186            }
187        }
188
189        if !self.pre.is_empty() {
190            f.write_str("+")?;
191        }
192        let mut len = self.pre.len();
193        for item in &self.pre {
194            Display::fmt(item, f)?;
195            len -= 1;
196            if len > 0 {
197                f.write_str(".")?;
198            }
199        }
200        Ok(())
201    }
202}
203
204#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)]
205pub enum Urn {
206    #[from]
207    #[display("urn:sten:lib:{0}", alt = "urn:sten:lib:{0:#}")]
208    Lib(TypeLibId),
209
210    #[from]
211    #[display("urn:sten:id:{0}", alt = "urn:sten:id:{0:#}")]
212    Type(SemId),
213}