field_kinds/field_meta/
visitors.rs

1/// Runtime-accessible metadata for a single field.
2///
3/// Contains all information about a field that can be queried at runtime.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct FieldMeta {
6    /// Original field name in Rust code.
7    pub name: &'static str,
8    /// Serialized name (may differ due to `#[serde(rename)]` or `rename_all`).
9    pub serialized_name: &'static str,
10    /// Type category (e.g., "numeric", "text", "bool", "optional", "collection").
11    pub category: &'static str,
12    /// Custom tags added via `#[field_tags(...)]`.
13    pub tags: &'static [&'static str],
14}
15
16impl FieldMeta {
17    /// Checks if this field has the given tag.
18    pub const fn has_tag(&self, tag: &str) -> bool {
19        let mut i = 0;
20        while i < self.tags.len() {
21            if const_str_eq(self.tags[i], tag) {
22                return true;
23            }
24            i += 1;
25        }
26        false
27    }
28
29    /// Checks if this field has the given category.
30    pub const fn has_category(&self, category: &str) -> bool {
31        const_str_eq(self.category, category)
32    }
33
34    /// Checks if this field matches the given criteria.
35    ///
36    /// Returns `true` if:
37    /// - `name` is `None` or matches the field name
38    /// - `category` is `None` or matches the field category
39    /// - `tag` is `None` or the field has the tag
40    pub fn matches(
41        &self,
42        name: Option<&str>,
43        category: Option<&str>,
44        tag: Option<&str>,
45    ) -> bool {
46        let name_ok = name.is_none_or(|n| self.name == n);
47        let category_ok = category.is_none_or(|c| self.category == c);
48        let tag_ok = tag.is_none_or(|t| self.tags.contains(&t));
49        name_ok && category_ok && tag_ok
50    }
51}
52
53const fn const_str_eq(a: &str, b: &str) -> bool {
54    let a = a.as_bytes();
55    let b = b.as_bytes();
56    if a.len() != b.len() {
57        return false;
58    }
59    let mut i = 0;
60    while i < a.len() {
61        if a[i] != b[i] {
62            return false;
63        }
64        i += 1;
65    }
66    true
67}
68
69/// Trait for types that provide static field metadata.
70///
71/// This trait is automatically implemented by the derive macro.
72pub trait VisitFields {
73    /// Static slice containing metadata for all fields.
74    const FIELDS: &'static [FieldMeta];
75}