yarnspinner_core/
yarn_value.rs1use crate::prelude::*;
3use core::error::Error;
4use core::fmt::{Display, Formatter};
5
6#[derive(Debug, Clone, PartialEq)]
16#[cfg_attr(feature = "bevy", derive(Reflect))]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18#[cfg_attr(feature = "bevy", reflect(Debug, PartialEq))]
19#[cfg_attr(
20 all(feature = "bevy", feature = "serde"),
21 reflect(Serialize, Deserialize)
22)]
23pub enum YarnValue {
24 Number(f32),
27 String(String),
29 Boolean(bool),
31}
32
33pub trait IntoYarnValueFromNonYarnValue {
38 #[doc(hidden)]
39 fn into_yarn_value(self) -> YarnValue;
40}
41
42impl YarnValue {
43 pub fn eq(&self, other: &Self, epsilon: f32) -> bool {
46 match (self, other) {
47 (Self::Number(a), Self::Number(b)) => (a - b).abs() < epsilon,
48 (a, b) => a == b,
49 }
50 }
51}
52
53impl<T> From<&T> for YarnValue
54where
55 T: Copy,
56 YarnValue: From<T>,
57{
58 fn from(value: &T) -> Self {
59 Self::from(*value)
60 }
61}
62
63macro_rules! impl_floating_point {
64 ($($from_type:ty,)*) => {
65 $(
66 impl From<$from_type> for YarnValue {
67 fn from(value: $from_type) -> Self {
68 Self::Number(value as f32)
69 }
70 }
71
72 impl TryFrom<YarnValue> for $from_type {
73 type Error = YarnValueCastError;
74
75 fn try_from(value: YarnValue) -> Result<Self, Self::Error> {
76 Self::try_from(&value)
77 }
78 }
79
80 impl TryFrom<&YarnValue> for $from_type {
81 type Error = YarnValueCastError;
82
83 fn try_from(value: &YarnValue) -> Result<Self, Self::Error> {
84 match value {
85 YarnValue::Number(value) => Ok(*value as $from_type),
86 YarnValue::String(value) => value.parse().map_err(Into::into),
87 YarnValue::Boolean(value) => Ok(if *value { 1.0 as $from_type } else { 0.0 }),
88 }
89 }
90 }
91
92
93 impl IntoYarnValueFromNonYarnValue for $from_type {
94 fn into_yarn_value(self) -> YarnValue {
95 self.into()
96 }
97 }
98 )*
99 };
100}
101
102impl_floating_point![f32, f64,];
103
104macro_rules! impl_whole_number {
105 ($($from_type:ty,)*) => {
106 $(
107 impl From<$from_type> for YarnValue {
108 fn from(value: $from_type) -> Self {
109 Self::Number(value as f32)
110 }
111 }
112
113 impl TryFrom<YarnValue> for $from_type {
114 type Error = YarnValueCastError;
115
116 fn try_from(value: YarnValue) -> Result<Self, Self::Error> {
117 Self::try_from(&value)
118 }
119 }
120
121 impl TryFrom<&YarnValue> for $from_type {
122 type Error = YarnValueCastError;
123
124 fn try_from(value: &YarnValue) -> Result<Self, Self::Error> {
125 f32::try_from(value).map(|value| value as $from_type)
126 }
127 }
128
129 impl IntoYarnValueFromNonYarnValue for $from_type {
130 fn into_yarn_value(self) -> YarnValue {
131 self.into()
132 }
133 }
134 )*
135 };
136}
137
138impl_whole_number![
139 i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize, isize,
140];
141
142impl From<YarnValue> for String {
143 fn from(value: YarnValue) -> Self {
144 match value {
145 YarnValue::Number(value) => value.to_string(),
146 YarnValue::String(value) => value,
147 YarnValue::Boolean(value) => value.to_string(),
148 }
149 }
150}
151
152impl From<&YarnValue> for String {
153 fn from(value: &YarnValue) -> Self {
154 Self::from(value.clone())
155 }
156}
157
158impl From<String> for YarnValue {
159 fn from(value: String) -> Self {
160 Self::String(value)
161 }
162}
163
164impl From<&str> for YarnValue {
165 fn from(value: &str) -> Self {
166 Self::String(value.to_string())
167 }
168}
169
170impl IntoYarnValueFromNonYarnValue for String {
171 fn into_yarn_value(self) -> YarnValue {
172 self.into()
173 }
174}
175
176impl TryFrom<YarnValue> for bool {
177 type Error = YarnValueCastError;
178
179 fn try_from(value: YarnValue) -> Result<Self, Self::Error> {
180 Self::try_from(&value)
181 }
182}
183
184impl TryFrom<&YarnValue> for bool {
185 type Error = YarnValueCastError;
186
187 fn try_from(value: &YarnValue) -> Result<Self, Self::Error> {
188 match value {
189 YarnValue::Number(value) => Ok(*value != 0.0),
190 YarnValue::String(value) => value.parse().map_err(Into::into),
191 YarnValue::Boolean(value) => Ok(*value),
192 }
193 }
194}
195
196impl From<bool> for YarnValue {
197 fn from(value: bool) -> Self {
198 Self::Boolean(value)
199 }
200}
201
202impl IntoYarnValueFromNonYarnValue for bool {
203 fn into_yarn_value(self) -> YarnValue {
204 self.into()
205 }
206}
207
208#[derive(Debug)]
210#[allow(missing_docs)]
211pub enum YarnValueCastError {
212 ParseFloatError(core::num::ParseFloatError),
213 ParseIntError(core::num::ParseIntError),
214 ParseBoolError(core::str::ParseBoolError),
215}
216
217impl Error for YarnValueCastError {
218 fn source(&self) -> Option<&(dyn Error + 'static)> {
219 match self {
220 YarnValueCastError::ParseFloatError(e) => Some(e),
221 YarnValueCastError::ParseIntError(e) => Some(e),
222 YarnValueCastError::ParseBoolError(e) => Some(e),
223 }
224 }
225}
226
227impl Display for YarnValueCastError {
228 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
229 match self {
230 YarnValueCastError::ParseFloatError(e) => Display::fmt(e, f),
231 YarnValueCastError::ParseIntError(e) => Display::fmt(e, f),
232 YarnValueCastError::ParseBoolError(e) => Display::fmt(e, f),
233 }
234 }
235}
236
237impl From<core::num::ParseFloatError> for YarnValueCastError {
238 fn from(value: core::num::ParseFloatError) -> Self {
239 Self::ParseFloatError(value)
240 }
241}
242
243impl From<core::num::ParseIntError> for YarnValueCastError {
244 fn from(value: core::num::ParseIntError) -> Self {
245 Self::ParseIntError(value)
246 }
247}
248
249impl From<core::str::ParseBoolError> for YarnValueCastError {
250 fn from(value: core::str::ParseBoolError) -> Self {
251 Self::ParseBoolError(value)
252 }
253}
254
255impl Display for YarnValue {
256 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
257 match self {
258 Self::Number(value) => write!(f, "{value}"),
259 Self::String(value) => write!(f, "{value}"),
260 Self::Boolean(value) => write!(f, "{value}"),
261 }
262 }
263}