1use anyhow::Result;
2
3use super::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
4use crate::data::datatable::DataValue;
5
6pub struct ChargeElectronFunction;
8
9impl SqlFunction for ChargeElectronFunction {
10 fn signature(&self) -> FunctionSignature {
11 FunctionSignature {
12 name: "CHARGE_ELECTRON",
13 category: FunctionCategory::Constant,
14 arg_count: ArgCount::Fixed(0),
15 description: "Returns the electron charge in coulombs (-1.602176634 × 10^-19 C)",
16 returns: "FLOAT",
17 examples: vec![
18 "SELECT CHARGE_ELECTRON()",
19 "SELECT n_electrons * CHARGE_ELECTRON() AS total_charge",
20 ],
21 }
22 }
23
24 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
25 self.validate_args(args)?;
26 Ok(DataValue::Float(-1.602176634e-19)) }
28}
29
30pub struct ChargeProtonFunction;
32
33impl SqlFunction for ChargeProtonFunction {
34 fn signature(&self) -> FunctionSignature {
35 FunctionSignature {
36 name: "CHARGE_PROTON",
37 category: FunctionCategory::Constant,
38 arg_count: ArgCount::Fixed(0),
39 description: "Returns the proton charge in coulombs (+1.602176634 × 10^-19 C)",
40 returns: "FLOAT",
41 examples: vec![
42 "SELECT CHARGE_PROTON()",
43 "SELECT n_protons * CHARGE_PROTON() AS nuclear_charge",
44 ],
45 }
46 }
47
48 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
49 self.validate_args(args)?;
50 Ok(DataValue::Float(1.602176634e-19)) }
52}
53
54pub struct ChargeNeutronFunction;
56
57impl SqlFunction for ChargeNeutronFunction {
58 fn signature(&self) -> FunctionSignature {
59 FunctionSignature {
60 name: "CHARGE_NEUTRON",
61 category: FunctionCategory::Constant,
62 arg_count: ArgCount::Fixed(0),
63 description: "Returns the neutron charge in coulombs (0 C)",
64 returns: "FLOAT",
65 examples: vec![
66 "SELECT CHARGE_NEUTRON()",
67 "SELECT CHARGE_NEUTRON() + CHARGE_PROTON() AS net_nucleon_charge",
68 ],
69 }
70 }
71
72 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
73 self.validate_args(args)?;
74 Ok(DataValue::Float(0.0)) }
76}
77
78pub struct ChargeUpQuarkFunction;
80
81impl SqlFunction for ChargeUpQuarkFunction {
82 fn signature(&self) -> FunctionSignature {
83 FunctionSignature {
84 name: "CHARGE_UP_QUARK",
85 category: FunctionCategory::Constant,
86 arg_count: ArgCount::Fixed(0),
87 description: "Returns the up quark charge in coulombs (+2/3 × 1.602176634 × 10^-19 C)",
88 returns: "FLOAT",
89 examples: vec![
90 "SELECT CHARGE_UP_QUARK()",
91 "SELECT 2 * CHARGE_UP_QUARK() + CHARGE_DOWN_QUARK() AS proton_charge",
92 ],
93 }
94 }
95
96 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
97 self.validate_args(args)?;
98 Ok(DataValue::Float(2.0 / 3.0 * 1.602176634e-19)) }
100}
101
102pub struct ChargeDownQuarkFunction;
104
105impl SqlFunction for ChargeDownQuarkFunction {
106 fn signature(&self) -> FunctionSignature {
107 FunctionSignature {
108 name: "CHARGE_DOWN_QUARK",
109 category: FunctionCategory::Constant,
110 arg_count: ArgCount::Fixed(0),
111 description:
112 "Returns the down quark charge in coulombs (-1/3 × 1.602176634 × 10^-19 C)",
113 returns: "FLOAT",
114 examples: vec![
115 "SELECT CHARGE_DOWN_QUARK()",
116 "SELECT CHARGE_UP_QUARK() + 2 * CHARGE_DOWN_QUARK() AS neutron_charge",
117 ],
118 }
119 }
120
121 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
122 self.validate_args(args)?;
123 Ok(DataValue::Float(-1.0 / 3.0 * 1.602176634e-19)) }
125}
126
127pub struct ChargePositronFunction;
129
130impl SqlFunction for ChargePositronFunction {
131 fn signature(&self) -> FunctionSignature {
132 FunctionSignature {
133 name: "CHARGE_POSITRON",
134 category: FunctionCategory::Constant,
135 arg_count: ArgCount::Fixed(0),
136 description: "Returns the positron charge in coulombs (+1.602176634 × 10^-19 C)",
137 returns: "FLOAT",
138 examples: vec![
139 "SELECT CHARGE_POSITRON()",
140 "SELECT CHARGE_ELECTRON() + CHARGE_POSITRON() AS annihilation_charge",
141 ],
142 }
143 }
144
145 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
146 self.validate_args(args)?;
147 Ok(DataValue::Float(1.602176634e-19)) }
149}
150
151pub struct ChargeMuonFunction;
153
154impl SqlFunction for ChargeMuonFunction {
155 fn signature(&self) -> FunctionSignature {
156 FunctionSignature {
157 name: "CHARGE_MUON",
158 category: FunctionCategory::Constant,
159 arg_count: ArgCount::Fixed(0),
160 description: "Returns the muon charge in coulombs (-1.602176634 × 10^-19 C)",
161 returns: "FLOAT",
162 examples: vec![
163 "SELECT CHARGE_MUON()",
164 "SELECT CHARGE_MUON() / CHARGE_ELECTRON() AS charge_ratio",
165 ],
166 }
167 }
168
169 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
170 self.validate_args(args)?;
171 Ok(DataValue::Float(-1.602176634e-19)) }
173}
174
175pub struct ChargeTauFunction;
177
178impl SqlFunction for ChargeTauFunction {
179 fn signature(&self) -> FunctionSignature {
180 FunctionSignature {
181 name: "CHARGE_TAU",
182 category: FunctionCategory::Constant,
183 arg_count: ArgCount::Fixed(0),
184 description: "Returns the tau lepton charge in coulombs (-1.602176634 × 10^-19 C)",
185 returns: "FLOAT",
186 examples: vec![
187 "SELECT CHARGE_TAU()",
188 "SELECT CHARGE_TAU() = CHARGE_ELECTRON() AS same_charge",
189 ],
190 }
191 }
192
193 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
194 self.validate_args(args)?;
195 Ok(DataValue::Float(-1.602176634e-19)) }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn test_electron_charge() {
205 let func = ChargeElectronFunction;
206 let result = func.evaluate(&[]).unwrap();
207 match result {
208 DataValue::Float(val) => {
209 assert_eq!(val, -1.602176634e-19);
210 assert!(val < 0.0, "Electron charge should be negative");
211 }
212 _ => panic!("Expected Float"),
213 }
214 }
215
216 #[test]
217 fn test_proton_charge() {
218 let func = ChargeProtonFunction;
219 let result = func.evaluate(&[]).unwrap();
220 match result {
221 DataValue::Float(val) => {
222 assert_eq!(val, 1.602176634e-19);
223 assert!(val > 0.0, "Proton charge should be positive");
224 }
225 _ => panic!("Expected Float"),
226 }
227 }
228
229 #[test]
230 fn test_neutron_charge() {
231 let func = ChargeNeutronFunction;
232 let result = func.evaluate(&[]).unwrap();
233 match result {
234 DataValue::Float(val) => {
235 assert_eq!(val, 0.0);
236 assert_eq!(val, 0.0, "Neutron charge should be zero");
237 }
238 _ => panic!("Expected Float"),
239 }
240 }
241
242 #[test]
243 fn test_charge_conservation() {
244 let electron = ChargeElectronFunction.evaluate(&[]).unwrap();
245 let proton = ChargeProtonFunction.evaluate(&[]).unwrap();
246
247 if let (DataValue::Float(e), DataValue::Float(p)) = (electron, proton) {
248 assert_eq!(e + p, 0.0, "Electron and proton charges should cancel");
249 } else {
250 panic!("Expected Float values");
251 }
252 }
253
254 #[test]
255 fn test_quark_charges() {
256 let up = ChargeUpQuarkFunction.evaluate(&[]).unwrap();
257 let down = ChargeDownQuarkFunction.evaluate(&[]).unwrap();
258
259 if let (DataValue::Float(u), DataValue::Float(d)) = (up, down) {
260 let proton_charge = 2.0 * u + d;
262 assert!(
263 (proton_charge - 1.602176634e-19).abs() < 1e-30,
264 "Proton charge from quarks"
265 );
266
267 let neutron_charge = u + 2.0 * d;
269 assert!(neutron_charge.abs() < 1e-30, "Neutron charge from quarks");
270 } else {
271 panic!("Expected Float values");
272 }
273 }
274}