Skip to main content

rasant/attributes/
scalar.rs

1use ntime::{Duration, Timestamp};
2use std::fmt;
3use std::thread;
4
5use crate::attributes::Map;
6use crate::level::Level;
7use crate::types::AttributeString;
8
9/// [`Scalar`] definitions for all log operations.
10/// Scalars are the basic data units for Rasant, representing a single type.
11#[derive(Clone, Debug, PartialEq)]
12pub enum Scalar {
13	/// A [`bool`]ean.
14	Bool(bool),
15	/// An owned [`AttributeString`].
16	String(AttributeString),
17	/// An integer, internally stored as a [`i64`].
18	Int(i64),
19	/// A long integer, internally stored as a [`i128`].
20	LongInt(i128),
21	/// A pointer-sized integer, stored as a [`isize`].
22	Size(isize),
23	/// An unsigned integer, internally stored as a [`u64`].
24	Uint(u64),
25	/// An unsigned long integer, internally stored as a [`i128`].
26	LongUint(u128),
27	/// A pointer-sized unsigned integer, stored as a [`isize`].
28	Usize(usize),
29	/// A float, internally stored as a [`f64`].
30	Float(f64),
31}
32
33/* ----------------------- Implementation ----------------------- */
34
35impl<'i> Scalar {
36	/// Writes a string representation of a [`Scalar`] into an [`fmt::Write`].
37	pub fn write_str<T: fmt::Write>(&self, out: &mut T, attrs: &Map) -> fmt::Result {
38		match &self {
39			Self::Bool(b) => write!(out, "{}", b),
40			Self::String(s) => write!(out, "\"{}\"", s.as_str(attrs)),
41			Self::Int(i) => write!(out, "{}", i),
42			Self::LongInt(i) => {
43				if *i < 1 {
44					write!(out, "-0x{:x}", -i)
45				} else {
46					write!(out, "0x{:x}", i)
47				}
48			}
49			Self::Size(s) => {
50				if *s < 1 {
51					write!(out, "-0x{:x}", -s)
52				} else {
53					write!(out, "0x{:x}", s)
54				}
55			}
56			Self::Uint(i) => write!(out, "{}", i),
57			Self::LongUint(u) => write!(out, "0x{:x}", u),
58			Self::Usize(u) => write!(out, "0x{:x}", u),
59			Self::Float(fl) => write!(out, "{}", fl),
60		}
61	}
62
63	/// Creates an array of [`Scalar`]s from a suitable type.
64	pub fn to_array<const N: usize, T: ToScalarArray<'i, N>>(v: T) -> [Self; N] {
65		v.to_scalar_array()
66	}
67
68	/// Serializes a [`Scalar`] into a pre-existing [`String`], whose contents are overwritten.
69	pub fn into_string(&self, out: &mut String, attrs: &Map) {
70		out.clear();
71		self.write_str(out, attrs).expect("failed to serialize Scalar into_string()");
72	}
73}
74
75/* ----------------------- Casting ----------------------- */
76
77impl From<bool> for Scalar {
78	fn from(b: bool) -> Self {
79		Self::Bool(b)
80	}
81}
82
83impl From<String> for Scalar {
84	fn from(s: String) -> Self {
85		Self::String(AttributeString::from(s))
86	}
87}
88
89impl From<&'static str> for Scalar {
90	fn from(s: &'static str) -> Self {
91		Self::String(AttributeString::from(s))
92	}
93}
94
95impl From<Duration> for Scalar {
96	fn from(d: Duration) -> Self {
97		Self::Uint(d.as_secs())
98	}
99}
100
101impl From<&Duration> for Scalar {
102	fn from(d: &Duration) -> Self {
103		Self::Uint(d.as_secs())
104	}
105}
106
107impl From<Timestamp> for Scalar {
108	fn from(t: Timestamp) -> Self {
109		Self::Uint(t.as_secs())
110	}
111}
112
113impl From<&Timestamp> for Scalar {
114	fn from(t: &Timestamp) -> Self {
115		Self::Uint(t.as_secs())
116	}
117}
118
119impl From<thread::ThreadId> for Scalar {
120	fn from(t: thread::ThreadId) -> Self {
121		Self::String(AttributeString::from(format!("{:?}", t)))
122	}
123}
124
125impl From<&thread::ThreadId> for Scalar {
126	fn from(t: &thread::ThreadId) -> Self {
127		Self::String(AttributeString::from(format!("{:?}", t)))
128	}
129}
130
131impl From<Level> for Scalar {
132	fn from(t: Level) -> Self {
133		Self::String(AttributeString::from(t.to_string()))
134	}
135}
136
137impl From<&Level> for Scalar {
138	fn from(t: &Level) -> Self {
139		Self::String(AttributeString::from(t.to_string()))
140	}
141}
142
143macro_rules! cast_signed_to_scalar {
144	($t: ty) => {
145		impl From<$t> for Scalar {
146			fn from(x: $t) -> Self {
147				Self::Int(x as i64)
148			}
149		}
150	};
151}
152
153cast_signed_to_scalar!(i8);
154cast_signed_to_scalar!(i16);
155cast_signed_to_scalar!(i32);
156cast_signed_to_scalar!(i64);
157
158impl From<i128> for Scalar {
159	fn from(x: i128) -> Self {
160		Self::LongInt(x)
161	}
162}
163
164impl From<isize> for Scalar {
165	fn from(x: isize) -> Self {
166		Self::Size(x)
167	}
168}
169
170macro_rules! cast_unsigned_to_scalar {
171	($t: ty) => {
172		impl From<$t> for Scalar {
173			fn from(x: $t) -> Self {
174				Self::Uint(x as u64)
175			}
176		}
177	};
178}
179
180cast_unsigned_to_scalar!(u8);
181cast_unsigned_to_scalar!(u16);
182cast_unsigned_to_scalar!(u32);
183cast_unsigned_to_scalar!(u64);
184
185impl From<u128> for Scalar {
186	fn from(x: u128) -> Self {
187		Self::LongUint(x)
188	}
189}
190
191impl From<usize> for Scalar {
192	fn from(x: usize) -> Self {
193		Self::Usize(x)
194	}
195}
196
197macro_rules! cast_float_to_scalar {
198	($t: ty) => {
199		impl From<$t> for Scalar {
200			fn from(x: $t) -> Self {
201				Self::Float(x as f64)
202			}
203		}
204	};
205}
206
207cast_float_to_scalar!(f32);
208cast_float_to_scalar!(f64);
209
210/* ----------------------- Scalar slice helper implementation ----------------------- */
211
212/// Trait for known types/structs which can be casted into an array of [`Scalar`].
213pub trait ToScalarArray<'t, const N: usize> {
214	/// Casts the type to a [`Scalar`] array.
215	fn to_scalar_array(self) -> [Scalar; N];
216}
217
218impl<'i, T: Into<Scalar>> ToScalarArray<'i, 1> for T
219where
220	Scalar: From<T>,
221{
222	fn to_scalar_array(self) -> [Scalar; 1] {
223		[Scalar::from(self)]
224	}
225}
226
227impl<'i, T: Into<Scalar>, const N: usize> ToScalarArray<'i, N> for [T; N]
228where
229	Scalar: From<T>,
230{
231	fn to_scalar_array(self) -> [Scalar; N] {
232		self.map(|x| Scalar::from(x))
233	}
234}
235
236/*
237impl<'i, T: ToScalar, const N: usize> ToScalarArray<'i, N> for &[T] {
238	fn to_scalar_array(self) -> [Scalar; N] {
239		let out: [Scalar; N] = array::from_fn(|i| self[i].to_scalar());
240		out
241	}
242}
243*/
244
245/* ----------------------- Tests ----------------------- */
246
247#[cfg(test)]
248mod tests {
249	use super::*;
250
251	#[test]
252	fn from_scalar() {
253		let short_string = "lalala";
254		let long_string = "this is a rather long string, which may be complicated";
255
256		assert_eq!(Scalar::from(true), Scalar::Bool(true));
257		assert_eq!(Scalar::from(short_string), Scalar::String(AttributeString::from(short_string)));
258		assert_eq!(Scalar::from(String::from(short_string)), Scalar::String(AttributeString::from(String::from(short_string))));
259		assert_eq!(Scalar::from(long_string), Scalar::String(long_string.into()));
260		assert_eq!(Scalar::from(String::from(long_string)), Scalar::String(AttributeString::from(String::from(long_string))));
261		assert_eq!(Scalar::from(-12 as i8), Scalar::Int(-12));
262		assert_eq!(Scalar::from(345 as i16), Scalar::Int(345));
263		assert_eq!(Scalar::from(-678 as i32), Scalar::Int(-678));
264		assert_eq!(Scalar::from(9012 as i64), Scalar::Int(9012));
265		assert_eq!(Scalar::from(-3456 as i128), Scalar::LongInt(-3456));
266		assert_eq!(Scalar::from(7890 as isize), Scalar::Size(7890));
267		assert_eq!(Scalar::from(12 as u8), Scalar::Uint(12));
268		assert_eq!(Scalar::from(345 as u16), Scalar::Uint(345));
269		assert_eq!(Scalar::from(678 as u32), Scalar::Uint(678));
270		assert_eq!(Scalar::from(9012 as u64), Scalar::Uint(9012));
271		assert_eq!(Scalar::from(3456 as u128), Scalar::LongUint(3456));
272		assert_eq!(Scalar::from(7890 as usize), Scalar::Usize(7890));
273		// yaay precision!
274		assert_eq!(Scalar::from(-123.456 as f32), Scalar::Float(-123.45600128173828));
275		assert_eq!(Scalar::from(789.012 as f64), Scalar::Float(789.012));
276		assert_eq!(Scalar::from(Duration::from_millis(12345)), Scalar::Uint(12));
277		assert_eq!(Scalar::from(&Duration::from_millis(67890)), Scalar::Uint(67));
278		assert_eq!(Scalar::from(Timestamp::from_millis(12345)), Scalar::Uint(12));
279		assert_eq!(Scalar::from(&Timestamp::from_millis(67890)), Scalar::Uint(67));
280	}
281
282	#[test]
283	fn into_string() {
284		for tc in [
285			(Scalar::Bool(true), "true"),
286			(Scalar::Bool(false), "false"),
287			(Scalar::String("".into()), "\"\""),
288			(Scalar::String("abcd 1234".into()), "\"abcd 1234\""),
289			(Scalar::String(String::from("heap String").into()), "\"heap String\""),
290			(Scalar::Int(-123), "-123"),
291			(Scalar::Int(456), "456"),
292			(Scalar::LongInt(-12345678901234567), "-0x2bdc545d6b4b87"),
293			(Scalar::LongInt(89801234567890123), "0x13f09bf3ecf84cb"),
294			(Scalar::Size(-12345678901234567), "-0x2bdc545d6b4b87"),
295			(Scalar::Size(89801234567890123), "0x13f09bf3ecf84cb"),
296			(Scalar::Uint(123456), "123456"),
297			(Scalar::LongUint(12345678901234567), "0x2bdc545d6b4b87"),
298			(Scalar::Usize(89801234567890123), "0x13f09bf3ecf84cb"),
299			(Scalar::Float(-1.2345), "-1.2345"),
300			(Scalar::Float(6.78901), "6.78901"),
301		] {
302			let (s, want): (Scalar, &str) = tc;
303
304			let mut out = String::from("lalalala!");
305			let attrs = Map::new();
306
307			s.into_string(&mut out, &attrs);
308			assert_eq!(out, want);
309		}
310	}
311}