1use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[repr(transparent)]
20pub struct MethodId(pub u16);
21
22impl MethodId {
23 pub const DYNAMIC: MethodId = MethodId(0xFFFF);
26
27 #[inline]
29 pub const fn is_dynamic(self) -> bool {
30 self.0 == 0xFFFF
31 }
32
33 pub fn from_name(name: &str) -> MethodId {
36 match name {
37 "type" => Self::TYPE,
39 "to_string" | "toString" => Self::TO_STRING,
40
41 "map" => Self::MAP,
43 "filter" => Self::FILTER,
44 "reduce" => Self::REDUCE,
45 "forEach" => Self::FOR_EACH,
46 "find" => Self::FIND,
47 "findIndex" => Self::FIND_INDEX,
48 "some" => Self::SOME,
49 "every" => Self::EVERY,
50 "sort" => Self::SORT,
51 "groupBy" | "group_by" => Self::GROUP_BY,
52 "flatMap" => Self::FLAT_MAP,
53
54 "len" => Self::LEN,
56 "length" => Self::LENGTH,
57 "first" => Self::FIRST,
58 "last" => Self::LAST,
59 "reverse" => Self::REVERSE,
60 "slice" => Self::SLICE,
61 "concat" => Self::CONCAT,
62 "take" => Self::TAKE,
63 "drop" => Self::DROP,
64 "skip" => Self::SKIP,
65
66 "indexOf" => Self::INDEX_OF,
68 "includes" => Self::INCLUDES,
69
70 "join" => Self::JOIN,
72 "flatten" => Self::FLATTEN,
73 "unique" => Self::UNIQUE,
74 "distinct" => Self::DISTINCT,
75 "distinctBy" => Self::DISTINCT_BY,
76
77 "sum" => Self::SUM,
79 "avg" => Self::AVG,
80 "min" => Self::MIN,
81 "max" => Self::MAX,
82 "count" => Self::COUNT,
83
84 "where" => Self::WHERE,
86 "select" => Self::SELECT,
87 "orderBy" => Self::ORDER_BY,
88 "thenBy" => Self::THEN_BY,
89 "takeWhile" => Self::TAKE_WHILE,
90 "skipWhile" => Self::SKIP_WHILE,
91 "single" => Self::SINGLE,
92 "any" => Self::ANY,
93 "all" => Self::ALL,
94
95 "innerJoin" => Self::INNER_JOIN,
97 "leftJoin" => Self::LEFT_JOIN,
98 "crossJoin" => Self::CROSS_JOIN,
99
100 "union" => Self::UNION,
102 "intersect" => Self::INTERSECT,
103 "except" => Self::EXCEPT,
104
105 "origin" => Self::ORIGIN,
107 "columns" => Self::COLUMNS,
108 "column" => Self::COLUMN,
109 "head" => Self::HEAD,
110 "tail" => Self::TAIL,
111 "mean" => Self::MEAN,
112 "describe" => Self::DESCRIBE,
113 "aggregate" => Self::AGGREGATE,
114 "index_by" | "indexBy" => Self::INDEX_BY,
115 "limit" => Self::LIMIT,
116 "execute" => Self::EXECUTE,
117 "simulate" => Self::SIMULATE,
118 "correlation" => Self::CORRELATION,
119 "covariance" => Self::COVARIANCE,
120 "rolling_sum" | "rollingSum" => Self::ROLLING_SUM,
121 "rolling_mean" | "rollingMean" => Self::ROLLING_MEAN,
122 "rolling_std" | "rollingStd" => Self::ROLLING_STD,
123 "diff" => Self::DIFF,
124 "pct_change" | "pctChange" => Self::PCT_CHANGE,
125 "forward_fill" | "forwardFill" => Self::FORWARD_FILL,
126
127 "std" => Self::STD,
129 "toArray" => Self::TO_ARRAY,
130 "abs" => Self::ABS,
131
132 "between" => Self::BETWEEN,
134 "resample" => Self::RESAMPLE,
135
136 "toFixed" | "to_fixed" => Self::TO_FIXED,
138 "toInt" | "to_int" => Self::TO_INT,
139 "toNumber" | "to_number" => Self::TO_NUMBER,
140 "floor" => Self::FLOOR,
141 "ceil" => Self::CEIL,
142 "round" => Self::ROUND,
143
144 "toUpperCase" | "to_upper_case" => Self::TO_UPPER_CASE,
146 "toLowerCase" | "to_lower_case" => Self::TO_LOWER_CASE,
147 "trim" => Self::TRIM,
148 "contains" => Self::CONTAINS,
149 "startsWith" => Self::STARTS_WITH,
150 "endsWith" => Self::ENDS_WITH,
151 "split" => Self::SPLIT,
152 "replace" => Self::REPLACE,
153 "substring" => Self::SUBSTRING,
154
155 "unwrap" => Self::UNWRAP,
157 "unwrapOr" => Self::UNWRAP_OR,
158 "isSome" => Self::IS_SOME,
159 "isNone" => Self::IS_NONE,
160 "isOk" => Self::IS_OK,
161 "isErr" => Self::IS_ERR,
162 "mapErr" => Self::MAP_ERR,
163
164 "push" => Self::PUSH,
166 "pop" => Self::POP,
167 "isEmpty" => Self::IS_EMPTY,
168
169 _ => Self::DYNAMIC,
170 }
171 }
172
173 pub fn name(self) -> Option<&'static str> {
176 match self {
177 Self::TYPE => Some("type"),
178 Self::TO_STRING => Some("toString"),
179 Self::MAP => Some("map"),
180 Self::FILTER => Some("filter"),
181 Self::REDUCE => Some("reduce"),
182 Self::FOR_EACH => Some("forEach"),
183 Self::FIND => Some("find"),
184 Self::FIND_INDEX => Some("findIndex"),
185 Self::SOME => Some("some"),
186 Self::EVERY => Some("every"),
187 Self::SORT => Some("sort"),
188 Self::GROUP_BY => Some("groupBy"),
189 Self::FLAT_MAP => Some("flatMap"),
190 Self::LEN => Some("len"),
191 Self::LENGTH => Some("length"),
192 Self::FIRST => Some("first"),
193 Self::LAST => Some("last"),
194 Self::REVERSE => Some("reverse"),
195 Self::SLICE => Some("slice"),
196 Self::CONCAT => Some("concat"),
197 Self::TAKE => Some("take"),
198 Self::DROP => Some("drop"),
199 Self::SKIP => Some("skip"),
200 Self::INDEX_OF => Some("indexOf"),
201 Self::INCLUDES => Some("includes"),
202 Self::JOIN => Some("join"),
203 Self::FLATTEN => Some("flatten"),
204 Self::UNIQUE => Some("unique"),
205 Self::DISTINCT => Some("distinct"),
206 Self::DISTINCT_BY => Some("distinctBy"),
207 Self::SUM => Some("sum"),
208 Self::AVG => Some("avg"),
209 Self::MIN => Some("min"),
210 Self::MAX => Some("max"),
211 Self::COUNT => Some("count"),
212 Self::WHERE => Some("where"),
213 Self::SELECT => Some("select"),
214 Self::ORDER_BY => Some("orderBy"),
215 Self::THEN_BY => Some("thenBy"),
216 Self::TAKE_WHILE => Some("takeWhile"),
217 Self::SKIP_WHILE => Some("skipWhile"),
218 Self::SINGLE => Some("single"),
219 Self::ANY => Some("any"),
220 Self::ALL => Some("all"),
221 Self::INNER_JOIN => Some("innerJoin"),
222 Self::LEFT_JOIN => Some("leftJoin"),
223 Self::CROSS_JOIN => Some("crossJoin"),
224 Self::UNION => Some("union"),
225 Self::INTERSECT => Some("intersect"),
226 Self::EXCEPT => Some("except"),
227 Self::ORIGIN => Some("origin"),
228 Self::COLUMNS => Some("columns"),
229 Self::COLUMN => Some("column"),
230 Self::HEAD => Some("head"),
231 Self::TAIL => Some("tail"),
232 Self::MEAN => Some("mean"),
233 Self::DESCRIBE => Some("describe"),
234 Self::AGGREGATE => Some("aggregate"),
235 Self::INDEX_BY => Some("indexBy"),
236 Self::LIMIT => Some("limit"),
237 Self::EXECUTE => Some("execute"),
238 Self::SIMULATE => Some("simulate"),
239 Self::CORRELATION => Some("correlation"),
240 Self::COVARIANCE => Some("covariance"),
241 Self::ROLLING_SUM => Some("rollingSum"),
242 Self::ROLLING_MEAN => Some("rollingMean"),
243 Self::ROLLING_STD => Some("rollingStd"),
244 Self::DIFF => Some("diff"),
245 Self::PCT_CHANGE => Some("pctChange"),
246 Self::FORWARD_FILL => Some("forwardFill"),
247 Self::STD => Some("std"),
248 Self::TO_ARRAY => Some("toArray"),
249 Self::ABS => Some("abs"),
250 Self::BETWEEN => Some("between"),
251 Self::RESAMPLE => Some("resample"),
252 Self::TO_FIXED => Some("toFixed"),
253 Self::TO_INT => Some("toInt"),
254 Self::TO_NUMBER => Some("toNumber"),
255 Self::FLOOR => Some("floor"),
256 Self::CEIL => Some("ceil"),
257 Self::ROUND => Some("round"),
258 Self::TO_UPPER_CASE => Some("toUpperCase"),
259 Self::TO_LOWER_CASE => Some("toLowerCase"),
260 Self::TRIM => Some("trim"),
261 Self::CONTAINS => Some("contains"),
262 Self::STARTS_WITH => Some("startsWith"),
263 Self::ENDS_WITH => Some("endsWith"),
264 Self::SPLIT => Some("split"),
265 Self::REPLACE => Some("replace"),
266 Self::SUBSTRING => Some("substring"),
267 Self::UNWRAP => Some("unwrap"),
268 Self::UNWRAP_OR => Some("unwrapOr"),
269 Self::IS_SOME => Some("isSome"),
270 Self::IS_NONE => Some("isNone"),
271 Self::IS_OK => Some("isOk"),
272 Self::IS_ERR => Some("isErr"),
273 Self::MAP_ERR => Some("mapErr"),
274 Self::PUSH => Some("push"),
275 Self::POP => Some("pop"),
276 Self::IS_EMPTY => Some("isEmpty"),
277 _ => None,
278 }
279 }
280
281 pub const TYPE: MethodId = MethodId(0);
283 pub const TO_STRING: MethodId = MethodId(1);
284
285 pub const MAP: MethodId = MethodId(10);
287 pub const FILTER: MethodId = MethodId(11);
288 pub const REDUCE: MethodId = MethodId(12);
289 pub const FOR_EACH: MethodId = MethodId(13);
290 pub const FIND: MethodId = MethodId(14);
291 pub const FIND_INDEX: MethodId = MethodId(15);
292 pub const SOME: MethodId = MethodId(16);
293 pub const EVERY: MethodId = MethodId(17);
294 pub const SORT: MethodId = MethodId(18);
295 pub const GROUP_BY: MethodId = MethodId(19);
296 pub const FLAT_MAP: MethodId = MethodId(20);
297
298 pub const LEN: MethodId = MethodId(30);
300 pub const LENGTH: MethodId = MethodId(31);
301 pub const FIRST: MethodId = MethodId(32);
302 pub const LAST: MethodId = MethodId(33);
303 pub const REVERSE: MethodId = MethodId(34);
304 pub const SLICE: MethodId = MethodId(35);
305 pub const CONCAT: MethodId = MethodId(36);
306 pub const TAKE: MethodId = MethodId(37);
307 pub const DROP: MethodId = MethodId(38);
308 pub const SKIP: MethodId = MethodId(39);
309
310 pub const INDEX_OF: MethodId = MethodId(40);
312 pub const INCLUDES: MethodId = MethodId(41);
313
314 pub const JOIN: MethodId = MethodId(50);
316 pub const FLATTEN: MethodId = MethodId(51);
317 pub const UNIQUE: MethodId = MethodId(52);
318 pub const DISTINCT: MethodId = MethodId(53);
319 pub const DISTINCT_BY: MethodId = MethodId(54);
320
321 pub const SUM: MethodId = MethodId(60);
323 pub const AVG: MethodId = MethodId(61);
324 pub const MIN: MethodId = MethodId(62);
325 pub const MAX: MethodId = MethodId(63);
326 pub const COUNT: MethodId = MethodId(64);
327
328 pub const WHERE: MethodId = MethodId(70);
330 pub const SELECT: MethodId = MethodId(71);
331 pub const ORDER_BY: MethodId = MethodId(72);
332 pub const THEN_BY: MethodId = MethodId(73);
333 pub const TAKE_WHILE: MethodId = MethodId(74);
334 pub const SKIP_WHILE: MethodId = MethodId(75);
335 pub const SINGLE: MethodId = MethodId(76);
336 pub const ANY: MethodId = MethodId(77);
337 pub const ALL: MethodId = MethodId(78);
338
339 pub const INNER_JOIN: MethodId = MethodId(80);
341 pub const LEFT_JOIN: MethodId = MethodId(81);
342 pub const CROSS_JOIN: MethodId = MethodId(82);
343
344 pub const UNION: MethodId = MethodId(85);
346 pub const INTERSECT: MethodId = MethodId(86);
347 pub const EXCEPT: MethodId = MethodId(87);
348
349 pub const ORIGIN: MethodId = MethodId(100);
351 pub const COLUMNS: MethodId = MethodId(101);
352 pub const COLUMN: MethodId = MethodId(102);
353 pub const HEAD: MethodId = MethodId(103);
354 pub const TAIL: MethodId = MethodId(104);
355 pub const MEAN: MethodId = MethodId(105);
356 pub const DESCRIBE: MethodId = MethodId(106);
357 pub const AGGREGATE: MethodId = MethodId(107);
358 pub const INDEX_BY: MethodId = MethodId(108);
359 pub const LIMIT: MethodId = MethodId(109);
360 pub const EXECUTE: MethodId = MethodId(110);
361 pub const SIMULATE: MethodId = MethodId(111);
362 pub const CORRELATION: MethodId = MethodId(112);
363 pub const COVARIANCE: MethodId = MethodId(113);
364 pub const ROLLING_SUM: MethodId = MethodId(114);
365 pub const ROLLING_MEAN: MethodId = MethodId(115);
366 pub const ROLLING_STD: MethodId = MethodId(116);
367 pub const DIFF: MethodId = MethodId(117);
368 pub const PCT_CHANGE: MethodId = MethodId(118);
369 pub const FORWARD_FILL: MethodId = MethodId(119);
370
371 pub const STD: MethodId = MethodId(130);
373 pub const TO_ARRAY: MethodId = MethodId(131);
374 pub const ABS: MethodId = MethodId(132);
375
376 pub const BETWEEN: MethodId = MethodId(140);
378 pub const RESAMPLE: MethodId = MethodId(141);
379
380 pub const TO_FIXED: MethodId = MethodId(150);
382 pub const TO_INT: MethodId = MethodId(151);
383 pub const TO_NUMBER: MethodId = MethodId(152);
384 pub const FLOOR: MethodId = MethodId(153);
385 pub const CEIL: MethodId = MethodId(154);
386 pub const ROUND: MethodId = MethodId(155);
387
388 pub const TO_UPPER_CASE: MethodId = MethodId(160);
390 pub const TO_LOWER_CASE: MethodId = MethodId(161);
391 pub const TRIM: MethodId = MethodId(162);
392 pub const CONTAINS: MethodId = MethodId(163);
393 pub const STARTS_WITH: MethodId = MethodId(164);
394 pub const ENDS_WITH: MethodId = MethodId(165);
395 pub const SPLIT: MethodId = MethodId(166);
396 pub const REPLACE: MethodId = MethodId(167);
397 pub const SUBSTRING: MethodId = MethodId(168);
398
399 pub const UNWRAP: MethodId = MethodId(180);
401 pub const UNWRAP_OR: MethodId = MethodId(181);
402 pub const IS_SOME: MethodId = MethodId(182);
403 pub const IS_NONE: MethodId = MethodId(183);
404 pub const IS_OK: MethodId = MethodId(184);
405 pub const IS_ERR: MethodId = MethodId(185);
406 pub const MAP_ERR: MethodId = MethodId(186);
407
408 pub const PUSH: MethodId = MethodId(190);
410 pub const POP: MethodId = MethodId(191);
411 pub const IS_EMPTY: MethodId = MethodId(192);
412}
413
414impl std::fmt::Display for MethodId {
415 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
416 if let Some(name) = self.name() {
417 write!(f, "{}(#{})", name, self.0)
418 } else if self.is_dynamic() {
419 write!(f, "<dynamic>")
420 } else {
421 write!(f, "<unknown #{}>", self.0)
422 }
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429
430 #[test]
431 fn test_known_methods_roundtrip() {
432 let methods = [
433 "map",
434 "filter",
435 "reduce",
436 "len",
437 "sum",
438 "avg",
439 "min",
440 "max",
441 "sort",
442 "first",
443 "last",
444 "push",
445 "pop",
446 "join",
447 "split",
448 "trim",
449 "replace",
450 "contains",
451 "toUpperCase",
452 "toLowerCase",
453 "type",
454 "toString",
455 "toFixed",
456 "floor",
457 "ceil",
458 "round",
459 "abs",
460 ];
461 for name in methods {
462 let id = MethodId::from_name(name);
463 assert!(!id.is_dynamic(), "expected known ID for '{}'", name);
464 assert!(id.name().is_some(), "expected name for '{}'", name);
465 }
466 }
467
468 #[test]
469 fn test_unknown_method_is_dynamic() {
470 let id = MethodId::from_name("nonexistent_method");
471 assert!(id.is_dynamic());
472 assert_eq!(id, MethodId::DYNAMIC);
473 assert!(id.name().is_none());
474 }
475
476 #[test]
477 fn test_aliases_resolve_to_same_id() {
478 assert_eq!(
479 MethodId::from_name("to_string"),
480 MethodId::from_name("toString")
481 );
482 assert_eq!(
483 MethodId::from_name("group_by"),
484 MethodId::from_name("groupBy")
485 );
486 assert_eq!(
487 MethodId::from_name("index_by"),
488 MethodId::from_name("indexBy")
489 );
490 assert_eq!(
491 MethodId::from_name("rollingSum"),
492 MethodId::from_name("rolling_sum")
493 );
494 assert_eq!(
495 MethodId::from_name("pctChange"),
496 MethodId::from_name("pct_change")
497 );
498 assert_eq!(
499 MethodId::from_name("forwardFill"),
500 MethodId::from_name("forward_fill")
501 );
502 assert_eq!(
503 MethodId::from_name("toFixed"),
504 MethodId::from_name("to_fixed")
505 );
506 assert_eq!(
507 MethodId::from_name("toUpperCase"),
508 MethodId::from_name("to_upper_case")
509 );
510 }
511
512 #[test]
513 fn test_display() {
514 assert_eq!(format!("{}", MethodId::MAP), "map(#10)");
515 assert_eq!(format!("{}", MethodId::DYNAMIC), "<dynamic>");
516 assert_eq!(format!("{}", MethodId(9999)), "<unknown #9999>");
517 }
518}