1use core::fmt;
2use std::str::FromStr;
3
4use kcl_error::CompilationIssue;
5use kcl_error::SourceRange;
6use schemars::JsonSchema;
7use serde::Deserialize;
8use serde::Serialize;
9
10use crate::NumericType;
11use crate::UnitAngle;
12use crate::UnitLength;
13use crate::UnitType;
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS, JsonSchema)]
16#[repr(u32)]
17pub enum NumericSuffix {
18 None,
19 Count,
20 Length,
21 Angle,
22 Mm,
23 Cm,
24 M,
25 Inch,
26 Ft,
27 Yd,
28 Deg,
29 Rad,
30 Unknown,
31}
32
33impl NumericSuffix {
34 #[allow(dead_code)]
35 pub fn is_none(self) -> bool {
36 self == Self::None
37 }
38
39 pub fn is_some(self) -> bool {
40 self != Self::None
41 }
42
43 pub fn digestable_id(&self) -> &[u8] {
44 match self {
45 NumericSuffix::None => &[],
46 NumericSuffix::Count => b"_",
47 NumericSuffix::Unknown => b"?",
48 NumericSuffix::Length => b"Length",
49 NumericSuffix::Angle => b"Angle",
50 NumericSuffix::Mm => b"mm",
51 NumericSuffix::Cm => b"cm",
52 NumericSuffix::M => b"m",
53 NumericSuffix::Inch => b"in",
54 NumericSuffix::Ft => b"ft",
55 NumericSuffix::Yd => b"yd",
56 NumericSuffix::Deg => b"deg",
57 NumericSuffix::Rad => b"rad",
58 }
59 }
60}
61
62impl FromStr for NumericSuffix {
63 type Err = CompilationIssue;
64
65 fn from_str(s: &str) -> Result<Self, Self::Err> {
66 match s {
67 "_" | "Count" => Ok(NumericSuffix::Count),
68 "Length" => Ok(NumericSuffix::Length),
69 "Angle" => Ok(NumericSuffix::Angle),
70 "mm" | "millimeters" => Ok(NumericSuffix::Mm),
71 "cm" | "centimeters" => Ok(NumericSuffix::Cm),
72 "m" | "meters" => Ok(NumericSuffix::M),
73 "inch" | "in" => Ok(NumericSuffix::Inch),
74 "ft" | "feet" => Ok(NumericSuffix::Ft),
75 "yd" | "yards" => Ok(NumericSuffix::Yd),
76 "deg" | "degrees" => Ok(NumericSuffix::Deg),
77 "rad" | "radians" => Ok(NumericSuffix::Rad),
78 "?" => Ok(NumericSuffix::Unknown),
79 _ => Err(CompilationIssue::err(SourceRange::default(), "invalid unit of measure")),
80 }
81 }
82}
83
84impl fmt::Display for NumericSuffix {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 match self {
87 NumericSuffix::None => Ok(()),
88 NumericSuffix::Count => write!(f, "_"),
89 NumericSuffix::Unknown => write!(f, "_?"),
90 NumericSuffix::Length => write!(f, "Length"),
91 NumericSuffix::Angle => write!(f, "Angle"),
92 NumericSuffix::Mm => write!(f, "mm"),
93 NumericSuffix::Cm => write!(f, "cm"),
94 NumericSuffix::M => write!(f, "m"),
95 NumericSuffix::Inch => write!(f, "in"),
96 NumericSuffix::Ft => write!(f, "ft"),
97 NumericSuffix::Yd => write!(f, "yd"),
98 NumericSuffix::Deg => write!(f, "deg"),
99 NumericSuffix::Rad => write!(f, "rad"),
100 }
101 }
102}
103
104impl From<UnitLength> for NumericSuffix {
105 fn from(value: UnitLength) -> Self {
106 match value {
107 UnitLength::Millimeters => NumericSuffix::Mm,
108 UnitLength::Centimeters => NumericSuffix::Cm,
109 UnitLength::Meters => NumericSuffix::M,
110 UnitLength::Inches => NumericSuffix::Inch,
111 UnitLength::Feet => NumericSuffix::Ft,
112 UnitLength::Yards => NumericSuffix::Yd,
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, ts_rs::TS)]
118pub struct NumericSuffixTypeConvertError;
119
120impl TryFrom<NumericType> for NumericSuffix {
121 type Error = NumericSuffixTypeConvertError;
122
123 fn try_from(value: NumericType) -> Result<Self, Self::Error> {
124 match value {
125 NumericType::Known(UnitType::Count) => Ok(NumericSuffix::Count),
126 NumericType::Known(UnitType::Length(unit_length)) => Ok(NumericSuffix::from(unit_length)),
127 NumericType::Known(UnitType::GenericLength) => Ok(NumericSuffix::Length),
128 NumericType::Known(UnitType::Angle(UnitAngle::Degrees)) => Ok(NumericSuffix::Deg),
129 NumericType::Known(UnitType::Angle(UnitAngle::Radians)) => Ok(NumericSuffix::Rad),
130 NumericType::Known(UnitType::GenericAngle) => Ok(NumericSuffix::Angle),
131 NumericType::Default { .. } => Ok(NumericSuffix::None),
132 NumericType::Unknown => Ok(NumericSuffix::Unknown),
133 NumericType::Any => Err(NumericSuffixTypeConvertError),
134 }
135 }
136}