graphrecords_query/operations/logic/
not.rs1use 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}