dbgen/functions/
mod.rs

1//! Defines functions for evaluation.
2
3use crate::{
4    error::Error,
5    eval::{CompileContext, C},
6    span::{ResultExt, Span, SpanExt, S},
7    value::Value,
8};
9
10use std::{convert::TryFrom, fmt::Debug};
11
12pub mod array;
13pub mod debug;
14pub mod ops;
15pub mod rand;
16pub mod string;
17pub mod time;
18
19/// Container of the arguments passed to functions.
20pub type Arguments = smallvec::SmallVec<[S<Value>; 2]>;
21
22/// An SQL function.
23pub trait Function: Sync + Debug {
24    /// Compiles or evaluates this function taking the provided arguments.
25    fn compile(&self, ctx: &CompileContext, span: Span, args: Arguments) -> Result<C, S<Error>>;
26}
27
28trait TryFromSpannedValue: Sized {
29    fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>>;
30}
31
32impl<T> TryFromSpannedValue for T
33where
34    T: TryFrom<Value>,
35    Error: From<T::Error>,
36{
37    fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>> {
38        let span = value.span;
39        Self::try_from(value.inner).span_err(span)
40    }
41}
42
43impl TryFromSpannedValue for S<String> {
44    fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>> {
45        String::try_from(value.inner).span_ok_err(value.span)
46    }
47}
48
49impl TryFromSpannedValue for S<Value> {
50    fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>> {
51        Ok(value)
52    }
53}
54
55macro_rules! declare_arg_fn {
56    (
57        $(#[$meta:meta])*
58        fn $name:ident($($def:ident: $ty:ident),+);
59    ) => {
60        $(#[$meta])*
61        fn $name<$($ty),+>(span: Span, args: Arguments, $($def: Option<$ty>),+) -> Result<($($ty),+), S<Error>>
62        where
63            $($ty: TryFromSpannedValue,)+
64        {
65            let mut it = args.into_iter();
66            $(
67                let $def = if let Some(arg) = it.next() {
68                    $ty::try_from_spanned_value(arg)
69                } else {
70                    $def.ok_or(Error::NotEnoughArguments.span(span))
71                }?;
72            )+
73            Ok(($($def),+))
74        }
75    }
76}
77
78declare_arg_fn! {
79    /// Extracts one value from the list of arguments.
80    #[allow(unused_parens)] // we do want args_1 to return the value instead of 1-tuple.
81    fn args_1(d1: T1);
82}
83declare_arg_fn! {
84    /// Extracts two values from the list of arguments.
85    fn args_2(d1: T1, d2: T2);
86}
87declare_arg_fn! {
88    /// Extracts three values from the list of arguments.
89    fn args_3(d1: T1, d2: T2, d3: T3);
90}
91declare_arg_fn! {
92    /// Extracts four values from the list of arguments.
93    fn args_4(d1: T1, d2: T2, d3: T3, d4: T4);
94}
95
96/// Converts a slice of arguments all into a specific type.
97fn iter_args<T>(args: Arguments) -> impl Iterator<Item = Result<T, S<Error>>>
98where
99    T: TryFromSpannedValue,
100{
101    args.into_iter().map(T::try_from_spanned_value)
102}
103
104fn require(span: Span, cond: bool, cause: impl FnOnce() -> String) -> Result<(), S<Error>> {
105    if cond {
106        Ok(())
107    } else {
108        Err(Error::InvalidArguments(cause()).span(span))
109    }
110}