rdf_fusion_functions/scalar/numeric/
add.rs

1use crate::scalar::dispatch::dispatch_binary_typed_value;
2use crate::scalar::sparql_op_impl::{
3    ScalarSparqlOpImpl, create_typed_value_sparql_op_impl,
4};
5use crate::scalar::{ScalarSparqlOp, ScalarSparqlOpSignature, SparqlOpArity};
6use rdf_fusion_encoding::typed_value::TypedValueEncoding;
7use rdf_fusion_extensions::functions::BuiltinName;
8use rdf_fusion_extensions::functions::FunctionName;
9use rdf_fusion_model::{Numeric, NumericPair, ThinError, TypedValueRef};
10
11/// Implementation of the SPARQL `+` operator.
12#[derive(Debug, Hash, PartialEq, Eq)]
13pub struct AddSparqlOp;
14
15impl Default for AddSparqlOp {
16    fn default() -> Self {
17        Self::new()
18    }
19}
20
21impl AddSparqlOp {
22    const NAME: FunctionName = FunctionName::Builtin(BuiltinName::Add);
23
24    /// Creates a new [AddSparqlOp].
25    pub fn new() -> Self {
26        Self {}
27    }
28}
29
30impl ScalarSparqlOp for AddSparqlOp {
31    fn name(&self) -> &FunctionName {
32        &Self::NAME
33    }
34
35    fn signature(&self) -> ScalarSparqlOpSignature {
36        ScalarSparqlOpSignature::default_with_arity(SparqlOpArity::Fixed(2))
37    }
38
39    fn typed_value_encoding_op(
40        &self,
41    ) -> Option<Box<dyn ScalarSparqlOpImpl<TypedValueEncoding>>> {
42        Some(create_typed_value_sparql_op_impl(|args| {
43            dispatch_binary_typed_value(
44                &args.args[0],
45                &args.args[1],
46                |lhs_value, rhs_value| {
47                    if let (
48                        TypedValueRef::NumericLiteral(lhs_numeric),
49                        TypedValueRef::NumericLiteral(rhs_numeric),
50                    ) = (lhs_value, rhs_value)
51                    {
52                        let result = match NumericPair::with_casts_from(
53                            lhs_numeric,
54                            rhs_numeric,
55                        ) {
56                            NumericPair::Int(lhs, rhs) => {
57                                lhs.checked_add(rhs).map(Numeric::Int)
58                            }
59                            NumericPair::Integer(lhs, rhs) => {
60                                lhs.checked_add(rhs).map(Numeric::Integer)
61                            }
62                            NumericPair::Float(lhs, rhs) => Ok(Numeric::Float(lhs + rhs)),
63                            NumericPair::Double(lhs, rhs) => {
64                                Ok(Numeric::Double(lhs + rhs))
65                            }
66                            NumericPair::Decimal(lhs, rhs) => {
67                                lhs.checked_add(rhs).map(Numeric::Decimal)
68                            }
69                        }?;
70                        Ok(TypedValueRef::NumericLiteral(result))
71                    } else {
72                        ThinError::expected()
73                    }
74                },
75                |_, _| ThinError::expected(),
76            )
77        }))
78    }
79}