Skip to main content

graphrecords_query/operations/logic/
not.rs

1use crate::{
2    Arity, Bare, ElementShape, Explain, IndexDomain, Indexed, Mask, Not, Operand, QueryResult,
3    element::{Pipeline, Preserving},
4    execution::EvaluationCache,
5    operands::OperandHandle,
6    operations::{Apply, ElementKernel, ElementPipeline, Operation, OperationContext, Prepare},
7    optimizer::{Estimate, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs, Stats},
8    registry::operation_manifest,
9};
10use graphrecords_core::GraphRecord;
11use std::ops::Not as BitNot;
12
13#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
14#[operation(scope = Element)]
15#[explain(label = "Not")]
16#[plan(optimizer_hints(
17    commutes_with_filter,
18    allows_limit_pushdown,
19    empty = if_any
20))]
21pub struct NotOperation;
22
23impl Prepare for NotOperation {
24    type Prepared<'a> = ();
25
26    fn prepare<'a>(
27        &'a self,
28        _graphrecord: &'a GraphRecord,
29        _cache: &'a EvaluationCache<'a>,
30    ) -> QueryResult<Self::Prepared<'a>> {
31        Ok(())
32    }
33}
34
35impl<I: IndexDomain> ElementKernel<Indexed<I, Mask>> for NotOperation {
36    type Emission = Preserving;
37    type OutShape = Indexed<I, Mask>;
38
39    fn pipeline<'a>(
40        _graphrecord: &'a GraphRecord,
41        _prepared: Self::Prepared<'a>,
42    ) -> QueryResult<ElementPipeline<'a, Indexed<I, Mask>, Self>> {
43        Ok(Pipeline::unkeyed(|value: QueryResult<bool>| {
44            value.map(|value| !value)
45        }))
46    }
47
48    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
49        Estimate {
50            selectivity: input.selectivity.map(|selectivity| 1.0 - selectivity),
51            ..input
52        }
53    }
54}
55
56impl ElementKernel<Bare<Mask>> for NotOperation {
57    type Emission = Preserving;
58    type OutShape = Bare<Mask>;
59
60    fn pipeline<'a>(
61        _graphrecord: &'a GraphRecord,
62        _prepared: Self::Prepared<'a>,
63    ) -> QueryResult<ElementPipeline<'a, Bare<Mask>, Self>> {
64        Ok(Pipeline::new(|value: QueryResult<bool>| {
65            value.map(|value| !value)
66        }))
67    }
68
69    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
70        Estimate {
71            selectivity: input.selectivity.map(|selectivity| 1.0 - selectivity),
72            ..input
73        }
74    }
75}
76
77impl<O: Apply<NotOperation>> Not for O {
78    type ReturnOperand = O::Output;
79
80    fn not(&self) -> Self::ReturnOperand {
81        Self::ReturnOperand::new(OperationContext::new(self.clone(), NotOperation))
82    }
83}
84
85impl<S, C> BitNot for OperandHandle<S, C>
86where
87    S: ElementShape,
88    C: Arity,
89    Self: Not,
90{
91    type Output = <Self as Not>::ReturnOperand;
92
93    fn not(self) -> Self::Output {
94        <Self as Not>::not(&self)
95    }
96}
97
98operation_manifest! {
99    NotOperation {
100        method: Not::not;
101        scope: element;
102
103        kernel {
104            parameters: <I: IndexDomain>;
105            input: Indexed<I, Mask>;
106            output: Indexed<I, Mask>;
107            emission: Preserving;
108        }
109
110        kernel {
111            parameters: <>;
112            input: Bare<Mask>;
113            output: Bare<Mask>;
114            emission: Preserving;
115        }
116    }
117}