Skip to main content

toasty/stmt/
into_expr.rs

1use std::{rc::Rc, sync::Arc};
2
3use super::assignment::impl_assign_via_expr;
4use super::{Expr, List, Value};
5#[cfg(feature = "net")]
6use super::{IpCidr, IpInet, MacAddr6, MacAddr8};
7use toasty_core::stmt;
8
9/// Convert a value into an [`Expr<T>`].
10///
11/// This trait is the primary way Toasty coerces Rust values into query
12/// expressions. It is implemented for all scalar types (`i64`, `String`,
13/// `bool`, `uuid::Uuid`, …), `Option<T>`, tuples, slices, `Vec`, and arrays.
14///
15/// Generated code uses `IntoExpr` bounds on filter and setter methods so that
16/// callers can pass either a raw value or an already-constructed [`Expr`]:
17///
18/// ```
19/// # use toasty::stmt::{Expr, IntoExpr};
20/// // Both &str and Expr<String> implement IntoExpr<String>:
21/// let _e1: Expr<String> = "Alice".into_expr();
22/// let _e2: Expr<String> = Expr::<String>::from_untyped(
23///     toasty_core::stmt::Value::from("Bob"),
24/// ).into_expr();
25/// ```
26///
27/// # Implementing for custom types
28///
29/// If you have a newtype that wraps a supported scalar, implement `IntoExpr`
30/// by converting to the inner type first, then calling [`Expr::from_value`].
31pub trait IntoExpr<T> {
32    /// Consume `self` and produce an [`Expr<T>`].
33    ///
34    /// # Examples
35    ///
36    /// ```
37    /// use toasty::stmt::{Expr, IntoExpr};
38    ///
39    /// let _expr: Expr<i64> = 42_i64.into_expr();
40    /// let _expr: Expr<String> = "hello".into_expr();
41    /// ```
42    fn into_expr(self) -> Expr<T>;
43
44    /// Produce an [`Expr<T>`] from a reference without consuming `self`.
45    ///
46    /// For [`Copy`] types this clones the value. For non-`Copy` types like
47    /// `String` this clones the underlying data.
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// use toasty::stmt::{Expr, IntoExpr};
53    ///
54    /// let value = 42_i64;
55    /// let _expr: Expr<i64> = value.by_ref();
56    /// // `value` is still usable
57    /// assert_eq!(value, 42);
58    /// ```
59    fn by_ref(&self) -> Expr<T>;
60}
61
62macro_rules! impl_into_expr_for_copy {
63    ( $( $var:ident($t:ty) ;)* ) => {
64        $(
65            impl IntoExpr<$t> for $t {
66                fn into_expr(self) -> Expr<$t> {
67                    Expr::from_value(Value::from(self))
68                }
69
70                fn by_ref(&self) -> Expr<$t> {
71                    Expr::from_value(Value::from(self.clone()))
72                }
73            }
74
75            impl_assign_via_expr!($t => $t);
76        )*
77    };
78}
79
80impl_into_expr_for_copy! {
81    Bool(bool);
82    I8(i8);
83    I16(i16);
84    I32(i32);
85    I64(i64);
86    U8(u8);
87    U16(u16);
88    U32(u32);
89    U64(u64);
90    F32(f32);
91    F64(f64);
92    Uuid(uuid::Uuid);
93}
94
95#[cfg(feature = "jiff")]
96impl_into_expr_for_copy! {
97    Timestamp(jiff::Timestamp);
98    Zoned(jiff::Zoned);
99    Date(jiff::civil::Date);
100    Time(jiff::civil::Time);
101    DateTime(jiff::civil::DateTime);
102}
103
104/// A time zone binds as its text form (see `schema::jiff`). Unlike the other
105/// conversions here this one can fail, and `into_expr` has no error channel —
106/// carrying the zone to a fallible cast instead would mean a `Value::TimeZone`
107/// variant and the core plumbing behind it.
108#[cfg(feature = "jiff")]
109impl IntoExpr<jiff::tz::TimeZone> for jiff::tz::TimeZone {
110    fn into_expr(self) -> Expr<jiff::tz::TimeZone> {
111        self.by_ref()
112    }
113
114    fn by_ref(&self) -> Expr<jiff::tz::TimeZone> {
115        let text = crate::schema::jiff::time_zone_to_text(self)
116            .expect("time zone cannot be stored: no IANA identifier, fixed offset, or POSIX rule");
117        Expr::from_value(Value::String(text))
118    }
119}
120
121#[cfg(feature = "jiff")]
122impl_assign_via_expr!(jiff::tz::TimeZone => jiff::tz::TimeZone);
123
124#[cfg(feature = "net")]
125impl_into_expr_for_copy! {
126    Cidr(IpCidr);
127    Inet(IpInet);
128    MacAddr(MacAddr6);
129    MacAddr8(MacAddr8);
130}
131
132// Pointer-sized integers convert through their fixed-size equivalents
133impl IntoExpr<isize> for isize {
134    fn into_expr(self) -> Expr<isize> {
135        Expr::from_value(Value::from(self as i64))
136    }
137
138    fn by_ref(&self) -> Expr<isize> {
139        Expr::from_value(Value::from(*self as i64))
140    }
141}
142impl_assign_via_expr!(isize => isize);
143
144impl IntoExpr<usize> for usize {
145    fn into_expr(self) -> Expr<usize> {
146        Expr::from_value(Value::from(self as u64))
147    }
148
149    fn by_ref(&self) -> Expr<usize> {
150        Expr::from_value(Value::from(*self as u64))
151    }
152}
153impl_assign_via_expr!(usize => usize);
154
155impl<T> IntoExpr<T> for Expr<T> {
156    fn into_expr(self) -> Self {
157        self
158    }
159
160    fn by_ref(&self) -> Self {
161        self.clone()
162    }
163}
164impl_assign_via_expr!({T} Expr<T> => T);
165
166impl<T: IntoExpr<T>> IntoExpr<T> for &T {
167    fn into_expr(self) -> Expr<T> {
168        self.by_ref()
169    }
170
171    fn by_ref(&self) -> Expr<T> {
172        (*self).by_ref()
173    }
174}
175impl_assign_via_expr!({T: IntoExpr<T>} &T => T);
176
177impl<T: IntoExpr<T>> IntoExpr<Self> for Option<T> {
178    fn into_expr(self) -> Expr<Self> {
179        match self {
180            Some(value) => value.into_expr().cast(),
181            None => Expr::from_value(Value::Null),
182        }
183    }
184
185    fn by_ref(&self) -> Expr<Self> {
186        match self {
187            Some(value) => value.by_ref().cast(),
188            None => Expr::from_value(Value::Null),
189        }
190    }
191}
192impl_assign_via_expr!({T: IntoExpr<T>} Option<T> => Option<T>);
193
194impl<T: IntoExpr<T>> IntoExpr<Option<T>> for T {
195    fn into_expr(self) -> Expr<Option<T>> {
196        self.into_expr().cast()
197    }
198
199    fn by_ref(&self) -> Expr<Option<T>> {
200        self.by_ref().cast()
201    }
202}
203impl_assign_via_expr!({T: IntoExpr<T>} T => Option<T>);
204
205impl<T: IntoExpr<T>> IntoExpr<Option<T>> for &T {
206    fn into_expr(self) -> Expr<Option<T>> {
207        self.by_ref().cast()
208    }
209
210    fn by_ref(&self) -> Expr<Option<T>> {
211        (*self).by_ref().cast()
212    }
213}
214impl_assign_via_expr!({T: IntoExpr<T>} &T => Option<T>);
215
216impl IntoExpr<String> for &str {
217    fn into_expr(self) -> Expr<String> {
218        Expr::from_value(Value::from(self))
219    }
220
221    fn by_ref(&self) -> Expr<String> {
222        Expr::from_value(Value::from(*self))
223    }
224}
225impl_assign_via_expr!(&str => String);
226
227impl IntoExpr<Option<String>> for &str {
228    fn into_expr(self) -> Expr<Option<String>> {
229        Expr::from_value(Value::from(self))
230    }
231
232    fn by_ref(&self) -> Expr<Option<String>> {
233        Expr::from_value(Value::from(*self))
234    }
235}
236impl_assign_via_expr!(&str => Option<String>);
237
238impl IntoExpr<Self> for String {
239    fn into_expr(self) -> Expr<Self> {
240        Expr::from_value(self.into())
241    }
242
243    fn by_ref(&self) -> Expr<Self> {
244        Expr::from_value(self.into())
245    }
246}
247impl_assign_via_expr!(String => String);
248
249impl IntoExpr<Self> for Vec<u8> {
250    fn into_expr(self) -> Expr<Self> {
251        Expr::from_value(self.into())
252    }
253
254    fn by_ref(&self) -> Expr<Self> {
255        Expr::from_value(self.clone().into())
256    }
257}
258impl_assign_via_expr!(Vec<u8> => Vec<u8>);
259
260#[cfg(feature = "rust_decimal")]
261impl IntoExpr<Self> for rust_decimal::Decimal {
262    fn into_expr(self) -> Expr<Self> {
263        Expr::from_value(self.into())
264    }
265
266    fn by_ref(&self) -> Expr<Self> {
267        Expr::from_value((*self).into())
268    }
269}
270#[cfg(feature = "rust_decimal")]
271impl_assign_via_expr!(rust_decimal::Decimal => rust_decimal::Decimal);
272
273#[cfg(feature = "bigdecimal")]
274impl IntoExpr<Self> for bigdecimal::BigDecimal {
275    fn into_expr(self) -> Expr<Self> {
276        Expr::from_value(self.into())
277    }
278
279    fn by_ref(&self) -> Expr<Self> {
280        Expr::from_value(self.clone().into())
281    }
282}
283#[cfg(feature = "bigdecimal")]
284impl_assign_via_expr!(bigdecimal::BigDecimal => bigdecimal::BigDecimal);
285
286impl<T, U, const N: usize> IntoExpr<List<T>> for [U; N]
287where
288    U: IntoExpr<T>,
289{
290    fn into_expr(self) -> Expr<List<T>> {
291        Expr::from_untyped(stmt::Expr::list(
292            self.into_iter().map(|item| item.into_expr().untyped),
293        ))
294    }
295
296    fn by_ref(&self) -> Expr<List<T>> {
297        Expr::from_untyped(stmt::Expr::list(
298            self.iter().map(|item| U::by_ref(item).untyped),
299        ))
300    }
301}
302impl_assign_via_expr!({T, U: IntoExpr<T>, const N: usize} [U; N] => List<T>);
303
304impl<T, U, const N: usize> IntoExpr<List<T>> for &[U; N]
305where
306    U: IntoExpr<T>,
307{
308    fn into_expr(self) -> Expr<List<T>> {
309        Expr::from_untyped(stmt::Expr::list(
310            self.iter().map(|item| U::by_ref(item).untyped),
311        ))
312    }
313
314    fn by_ref(&self) -> Expr<List<T>> {
315        Expr::from_untyped(stmt::Expr::list(
316            self.iter().map(|item| U::by_ref(item).untyped),
317        ))
318    }
319}
320impl_assign_via_expr!({T, U: IntoExpr<T>, const N: usize} &[U; N] => List<T>);
321
322impl<T, E: IntoExpr<T>> IntoExpr<List<T>> for &[E] {
323    fn into_expr(self) -> Expr<List<T>> {
324        Expr::from_untyped(stmt::Expr::list(
325            self.iter().map(|item| E::by_ref(item).untyped),
326        ))
327    }
328
329    fn by_ref(&self) -> Expr<List<T>> {
330        Expr::from_untyped(stmt::Expr::list(
331            self.iter().map(|item| E::by_ref(item).untyped),
332        ))
333    }
334}
335impl_assign_via_expr!({T, E: IntoExpr<T>} &[E] => List<T>);
336
337impl<T, U> IntoExpr<List<T>> for Vec<U>
338where
339    U: IntoExpr<T>,
340{
341    fn into_expr(self) -> Expr<List<T>> {
342        Expr::from_untyped(stmt::Expr::list(
343            self.into_iter().map(|item| item.into_expr().untyped),
344        ))
345    }
346
347    fn by_ref(&self) -> Expr<List<T>> {
348        Expr::from_untyped(stmt::Expr::list(
349            self.iter().map(|item| item.by_ref().untyped),
350        ))
351    }
352}
353impl_assign_via_expr!({T, U: IntoExpr<T>} Vec<U> => List<T>);
354
355// `Vec<scalar>` model fields bind through the existing `IntoExpr<List<T>>`
356// impls (slice, array, `Vec<U>`, …) — `Field::ExprTarget = List<T>` for
357// `Vec<T: Scalar>`, so the create/update setter macros emit
358// `IntoExpr<List<T>>` bounds without any type parsing. `Vec<u8>` keeps
359// `ExprTarget = Self` and goes through its scalar `IntoExpr<Vec<u8>>` impl
360// above.
361
362macro_rules! forward_impl {
363    ( $( $ty:ty ,) *) => {
364        $(
365            impl<T> IntoExpr<$ty> for T
366            where
367                T: IntoExpr<T>,
368            {
369                fn into_expr(self) -> Expr<$ty> {
370                    <Self as IntoExpr<Self>>::into_expr(self).cast()
371                }
372
373                fn by_ref(&self) -> Expr<$ty> {
374                    <Self as IntoExpr<Self>>::by_ref(self).cast()
375                }
376            }
377        ) *
378    };
379}
380
381forward_impl!(Arc<T>, Box<T>, Rc<T>,);
382impl_assign_via_expr!({T: IntoExpr<T>} T => Arc<T>);
383impl_assign_via_expr!({T: IntoExpr<T>} T => Box<T>);
384impl_assign_via_expr!({T: IntoExpr<T>} T => Rc<T>);
385
386macro_rules! ref_smart_ptr_impl {
387    ( $( $ptr:ident ,)* ) => {
388        $(
389            impl<T: IntoExpr<T>> IntoExpr<$ptr<T>> for $ptr<T> {
390                fn into_expr(self) -> Expr<$ptr<T>> {
391                    T::by_ref(&self).cast()
392                }
393
394                fn by_ref(&self) -> Expr<$ptr<T>> {
395                    T::by_ref(self).cast()
396                }
397            }
398
399            impl<T: IntoExpr<T>> IntoExpr<T> for &$ptr<T> {
400                fn into_expr(self) -> Expr<T> {
401                    T::by_ref(self)
402                }
403
404                fn by_ref(&self) -> Expr<T> {
405                    T::by_ref(self)
406                }
407            }
408        )*
409    };
410}
411
412ref_smart_ptr_impl!(Arc, Box, Rc,);
413
414macro_rules! impl_into_expr_for_tuple {
415    (! $( $n:tt $t:ident $e:ident )* ) => {
416        impl<$( $t, $e ),*> IntoExpr<($( $t, )*)> for ($( $e, )*)
417        where
418            $( $e: IntoExpr<$t>, )*
419        {
420            fn into_expr(self) -> Expr<($( $t, )*)> {
421                let record = stmt::ExprRecord::from_vec(vec![
422                    $( self.$n.into_expr().untyped, )*
423                ]);
424                let untyped = stmt::Expr::Record(record);
425                Expr::from_untyped(untyped)
426            }
427
428            fn by_ref(&self) -> Expr<($( $t, )*)> {
429                let record = stmt::ExprRecord::from_vec(vec![
430                    $( self.$n.by_ref().untyped, )*
431                ]);
432                let untyped = stmt::Expr::Record(record);
433                Expr::from_untyped(untyped)
434            }
435        }
436
437        impl_assign_via_expr!({$( $t, $e: IntoExpr<$t> ),*} ($( $e, )*) => ($( $t, )*));
438    };
439
440    (
441        ( $( $n_base:tt $t_base:ident $e_base:ident )* )
442        $n:tt $t:ident $e:ident
443        $( $rest:tt )*
444    ) => {
445        // Implement for tuples at this level
446        impl_into_expr_for_tuple!(! $( $n_base $t_base $e_base )* $n $t $e);
447
448        // Recurse
449        impl_into_expr_for_tuple!(
450            ( $( $n_base $t_base $e_base )* $n $t $e )
451            $( $rest )*
452        );
453    };
454
455    ( ( $( $n:tt $t:ident $e:ident )* ) ) => {}
456}
457
458impl_into_expr_for_tuple! {
459    ()
460    0 T0 E0
461    1 T1 E1
462    2 T2 E2
463    3 T3 E3
464    4 T4 E4
465    5 T5 E5
466    6 T6 E6
467    7 T7 E7
468    8 T8 E8
469    9 T9 E9
470}
471
472#[test]
473fn assert_bounds() {
474    fn assert_into_expr<T, E: IntoExpr<T>>() {}
475
476    assert_into_expr::<i64, i64>();
477    assert_into_expr::<(String, String), (&String, &String)>();
478    assert_into_expr::<List<(String, String)>, &[(&String, &String)]>();
479    assert_into_expr::<List<(String, String)>, [(&String, &String); 3]>();
480    assert_into_expr::<List<(String, String)>, &[(&String, &String); 3]>();
481}