1use crate::atomic::Atomic;
10use crate::union::Union;
11use serde::{Deserialize, Serialize};
12use std::fmt;
13
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15pub enum SimpleType {
16 String,
17 Int,
18 Float,
19 Bool,
20 Mixed,
21 Null,
22 Void,
23 Never,
24 Complex(Box<Union>),
26}
27
28impl SimpleType {
29 pub fn from_union(u: Union) -> Self {
31 if !u.possibly_undefined && !u.from_docblock && u.types.len() == 1 {
33 match &u.types[0] {
34 Atomic::TString => return Self::String,
35 Atomic::TInt => return Self::Int,
36 Atomic::TFloat => return Self::Float,
37 Atomic::TBool => return Self::Bool,
38 Atomic::TMixed => return Self::Mixed,
39 Atomic::TNull => return Self::Null,
40 Atomic::TVoid => return Self::Void,
41 Atomic::TNever => return Self::Never,
42 _ => {}
43 }
44 }
45 Self::Complex(Box::new(u))
46 }
47
48 pub fn to_union(&self) -> Union {
50 match self {
51 Self::String => Union::string(),
52 Self::Int => Union::int(),
53 Self::Float => Union::float(),
54 Self::Bool => Union::bool(),
55 Self::Mixed => Union::mixed(),
56 Self::Null => Union::null(),
57 Self::Void => Union::void(),
58 Self::Never => Union::never(),
59 Self::Complex(u) => *u.clone(),
60 }
61 }
62
63 pub fn is_simple(&self) -> bool {
65 !matches!(self, Self::Complex(_))
66 }
67
68 pub fn as_complex(&self) -> Option<&Union> {
70 match self {
71 Self::Complex(u) => Some(u),
72 _ => None,
73 }
74 }
75}
76
77impl fmt::Display for SimpleType {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 match self {
80 Self::String => write!(f, "string"),
81 Self::Int => write!(f, "int"),
82 Self::Float => write!(f, "float"),
83 Self::Bool => write!(f, "bool"),
84 Self::Mixed => write!(f, "mixed"),
85 Self::Null => write!(f, "null"),
86 Self::Void => write!(f, "void"),
87 Self::Never => write!(f, "never"),
88 Self::Complex(u) => write!(f, "{}", u),
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn simple_scalar_roundtrip() {
99 let u = Union::string();
100 let s = SimpleType::from_union(u.clone());
101 assert_eq!(s, SimpleType::String);
102 assert_eq!(s.to_union(), u);
103 }
104
105 #[test]
106 fn nullable_scalar_is_complex() {
107 let u = Union::nullable(Atomic::TString);
108 let s = SimpleType::from_union(u.clone());
109 assert_eq!(s, SimpleType::Complex(Box::new(u.clone())));
110 assert_eq!(s.to_union(), u);
111 }
112}