ayaka_primitive/raw_value.rs
1use serde::{Deserialize, Serialize};
2use std::borrow::Cow;
3
4/// The basic and only type used in scripts.
5/// ```
6/// # use ayaka_primitive::RawValue;
7/// assert_eq!(serde_yaml::from_str::<RawValue>("~").unwrap(), RawValue::Unit);
8/// assert_eq!(serde_yaml::from_str::<RawValue>("true").unwrap(), RawValue::Bool(true));
9/// assert_eq!(serde_yaml::from_str::<RawValue>("123").unwrap(), RawValue::Num(123));
10/// assert_eq!(serde_yaml::from_str::<RawValue>("\"hello\"").unwrap(), RawValue::Str("hello".to_string()));
11/// ```
12#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
13#[serde(untagged)]
14pub enum RawValue {
15 /// The unit type. It is empty, just like [`None`] or [`()`] in Rust.
16 #[default]
17 Unit,
18 /// The boolean type.
19 Bool(bool),
20 /// The number type. It's [`i64`].
21 Num(i64),
22 /// The string type.
23 Str(String),
24}
25
26/// Represents the type of [`RawValue`].
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
28pub enum ValueType {
29 /// The unit type.
30 Unit,
31 /// The boolean type.
32 Bool,
33 /// The number type.
34 Num,
35 /// The string type.
36 Str,
37}
38
39impl RawValue {
40 /// Gets [`ValueType`].
41 pub fn get_type(&self) -> ValueType {
42 match self {
43 Self::Unit => ValueType::Unit,
44 Self::Bool(_) => ValueType::Bool,
45 Self::Num(_) => ValueType::Num,
46 Self::Str(_) => ValueType::Str,
47 }
48 }
49
50 /// Gets a boolean from the value:
51 /// * A [`RawValue::Unit`] converts to `false`.
52 /// * A [`RawValue::Num`] converts to `false` if and only if it's zero.
53 /// * A [`RawValue::Str`] converts to `false` if and only if it's empty.
54 ///
55 /// ```
56 /// # use ayaka_primitive::RawValue;
57 /// let unit_value = RawValue::Unit;
58 /// assert!(!unit_value.get_bool());
59 /// let num_value = RawValue::Num(123);
60 /// assert!(num_value.get_bool());
61 /// let str_value = RawValue::Str("hello".to_string());
62 /// assert!(str_value.get_bool());
63 /// let empty_str_value = RawValue::Str(String::default());
64 /// assert!(!empty_str_value.get_bool());
65 /// ```
66 pub fn get_bool(&self) -> bool {
67 match self {
68 Self::Unit => false,
69 Self::Bool(b) => *b,
70 Self::Num(i) => *i != 0,
71 Self::Str(s) => !s.is_empty(),
72 }
73 }
74
75 /// Gets a number from the value:
76 /// * A [`RawValue::Unit`] converts to 0.
77 /// * A [`RawValue::Bool`] converts `false` to 0 and `true` to 1.
78 /// * A [`RawValue::Str`] converts to the length of the string.
79 ///
80 /// ```
81 /// # use ayaka_primitive::RawValue;
82 /// let unit_value = RawValue::Unit;
83 /// assert_eq!(unit_value.get_num(), 0);
84 /// let bool_value = RawValue::Bool(true);
85 /// assert_eq!(bool_value.get_num(), 1);
86 /// let str_value = RawValue::Str("hello".to_string());
87 /// assert_eq!(str_value.get_num(), 5);
88 /// ```
89 pub fn get_num(&self) -> i64 {
90 match self {
91 Self::Unit => 0,
92 Self::Bool(b) => *b as i64,
93 Self::Num(i) => *i,
94 Self::Str(s) => s.len() as i64,
95 }
96 }
97
98 /// Gets a string from the value:
99 /// * A [`RawValue::Unit`] converts to empty string.
100 /// * A [`RawValue::Bool`] converts to "false" or "true".
101 /// * A [`RawValue::Num`] converts to the string representation of the number.\
102 ///
103 /// Be careful to use `get_str().into_owned()`, if possible, use `into_str()` instead.
104 ///
105 /// ```
106 /// # use ayaka_primitive::RawValue;
107 /// let unit_value = RawValue::Unit;
108 /// assert_eq!(unit_value.get_str(), "");
109 /// let bool_value = RawValue::Bool(true);
110 /// assert_eq!(bool_value.get_str(), "true");
111 /// let num_value = RawValue::Num(123);
112 /// assert_eq!(num_value.get_str(), "123");
113 /// ```
114 pub fn get_str(&self) -> Cow<str> {
115 match self {
116 Self::Unit => Cow::default(),
117 Self::Bool(b) => b.to_string().into(),
118 Self::Num(i) => i.to_string().into(),
119 Self::Str(s) => s.as_str().into(),
120 }
121 }
122
123 /// Gets a string from the value:
124 /// * A [`RawValue::Unit`] converts to empty string.
125 /// * A [`RawValue::Bool`] converts to "false" or "true".
126 /// * A [`RawValue::Num`] converts to the string representation of the number.
127 pub fn into_str(self) -> String {
128 match self {
129 Self::Unit => String::default(),
130 Self::Bool(b) => b.to_string(),
131 Self::Num(i) => i.to_string(),
132 Self::Str(s) => s,
133 }
134 }
135}
136
137#[cfg(test)]
138mod test {
139 use crate::*;
140
141 #[test]
142 fn serde_value() {
143 assert_eq!(
144 serde_yaml::from_str::<RawValue>("~").unwrap(),
145 RawValue::Unit
146 );
147
148 assert_eq!(
149 serde_yaml::from_str::<RawValue>("true").unwrap(),
150 RawValue::Bool(true)
151 );
152 assert_eq!(
153 serde_yaml::from_str::<RawValue>("false").unwrap(),
154 RawValue::Bool(false)
155 );
156
157 assert_eq!(
158 serde_yaml::from_str::<RawValue>("114514").unwrap(),
159 RawValue::Num(114514)
160 );
161 assert_eq!(
162 serde_yaml::from_str::<RawValue>("-1919810").unwrap(),
163 RawValue::Num(-1919810)
164 );
165
166 assert_eq!(
167 serde_yaml::from_str::<RawValue>("\"Hello world!\"").unwrap(),
168 RawValue::Str("Hello world!".into())
169 );
170
171 assert_eq!(serde_yaml::to_string(&RawValue::Unit).unwrap(), "null\n");
172
173 assert_eq!(
174 serde_yaml::to_string(&RawValue::Bool(true)).unwrap(),
175 "true\n"
176 );
177 assert_eq!(
178 serde_yaml::to_string(&RawValue::Bool(false)).unwrap(),
179 "false\n"
180 );
181
182 assert_eq!(
183 serde_yaml::to_string(&RawValue::Num(114514)).unwrap(),
184 "114514\n"
185 );
186 assert_eq!(
187 serde_yaml::to_string(&RawValue::Num(-1919)).unwrap(),
188 "-1919\n"
189 );
190
191 assert_eq!(
192 serde_yaml::to_string(&RawValue::Str("aaa".into())).unwrap(),
193 "aaa\n"
194 );
195 }
196}