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 std::cmp;
9use std::sync::Arc;
10
11/// Byte-based specification of a Simplicity type.
12///
13/// Because jets are black boxes, the type inference engine has no access to their
14/// source and target types. Therefore, these types need to be specified manually.
15///
16/// The types are written in prefix (aka Polish) notation,
17/// where `+` and `*` represent sum and product types, respectively,
18/// and base types are represented by the following:
19///
20/// | char | type         |
21/// |------|--------------|
22/// | `1`  | unit         |
23/// | `2`  | single bit   |
24/// | `c`  | 8-bit word   |
25/// | `s`  | 16-bit word  |
26/// | `i`  | 32-bit word  |
27/// | `l`  | 64-bit word  |
28/// | `h`  | 256-bit word |
29///
30#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
31pub struct TypeName(pub &'static [u8]);
32
33impl TypeName {
34    /// Convert the type name into a type.
35    pub fn to_type<'brand>(&self, ctx: &types::Context<'brand>) -> Type<'brand> {
36        Type::complete(ctx, self.to_final())
37    }
38
39    /// Convert the type name into a finalized type.
40    pub fn to_final(&self) -> Arc<Final> {
41        let mut stack = Vec::with_capacity(16);
42
43        for c in self.0.iter().rev() {
44            match c {
45                b'1' => stack.push(Final::unit()),
46                b'2' => stack.push(Final::two_two_n(0)),
47                b'c' => stack.push(Final::two_two_n(3)),
48                b's' => stack.push(Final::two_two_n(4)),
49                b'i' => stack.push(Final::two_two_n(5)),
50                b'l' => stack.push(Final::two_two_n(6)),
51                b'h' => stack.push(Final::two_two_n(8)),
52                b'+' | b'*' => {
53                    let left = stack.pop().expect("Illegal type name syntax!");
54                    let right = stack.pop().expect("Illegal type name syntax!");
55
56                    match c {
57                        b'+' => stack.push(Final::sum(left, right)),
58                        b'*' => stack.push(Final::product(left, right)),
59                        _ => unreachable!(),
60                    }
61                }
62                _ => panic!("Illegal type name syntax!"),
63            }
64        }
65
66        if stack.len() == 1 {
67            stack.pop().unwrap()
68        } else {
69            panic!("Illegal type name syntax!")
70        }
71    }
72
73    /// Convert the type name into a type's bitwidth.
74    ///
75    /// This is more efficient than creating the type and computing its bit-width
76    pub fn to_bit_width(&self) -> usize {
77        let mut stack = Vec::with_capacity(16);
78
79        for c in self.0.iter().rev() {
80            match c {
81                b'1' => stack.push(0),
82                b'2' => stack.push(1),
83                b'c' => stack.push(8),
84                b's' => stack.push(16),
85                b'i' => stack.push(32),
86                b'l' => stack.push(64),
87                b'h' => stack.push(256),
88                b'+' | b'*' => {
89                    let left = stack.pop().expect("Illegal type name syntax!");
90                    let right = stack.pop().expect("Illegal type name syntax!");
91
92                    match c {
93                        b'+' => stack.push(1 + cmp::max(left, right)),
94                        b'*' => stack.push(left + right),
95                        _ => unreachable!(),
96                    }
97                }
98                _ => panic!("Illegal type name syntax!"),
99            }
100        }
101
102        if stack.len() == 1 {
103            stack.pop().unwrap()
104        } else {
105            panic!("Illegal type name syntax!")
106        }
107    }
108}