1use super::BTreeMap;
4#[cfg(not(feature = "std"))]
5use super::imp::*;
6#[cfg(not(feature = "std"))]
7use alloc::boxed::Box;
8#[cfg(not(feature = "std"))]
9use alloc::vec;
10use core::any::type_name;
11use core::fmt;
12use core::fmt::Display;
13use cu29_traits::CuError;
14use cu29_value::Value as CuValue;
15use hashbrown::HashMap;
16use ron::Number;
17use ron::value::Value as RonValue;
18use serde::de::DeserializeOwned;
19use serde::{Deserialize, Deserializer, Serialize};
20
21#[derive(Serialize, Deserialize, Debug, Clone, Default)]
25pub struct ComponentConfig(
26 #[serde(serialize_with = "super::serialize_ordered_map")] pub HashMap<String, Value>,
27);
28
29#[allow(dead_code)]
31impl Display for ComponentConfig {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 let mut first = true;
34 let ComponentConfig(config) = self;
35 write!(f, "{{")?;
36 for (key, value) in config.iter() {
37 if !first {
38 write!(f, ", ")?;
39 }
40 write!(f, "{key}: {value}")?;
41 first = false;
42 }
43 write!(f, "}}")
44 }
45}
46
47impl ComponentConfig {
49 #[allow(dead_code)]
50 pub fn new() -> Self {
51 ComponentConfig(HashMap::new())
52 }
53
54 #[allow(dead_code)]
55 pub fn get<T>(&self, key: &str) -> Result<Option<T>, ConfigError>
56 where
57 T: for<'a> TryFrom<&'a Value, Error = ConfigError>,
58 {
59 let ComponentConfig(config) = self;
60 match config.get(key) {
61 Some(value) => T::try_from(value).map(Some),
62 None => Ok(None),
63 }
64 }
65
66 #[allow(dead_code)]
67 pub fn get_value<T>(&self, key: &str) -> Result<Option<T>, ConfigError>
81 where
82 T: DeserializeOwned,
83 {
84 let ComponentConfig(config) = self;
85 let Some(value) = config.get(key) else {
86 return Ok(None);
87 };
88 let cu_value = ron_value_to_cu_value(&value.0).map_err(|err| err.with_key(key))?;
89 cu_value
90 .deserialize_into::<T>()
91 .map(Some)
92 .map_err(|err| ConfigError {
93 message: format!(
94 "Config key '{key}' failed to deserialize as {}: {err}",
95 type_name::<T>()
96 ),
97 })
98 }
99
100 #[allow(dead_code)]
101 pub fn deserialize_into<T>(&self) -> Result<T, ConfigError>
102 where
103 T: DeserializeOwned,
104 {
105 let mut map = BTreeMap::new();
106 for (key, value) in &self.0 {
107 let mapped_value = ron_value_to_cu_value(&value.0).map_err(|err| err.with_key(key))?;
108 map.insert(CuValue::String(key.clone()), mapped_value);
109 }
110
111 CuValue::Map(map)
112 .deserialize_into::<T>()
113 .map_err(|err| ConfigError {
114 message: format!(
115 "Config failed to deserialize as {}: {err}",
116 type_name::<T>()
117 ),
118 })
119 }
120
121 #[allow(dead_code)]
122 pub fn set<T: Into<Value>>(&mut self, key: &str, value: T) {
123 let ComponentConfig(config) = self;
124 config.insert(key.to_string(), value.into());
125 }
126
127 #[allow(dead_code)]
128 pub fn merge_from(&mut self, other: &ComponentConfig) {
129 let ComponentConfig(config) = self;
130 for (key, value) in &other.0 {
131 config.insert(key.clone(), value.clone());
132 }
133 }
134}
135
136fn ron_value_to_cu_value(value: &RonValue) -> Result<CuValue, ConfigError> {
137 match value {
138 RonValue::Bool(v) => Ok(CuValue::Bool(*v)),
139 RonValue::Char(v) => Ok(CuValue::Char(*v)),
140 RonValue::String(v) => Ok(CuValue::String(v.clone())),
141 RonValue::Bytes(v) => Ok(CuValue::Bytes(v.clone())),
142 RonValue::Unit => Ok(CuValue::Unit),
143 RonValue::Option(v) => {
144 let mapped = match v {
145 Some(inner) => Some(Box::new(ron_value_to_cu_value(inner)?)),
146 None => None,
147 };
148 Ok(CuValue::Option(mapped))
149 }
150 RonValue::Seq(seq) => {
151 let mut mapped = Vec::with_capacity(seq.len());
152 for item in seq {
153 mapped.push(ron_value_to_cu_value(item)?);
154 }
155 Ok(CuValue::Seq(mapped))
156 }
157 RonValue::Map(map) => {
158 let mut mapped = BTreeMap::new();
159 for (key, value) in map.iter() {
160 let mapped_key = ron_value_to_cu_value(key)?;
161 let mapped_value = ron_value_to_cu_value(value)?;
162 mapped.insert(mapped_key, mapped_value);
163 }
164 Ok(CuValue::Map(mapped))
165 }
166 RonValue::Number(num) => match num {
167 Number::I8(v) => Ok(CuValue::I8(*v)),
168 Number::I16(v) => Ok(CuValue::I16(*v)),
169 Number::I32(v) => Ok(CuValue::I32(*v)),
170 Number::I64(v) => Ok(CuValue::I64(*v)),
171 Number::U8(v) => Ok(CuValue::U8(*v)),
172 Number::U16(v) => Ok(CuValue::U16(*v)),
173 Number::U32(v) => Ok(CuValue::U32(*v)),
174 Number::U64(v) => Ok(CuValue::U64(*v)),
175 Number::F32(v) => Ok(CuValue::F32(v.0)),
176 Number::F64(v) => Ok(CuValue::F64(v.0)),
177 _ => Err(ConfigError {
178 message: "Unsupported RON number variant".to_string(),
179 }),
180 },
181 }
182}
183
184#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
193pub struct Value(pub(super) RonValue);
194
195#[doc(hidden)]
197#[derive(Debug, Clone, Copy, PartialEq)]
198pub enum ConstantNumber {
199 Signed(i64),
200 Unsigned(u64),
201 Float(f64),
202}
203
204impl ConstantNumber {
205 pub fn as_f64(self) -> f64 {
206 match self {
207 Self::Signed(value) => value as f64,
208 Self::Unsigned(value) => value as f64,
209 Self::Float(value) => value,
210 }
211 }
212}
213
214#[doc(hidden)]
216#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)]
217#[serde(rename_all = "lowercase")]
218pub enum ConstantStorage {
219 I8,
220 I16,
221 I32,
222 I64,
223 Isize,
224 U8,
225 U16,
226 U32,
227 U64,
228 Usize,
229 #[default]
230 F32,
231 F64,
232}
233
234impl ConstantStorage {
235 pub const fn rust_type(self) -> &'static str {
236 match self {
237 Self::I8 => "i8",
238 Self::I16 => "i16",
239 Self::I32 => "i32",
240 Self::I64 => "i64",
241 Self::Isize => "isize",
242 Self::U8 => "u8",
243 Self::U16 => "u16",
244 Self::U32 => "u32",
245 Self::U64 => "u64",
246 Self::Usize => "usize",
247 Self::F32 => "f32",
248 Self::F64 => "f64",
249 }
250 }
251
252 pub const fn supports_quantity(self) -> bool {
253 matches!(self, Self::F32 | Self::F64)
254 }
255}
256
257#[doc(hidden)]
259#[derive(Serialize, Deserialize, Debug, Clone)]
260pub struct ConstantConfig {
261 pub(super) id: String,
262 #[serde(default, deserialize_with = "deserialize_constant_module")]
263 module: Option<String>,
264 #[serde(default)]
265 pub(super) storage: Option<ConstantStorage>,
266 pub(super) quantity: Option<cu29_units::constant::Quantity>,
267 pub(super) unit: Option<cu29_units::constant::Unit>,
268 pub(super) value: Option<Value>,
269 #[serde(rename = "type")]
270 pub(super) rust_type: Option<String>,
271 pub(super) expression: Option<String>,
272}
273
274fn deserialize_constant_module<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
275where
276 D: Deserializer<'de>,
277{
278 Option::<String>::deserialize(deserializer).map(|module| {
279 module.map(|module| {
280 module
281 .chars()
282 .filter(|character| !character.is_whitespace())
283 .collect()
284 })
285 })
286}
287
288impl ConstantConfig {
289 pub const DEFAULT_MODULE: &'static str = "constants";
290
291 pub fn id(&self) -> &str {
292 &self.id
293 }
294
295 pub fn module_path(&self) -> &str {
296 self.module.as_deref().unwrap_or(Self::DEFAULT_MODULE)
297 }
298
299 pub fn qualified_id(&self) -> String {
300 format!("{}::{}", self.module_path(), self.id)
301 }
302
303 pub const fn storage(&self) -> ConstantStorage {
304 match self.storage {
305 Some(storage) => storage,
306 None => ConstantStorage::F32,
307 }
308 }
309
310 pub const fn quantity(&self) -> Option<cu29_units::constant::Quantity> {
311 self.quantity
312 }
313
314 pub const fn explicit_unit(&self) -> Option<cu29_units::constant::Unit> {
315 self.unit
316 }
317
318 pub fn expression_definition(&self) -> Option<(&str, &str)> {
319 self.rust_type.as_deref().zip(self.expression.as_deref())
320 }
321
322 pub fn resolved_unit(&self) -> Result<Option<cu29_units::constant::Unit>, String> {
323 let Some(quantity) = self.quantity else {
324 return Ok(None);
325 };
326 if let Some(unit) = self.unit {
327 return Ok(Some(unit));
328 }
329 let definition = cu29_units::constant::definition(quantity).ok_or_else(|| {
330 format!(
331 "Constant '{}' uses quantity '{}' which is missing from the unit catalogue",
332 self.id,
333 quantity.name()
334 )
335 })?;
336 cu29_units::constant::Unit::from_name(definition.coherent_unit)
337 .map(Some)
338 .ok_or_else(|| {
339 format!(
340 "Constant '{}' quantity '{}' has invalid coherent unit metadata '{}'",
341 self.id,
342 quantity.name(),
343 definition.coherent_unit
344 )
345 })
346 }
347
348 pub fn numbers(&self) -> Result<(bool, Vec<ConstantNumber>), String> {
349 fn number(value: &RonValue) -> Result<ConstantNumber, String> {
350 match value {
351 RonValue::Number(number) => match number {
352 Number::I8(value) => Ok(ConstantNumber::Signed(i64::from(*value))),
353 Number::I16(value) => Ok(ConstantNumber::Signed(i64::from(*value))),
354 Number::I32(value) => Ok(ConstantNumber::Signed(i64::from(*value))),
355 Number::I64(value) => Ok(ConstantNumber::Signed(*value)),
356 Number::U8(value) => Ok(ConstantNumber::Unsigned(u64::from(*value))),
357 Number::U16(value) => Ok(ConstantNumber::Unsigned(u64::from(*value))),
358 Number::U32(value) => Ok(ConstantNumber::Unsigned(u64::from(*value))),
359 Number::U64(value) => Ok(ConstantNumber::Unsigned(*value)),
360 Number::F32(value) => Ok(ConstantNumber::Float(f64::from(value.0))),
361 Number::F64(value) => Ok(ConstantNumber::Float(value.0)),
362 _ => Err("unsupported numeric representation".to_string()),
363 },
364 _ => Err("expected a number".to_string()),
365 }
366 }
367
368 let value = self
369 .value
370 .as_ref()
371 .ok_or_else(|| format!("Constant '{}' does not declare a numeric value", self.id))?;
372 match &value.0 {
373 RonValue::Seq(values) => values
374 .iter()
375 .map(number)
376 .collect::<Result<Vec<_>, _>>()
377 .map(|values| (true, values)),
378 value => number(value).map(|value| (false, vec![value])),
379 }
380 .map_err(|error| format!("Constant '{}': {error}", self.id))
381 }
382
383 pub fn normalized_f32(&self) -> Result<(bool, Vec<f32>), String> {
384 let quantity = self.quantity.ok_or_else(|| {
385 format!(
386 "Constant '{}' does not declare a physical quantity",
387 self.id
388 )
389 })?;
390 let unit = self
391 .resolved_unit()?
392 .ok_or_else(|| format!("Constant '{}' has no resolved unit", self.id))?;
393 let (is_array, numbers) = self.numbers()?;
394 numbers
395 .into_iter()
396 .map(|number| {
397 let value = number.as_f64() as f32;
398 if !value.is_finite() {
399 return Err(format!("Constant '{}' values must be finite", self.id));
400 }
401 cu29_units::constant::normalize_f32(quantity, unit, value).ok_or_else(|| {
402 format!(
403 "Constant '{}' unit '{}' is not compatible with quantity '{}'",
404 self.id,
405 unit.name(),
406 quantity.name()
407 )
408 })
409 })
410 .collect::<Result<Vec<_>, _>>()
411 .map(|values| (is_array, values))
412 }
413
414 pub fn normalized_f64(&self) -> Result<(bool, Vec<f64>), String> {
415 let quantity = self.quantity.ok_or_else(|| {
416 format!(
417 "Constant '{}' does not declare a physical quantity",
418 self.id
419 )
420 })?;
421 let unit = self
422 .resolved_unit()?
423 .ok_or_else(|| format!("Constant '{}' has no resolved unit", self.id))?;
424 let (is_array, numbers) = self.numbers()?;
425 numbers
426 .into_iter()
427 .map(|number| {
428 let value = number.as_f64();
429 if !value.is_finite() {
430 return Err(format!("Constant '{}' values must be finite", self.id));
431 }
432 cu29_units::constant::normalize_f64(quantity, unit, value).ok_or_else(|| {
433 format!(
434 "Constant '{}' unit '{}' is not compatible with quantity '{}'",
435 self.id,
436 unit.name(),
437 quantity.name()
438 )
439 })
440 })
441 .collect::<Result<Vec<_>, _>>()
442 .map(|values| (is_array, values))
443 }
444
445 #[allow(dead_code)]
447 pub fn semantic_fingerprint(&self) -> Result<u64, String> {
448 const OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
449 const PRIME: u64 = 0x0000_0100_0000_01b3;
450
451 fn hash_bytes(hash: &mut u64, bytes: &[u8]) {
452 for byte in bytes {
453 *hash ^= u64::from(*byte);
454 *hash = hash.wrapping_mul(PRIME);
455 }
456 }
457
458 let mut hash = OFFSET;
459 if let Some((rust_type, expression)) = self.expression_definition() {
460 hash_bytes(&mut hash, b"expression");
461 hash_bytes(&mut hash, rust_type.as_bytes());
462 hash_bytes(&mut hash, &[0]);
463 hash_bytes(&mut hash, expression.as_bytes());
464 return Ok(hash);
465 }
466
467 let storage = self.storage();
468 hash_bytes(&mut hash, b"numeric");
469 hash_bytes(&mut hash, storage.rust_type().as_bytes());
470 hash_bytes(
471 &mut hash,
472 self.quantity
473 .map_or("primitive", |quantity| quantity.name())
474 .as_bytes(),
475 );
476
477 if self.quantity.is_some() {
478 match storage {
479 ConstantStorage::F32 => {
480 let (is_array, values) = self.normalized_f32()?;
481 hash_bytes(&mut hash, &[u8::from(is_array)]);
482 for value in values {
483 hash_bytes(&mut hash, &value.to_bits().to_le_bytes());
484 }
485 }
486 ConstantStorage::F64 => {
487 let (is_array, values) = self.normalized_f64()?;
488 hash_bytes(&mut hash, &[u8::from(is_array)]);
489 for value in values {
490 hash_bytes(&mut hash, &value.to_bits().to_le_bytes());
491 }
492 }
493 _ => {
494 return Err(format!(
495 "Constant '{}' quantity storage must be f32 or f64",
496 self.id
497 ));
498 }
499 }
500 return Ok(hash);
501 }
502
503 let (is_array, numbers) = self.numbers()?;
504 hash_bytes(&mut hash, &[u8::from(is_array)]);
505 for number in numbers {
506 match (storage, number) {
507 (ConstantStorage::F32, number) => {
508 hash_bytes(&mut hash, &(number.as_f64() as f32).to_bits().to_le_bytes())
509 }
510 (ConstantStorage::F64, number) => {
511 hash_bytes(&mut hash, &number.as_f64().to_bits().to_le_bytes())
512 }
513 (_, ConstantNumber::Signed(value)) => hash_bytes(&mut hash, &value.to_le_bytes()),
514 (_, ConstantNumber::Unsigned(value)) => hash_bytes(&mut hash, &value.to_le_bytes()),
515 (_, ConstantNumber::Float(value)) => {
516 hash_bytes(&mut hash, &value.to_bits().to_le_bytes())
517 }
518 }
519 }
520 Ok(hash)
521 }
522}
523
524#[derive(Debug, Clone, PartialEq)]
525pub struct ConfigError {
526 message: String,
527}
528
529impl ConfigError {
530 fn type_mismatch(expected: &'static str, value: &Value) -> Self {
531 ConfigError {
532 message: format!("Expected {expected} but got {value:?}"),
533 }
534 }
535
536 fn with_key(self, key: &str) -> Self {
537 ConfigError {
538 message: format!("Config key '{key}': {}", self.message),
539 }
540 }
541}
542
543impl Display for ConfigError {
544 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
545 write!(f, "{}", self.message)
546 }
547}
548
549#[cfg(feature = "std")]
550impl std::error::Error for ConfigError {}
551
552#[cfg(not(feature = "std"))]
553impl core::error::Error for ConfigError {}
554
555impl From<ConfigError> for CuError {
556 fn from(err: ConfigError) -> Self {
557 CuError::from(err.to_string())
558 }
559}
560
561macro_rules! impl_from_numeric_for_value {
563 ($($source:ty),* $(,)?) => {
564 $(impl From<$source> for Value {
565 fn from(value: $source) -> Self {
566 Value(RonValue::Number(value.into()))
567 }
568 })*
569 };
570}
571
572impl_from_numeric_for_value!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
574
575impl TryFrom<&Value> for bool {
576 type Error = ConfigError;
577
578 fn try_from(value: &Value) -> Result<Self, Self::Error> {
579 if let Value(RonValue::Bool(v)) = value {
580 Ok(*v)
581 } else {
582 Err(ConfigError::type_mismatch("bool", value))
583 }
584 }
585}
586
587impl From<Value> for bool {
588 fn from(value: Value) -> Self {
589 if let Value(RonValue::Bool(v)) = value {
590 v
591 } else {
592 panic!("Expected a Boolean variant but got {value:?}")
593 }
594 }
595}
596macro_rules! impl_from_value_for_int {
597 ($($target:ty),* $(,)?) => {
598 $(
599 impl From<Value> for $target {
600 fn from(value: Value) -> Self {
601 if let Value(RonValue::Number(num)) = value {
602 match num {
603 Number::I8(n) => n as $target,
604 Number::I16(n) => n as $target,
605 Number::I32(n) => n as $target,
606 Number::I64(n) => n as $target,
607 Number::U8(n) => n as $target,
608 Number::U16(n) => n as $target,
609 Number::U32(n) => n as $target,
610 Number::U64(n) => n as $target,
611 Number::F32(_) | Number::F64(_) => {
612 panic!("Expected an integer Number variant but got {num:?}")
613 }
614 _ => {
615 panic!("Expected an integer Number variant but got {num:?}")
616 }
617 }
618 } else {
619 panic!("Expected a Number variant but got {value:?}")
620 }
621 }
622 }
623 )*
624 };
625}
626
627impl_from_value_for_int!(u8, i8, u16, i16, u32, i32, u64, i64);
628
629macro_rules! impl_try_from_value_for_int {
630 ($($target:ty),* $(,)?) => {
631 $(
632 impl TryFrom<&Value> for $target {
633 type Error = ConfigError;
634
635 fn try_from(value: &Value) -> Result<Self, Self::Error> {
636 if let Value(RonValue::Number(num)) = value {
637 match num {
638 Number::I8(n) => Ok(*n as $target),
639 Number::I16(n) => Ok(*n as $target),
640 Number::I32(n) => Ok(*n as $target),
641 Number::I64(n) => Ok(*n as $target),
642 Number::U8(n) => Ok(*n as $target),
643 Number::U16(n) => Ok(*n as $target),
644 Number::U32(n) => Ok(*n as $target),
645 Number::U64(n) => Ok(*n as $target),
646 Number::F32(_) | Number::F64(_) => {
647 Err(ConfigError::type_mismatch("integer", value))
648 }
649 _ => {
650 Err(ConfigError::type_mismatch("integer", value))
651 }
652 }
653 } else {
654 Err(ConfigError::type_mismatch("integer", value))
655 }
656 }
657 }
658 )*
659 };
660}
661
662impl_try_from_value_for_int!(u8, i8, u16, i16, u32, i32, u64, i64);
663
664impl TryFrom<&Value> for f64 {
665 type Error = ConfigError;
666
667 fn try_from(value: &Value) -> Result<Self, Self::Error> {
668 if let Value(RonValue::Number(num)) = value {
669 let number = match num {
670 Number::I8(n) => *n as f64,
671 Number::I16(n) => *n as f64,
672 Number::I32(n) => *n as f64,
673 Number::I64(n) => *n as f64,
674 Number::U8(n) => *n as f64,
675 Number::U16(n) => *n as f64,
676 Number::U32(n) => *n as f64,
677 Number::U64(n) => *n as f64,
678 Number::F32(n) => n.0 as f64,
679 Number::F64(n) => n.0,
680 _ => {
681 return Err(ConfigError::type_mismatch("number", value));
682 }
683 };
684 Ok(number)
685 } else {
686 Err(ConfigError::type_mismatch("number", value))
687 }
688 }
689}
690
691impl From<Value> for f64 {
692 fn from(value: Value) -> Self {
693 if let Value(RonValue::Number(num)) = value {
694 num.into_f64()
695 } else {
696 panic!("Expected a Number variant but got {value:?}")
697 }
698 }
699}
700
701impl TryFrom<&Value> for f32 {
703 type Error = ConfigError;
704
705 fn try_from(value: &Value) -> Result<Self, Self::Error> {
706 if let Value(RonValue::Number(num)) = value {
707 let number = match num {
708 Number::I8(n) => *n as f32,
709 Number::I16(n) => *n as f32,
710 Number::I32(n) => *n as f32,
711 Number::I64(n) => *n as f32,
712 Number::U8(n) => *n as f32,
713 Number::U16(n) => *n as f32,
714 Number::U32(n) => *n as f32,
715 Number::U64(n) => *n as f32,
716 Number::F32(n) => n.0,
717 Number::F64(n) => n.0 as f32,
718 _ => {
719 return Err(ConfigError::type_mismatch("number", value));
720 }
721 };
722 Ok(number)
723 } else {
724 Err(ConfigError::type_mismatch("number", value))
725 }
726 }
727}
728
729impl From<Value> for f32 {
730 fn from(value: Value) -> Self {
731 if let Value(RonValue::Number(num)) = value {
732 num.into_f64() as f32
733 } else {
734 panic!("Expected a Number variant but got {value:?}")
735 }
736 }
737}
738
739impl From<String> for Value {
740 fn from(value: String) -> Self {
741 Value(RonValue::String(value))
742 }
743}
744
745impl TryFrom<&Value> for String {
746 type Error = ConfigError;
747
748 fn try_from(value: &Value) -> Result<Self, Self::Error> {
749 if let Value(RonValue::String(s)) = value {
750 Ok(s.clone())
751 } else {
752 Err(ConfigError::type_mismatch("string", value))
753 }
754 }
755}
756
757impl From<Value> for String {
758 fn from(value: Value) -> Self {
759 if let Value(RonValue::String(s)) = value {
760 s
761 } else {
762 panic!("Expected a String variant")
763 }
764 }
765}
766
767impl Display for Value {
768 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
769 let Value(value) = self;
770 match value {
771 RonValue::Number(n) => {
772 let s = match n {
773 Number::I8(n) => n.to_string(),
774 Number::I16(n) => n.to_string(),
775 Number::I32(n) => n.to_string(),
776 Number::I64(n) => n.to_string(),
777 Number::U8(n) => n.to_string(),
778 Number::U16(n) => n.to_string(),
779 Number::U32(n) => n.to_string(),
780 Number::U64(n) => n.to_string(),
781 Number::F32(n) => n.0.to_string(),
782 Number::F64(n) => n.0.to_string(),
783 _ => panic!("Expected a Number variant but got {value:?}"),
784 };
785 write!(f, "{s}")
786 }
787 RonValue::String(s) => write!(f, "{s}"),
788 RonValue::Bool(b) => write!(f, "{b}"),
789 RonValue::Map(m) => write!(f, "{m:?}"),
790 RonValue::Char(c) => write!(f, "{c:?}"),
791 RonValue::Unit => write!(f, "unit"),
792 RonValue::Option(o) => write!(f, "{o:?}"),
793 RonValue::Seq(s) => write!(f, "{s:?}"),
794 RonValue::Bytes(bytes) => write!(f, "{bytes:?}"),
795 }
796 }
797}