Skip to main content

type_bridge/
value.rs

1#![deny(missing_docs)]
2//! Client-owned canonical query literals (Flight 3, F3-02).
3//!
4//! Query operands are deliberately distinct from generated attribute
5//! wrappers: a prefix or range boundary is a valid operand even when it is
6//! not itself storable, so no constructor here applies a field's storage
7//! annotations. Invalid grammar, nonfinite doubles, over-limit text, and
8//! invalid regex fail at literal construction.
9
10use crate::__codegen::{
11    CanonicalDouble, Date as CodegenDate, DateTime as CodegenDateTime,
12    DateTimeTz as CodegenDateTimeTz, Decimal as CodegenDecimal, Duration as CodegenDuration,
13    ValidationError,
14};
15use type_bridge_contract::value::CanonicalString;
16
17fn literal_error(field: &'static str, code: &'static str) -> ValidationError {
18    ValidationError::new(field, code)
19}
20
21/// Bounded canonical text for equality, ordering, and substring operators.
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct Text(String);
24
25impl Text {
26    /// Validate one bounded canonical text literal.
27    pub fn new(value: impl Into<String>) -> Result<Self, ValidationError> {
28        let value = value.into();
29        CanonicalString::new(&value).map_err(|_| literal_error("text", "string_limit_exceeded"))?;
30        Ok(Self(value))
31    }
32    /// Return the validated text.
33    #[must_use]
34    pub fn as_str(&self) -> &str {
35        &self.0
36    }
37    pub(crate) fn into_string(self) -> String {
38        self.0
39    }
40}
41
42/// A client-owned validated regular expression operand.
43#[derive(Clone, Debug)]
44pub struct Regex(String);
45
46impl Regex {
47    /// Compile-validate one regular expression pattern.
48    pub fn new(pattern: impl Into<String>) -> Result<Self, ValidationError> {
49        let pattern = pattern.into();
50        CanonicalString::new(&pattern)
51            .map_err(|_| literal_error("regex", "string_limit_exceeded"))?;
52        regex::Regex::new(&pattern).map_err(|_| literal_error("regex", "invalid_regex_pattern"))?;
53        Ok(Self(pattern))
54    }
55    /// Return the validated pattern text.
56    #[must_use]
57    pub fn as_str(&self) -> &str {
58        &self.0
59    }
60    pub(crate) fn into_string(self) -> String {
61        self.0
62    }
63}
64
65/// A finite exact-bit double literal; signed zero is preserved.
66#[derive(Clone, Copy, Debug, PartialEq)]
67pub struct Double(f64);
68
69impl Double {
70    /// Validate one finite double literal.
71    pub fn new(value: f64) -> Result<Self, ValidationError> {
72        CanonicalDouble::try_new(value)?;
73        Ok(Self(value))
74    }
75    /// Return the finite value.
76    #[must_use]
77    pub fn get(&self) -> f64 {
78        self.0
79    }
80}
81
82macro_rules! grammar_literal {
83    ($(#[$doc:meta])* $name:ident, $inner:ident) => {
84        $(#[$doc])*
85        #[derive(Clone, Debug, PartialEq, Eq)]
86        pub struct $name(String);
87
88        impl $name {
89            /// Validate one canonical literal of this domain.
90            pub fn new(value: impl AsRef<str>) -> Result<Self, ValidationError> {
91                let validated = $inner::try_new(value.as_ref())?;
92                Ok(Self(validated.as_str().to_owned()))
93            }
94            /// Return the canonical literal text.
95            #[must_use]
96            pub fn as_str(&self) -> &str {
97                &self.0
98            }
99            pub(crate) fn into_string(self) -> String {
100                self.0
101            }
102        }
103    };
104}
105
106grammar_literal!(
107    /// A canonical decimal literal.
108    Decimal,
109    CodegenDecimal
110);
111grammar_literal!(
112    /// A canonical date literal.
113    Date,
114    CodegenDate
115);
116grammar_literal!(
117    /// A canonical datetime literal.
118    DateTime,
119    CodegenDateTime
120);
121grammar_literal!(
122    /// A canonical datetime-tz literal.
123    DateTimeTz,
124    CodegenDateTimeTz
125);
126grammar_literal!(
127    /// A canonical duration literal.
128    Duration,
129    CodegenDuration
130);