bp3d_debug/
field.rs

1// Copyright (c) 2025, BlockProject 3D
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification,
6// are permitted provided that the following conditions are met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above copyright notice,
11//       this list of conditions and the following disclaimer in the documentation
12//       and/or other materials provided with the distribution.
13//     * Neither the name of BlockProject 3D nor the names of its contributors
14//       may be used to endorse or promote products derived from this software
15//       without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29use std::fmt::{Debug, Display, Formatter};
30
31#[derive(Debug)]
32pub enum FieldValue<'a> {
33    Int(i64),
34    UInt(u64),
35    Float(f32),
36    Double(f64),
37    String(&'a str),
38    Debug(&'a dyn Debug),
39    Boolean(bool),
40}
41
42impl Display for FieldValue<'_> {
43    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
44        match self {
45            FieldValue::Int(v) => write!(f, "{}", v),
46            FieldValue::UInt(v) => write!(f, "{}", v),
47            FieldValue::Float(v) => write!(f, "{}", v),
48            FieldValue::Double(v) => write!(f, "{}", v),
49            FieldValue::String(v) => f.write_str(v),
50            FieldValue::Debug(v) => write!(f, "{:?}", v),
51            FieldValue::Boolean(v) => write!(f, "{:?}", v),
52        }
53    }
54}
55
56pub struct Field<'a> {
57    name: &'a str,
58    value: FieldValue<'a>,
59}
60
61impl<'a> Field<'a> {
62    pub fn new(name: &'a str, value: impl Into<FieldValue<'a>>) -> Self {
63        Self {
64            name,
65            value: value.into(),
66        }
67    }
68
69    pub fn new_debug(name: &'a str, value: &'a dyn Debug) -> Self {
70        Self {
71            name,
72            value: FieldValue::Debug(value),
73        }
74    }
75
76    pub fn name(&self) -> &str {
77        self.name
78    }
79
80    pub fn value(&self) -> &FieldValue<'a> {
81        &self.value
82    }
83}
84
85macro_rules! impl_into_field_value {
86    // Would've preferred expr, but turns out expr is useless in macros, so let's not use it.
87    ($($t: ty => $func: ident),*) => {
88        $(
89            impl<'a> From<$t> for FieldValue<'a> {
90                fn from(value: $t) -> Self {
91                    FieldValue::$func(value as _)
92                }
93            }
94        )*
95    };
96}
97
98impl_into_field_value! {
99    u8 => UInt,
100    u16 => UInt,
101    u32 => UInt,
102    u64 => UInt,
103    usize => UInt,
104    i8 => Int,
105    i16 => Int,
106    i32 => Int,
107    i64 => Int,
108    isize => Int,
109    f32 => Float,
110    f64 => Double,
111    bool => Boolean
112}
113
114impl<'a> From<&'a str> for FieldValue<'a> {
115    fn from(value: &'a str) -> Self {
116        Self::String(value)
117    }
118}
119
120pub struct FieldSet<'a, const N: usize>([Field<'a>; N]);
121
122impl<'a, const N: usize> FieldSet<'a, N> {
123    pub fn new(fields: [Field<'a>; N]) -> Self {
124        Self(fields)
125    }
126}
127
128impl<'a, const N: usize> AsRef<[Field<'a>]> for FieldSet<'a, N> {
129    fn as_ref(&self) -> &[Field<'a>] {
130        &self.0
131    }
132}
133
134#[macro_export]
135macro_rules! field {
136    ($name: ident) => {
137        $crate::field::Field::new(stringify!($name), $name)
138    };
139    (?$name: ident) => {
140        $crate::field::Field::new_debug(stringify!($name), &$name)
141    };
142    ($name: ident = $value: expr) => {
143        $crate::field::Field::new(stringify!($name), $value)
144    };
145    ($name: ident = ?$value: expr) => {
146        $crate::field::Field::new_debug(stringify!($name), &$value)
147    };
148}
149
150#[macro_export]
151macro_rules! fields {
152    ($({$($field: tt)*})*) => {
153        [$(
154            $crate::field!($($field)*),
155        )*]
156    };
157}