Skip to main content

simplicity/jet/
type_name.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! # Manual type specification
4//!
5//! Source and target types of jet nodes need to be specified manually.
6
7use crate::types::{self, Final, Type};
8use crate::Tmr;
9use std::cmp;
10use std::sync::Arc;
11
12/// Byte-based specification of a Simplicity type.
13///
14/// Because jets are black boxes, the type inference engine has no access to their
15/// source and target types. Therefore, these types need to be specified manually.
16///
17/// The types are written in prefix (aka Polish) notation,
18/// where `+` and `*` represent sum and product types, respectively,
19/// and base types are represented by the following:
20///
21/// | char | type         |
22/// |------|--------------|
23/// | `1`  | unit         |
24/// | `2`  | single bit   |
25/// | `c`  | 8-bit word   |
26/// | `s`  | 16-bit word  |
27/// | `i`  | 32-bit word  |
28/// | `l`  | 64-bit word  |
29/// | `h`  | 256-bit word |
30///
31#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
32pub struct TypeName(pub &'static [u8]);
33
34impl PartialEq<Final> for TypeName {
35    fn eq(&self, other: &Final) -> bool {
36        self.tmr() == other.tmr()
37    }
38}
39
40impl PartialEq<TypeName> for Final {
41    fn eq(&self, other: &TypeName) -> bool {
42        self.tmr() == other.tmr()
43    }
44}
45
46impl TypeName {
47    /// Convert the type name into a type.
48    pub fn to_type<'brand>(&self, ctx: &types::Context<'brand>) -> Type<'brand> {
49        Type::complete(ctx, self.to_final())
50    }
51
52    /// Convert the type name into a finalized type.
53    pub fn to_final(&self) -> Arc<Final> {
54        let mut stack = Vec::with_capacity(16);
55
56        for c in self.0.iter().rev() {
57            match c {
58                b'1' => stack.push(Final::unit()),
59                b'2' => stack.push(Final::two_two_n_fixed::<0>()),
60                b'c' => stack.push(Final::two_two_n_fixed::<3>()),
61                b's' => stack.push(Final::two_two_n_fixed::<4>()),
62                b'i' => stack.push(Final::two_two_n_fixed::<5>()),
63                b'l' => stack.push(Final::two_two_n_fixed::<6>()),
64                b'h' => stack.push(Final::two_two_n_fixed::<8>()),
65                b'+' | b'*' => {
66                    let left = stack.pop().expect("Illegal type name syntax!");
67                    let right = stack.pop().expect("Illegal type name syntax!");
68
69                    match c {
70                        b'+' => stack.push(Final::sum(left, right)),
71                        b'*' => stack.push(Final::product(left, right)),
72                        _ => unreachable!(),
73                    }
74                }
75                _ => panic!("Illegal type name syntax!"),
76            }
77        }
78
79        if stack.len() == 1 {
80            stack.pop().unwrap()
81        } else {
82            panic!("Illegal type name syntax!")
83        }
84    }
85
86    /// Compute the TMR of the type name.
87    pub fn tmr(&self) -> Tmr {
88        let mut stack = Vec::with_capacity(16);
89
90        for c in self.0.iter().rev() {
91            match c {
92                b'1' => stack.push(Tmr::unit()),
93                b'2' => stack.push(Tmr::TWO_TWO_N[0]),
94                b'c' => stack.push(Tmr::TWO_TWO_N[3]),
95                b's' => stack.push(Tmr::TWO_TWO_N[4]),
96                b'i' => stack.push(Tmr::TWO_TWO_N[5]),
97                b'l' => stack.push(Tmr::TWO_TWO_N[6]),
98                b'h' => stack.push(Tmr::TWO_TWO_N[8]),
99                b'+' | b'*' => {
100                    let left = stack.pop().expect("Illegal type name syntax!");
101                    let right = stack.pop().expect("Illegal type name syntax!");
102
103                    match c {
104                        b'+' => stack.push(Tmr::sum(left, right)),
105                        b'*' => stack.push(Tmr::product(left, right)),
106                        _ => unreachable!(),
107                    }
108                }
109                _ => panic!("Illegal type name syntax!"),
110            }
111        }
112
113        if stack.len() == 1 {
114            stack.pop().unwrap()
115        } else {
116            panic!("Illegal type name syntax!")
117        }
118    }
119
120    /// Convert the type name into a type's bitwidth.
121    ///
122    /// This is more efficient than creating the type and computing its bit-width
123    pub fn to_bit_width(&self) -> usize {
124        let mut stack = Vec::with_capacity(16);
125
126        for c in self.0.iter().rev() {
127            match c {
128                b'1' => stack.push(0),
129                b'2' => stack.push(1),
130                b'c' => stack.push(8),
131                b's' => stack.push(16),
132                b'i' => stack.push(32),
133                b'l' => stack.push(64),
134                b'h' => stack.push(256),
135                b'+' | b'*' => {
136                    let left = stack.pop().expect("Illegal type name syntax!");
137                    let right = stack.pop().expect("Illegal type name syntax!");
138
139                    match c {
140                        b'+' => stack.push(1 + cmp::max(left, right)),
141                        b'*' => stack.push(left + right),
142                        _ => unreachable!(),
143                    }
144                }
145                _ => panic!("Illegal type name syntax!"),
146            }
147        }
148
149        if stack.len() == 1 {
150            stack.pop().unwrap()
151        } else {
152            panic!("Illegal type name syntax!")
153        }
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use crate::jet::{Core, Jet};
160
161    #[test]
162    fn all_jet_tmrs() {
163        for jet in &Core::ALL {
164            let source_final = jet.source_ty().to_final();
165            let target_final = jet.target_ty().to_final();
166
167            assert_eq!(*source_final, jet.source_ty());
168            assert_eq!(jet.source_ty(), *source_final);
169            assert_eq!(source_final.tmr(), jet.source_ty().tmr());
170            assert_eq!(source_final.bit_width(), jet.source_ty().to_bit_width());
171
172            assert_eq!(*target_final, jet.target_ty());
173            assert_eq!(jet.target_ty(), *target_final);
174            assert_eq!(target_final.tmr(), jet.target_ty().tmr());
175            assert_eq!(target_final.bit_width(), jet.target_ty().to_bit_width());
176        }
177    }
178}