1use std::collections::BTreeMap;
2use std::collections::btree_map::Entry;
3use std::fmt;
4
5use pext::simple_extension_declaration::MappingType;
6use substrait::proto::extensions as pext;
7use thiserror::Error;
8
9pub const EXTENSIONS_HEADER: &str = "=== Extensions";
10pub const EXTENSION_URNS_HEADER: &str = "URNs:";
11pub const EXTENSION_FUNCTIONS_HEADER: &str = "Functions:";
12pub const EXTENSION_TYPES_HEADER: &str = "Types:";
13pub const EXTENSION_TYPE_VARIATIONS_HEADER: &str = "Type Variations:";
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
16pub enum ExtensionKind {
17 Function,
19 Type,
20 TypeVariation,
21}
22
23impl ExtensionKind {
24 pub fn name(&self) -> &'static str {
25 match self {
26 ExtensionKind::Function => "function",
28 ExtensionKind::Type => "type",
29 ExtensionKind::TypeVariation => "type_variation",
30 }
31 }
32}
33
34impl fmt::Display for ExtensionKind {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 ExtensionKind::Function => write!(f, "Function"),
39 ExtensionKind::Type => write!(f, "Type"),
40 ExtensionKind::TypeVariation => write!(f, "Type Variation"),
41 }
42 }
43}
44
45#[derive(Error, Debug, PartialEq, Clone)]
46pub enum InsertError {
47 #[error("Extension declaration missing mapping type")]
48 MissingMappingType,
49
50 #[error("Duplicate URN anchor {anchor} for {prev} and {name}")]
51 DuplicateUrnAnchor {
52 anchor: u32,
53 prev: String,
54 name: String,
55 },
56
57 #[error("Duplicate extension {kind} anchor {anchor} for {prev} and {name}")]
58 DuplicateAnchor {
59 kind: ExtensionKind,
60 anchor: u32,
61 prev: String,
62 name: String,
63 },
64
65 #[error("Missing URN anchor {urn} for extension {kind} anchor {anchor} name {name}")]
66 MissingUrn {
67 kind: ExtensionKind,
68 anchor: u32,
69 name: String,
70 urn: u32,
71 },
72
73 #[error(
74 "Duplicate extension {kind} anchor {anchor} for {prev} and {name}, also missing URN {urn}"
75 )]
76 DuplicateAndMissingUrn {
77 kind: ExtensionKind,
78 anchor: u32,
79 prev: String,
80 name: String,
81 urn: u32,
82 },
83
84 #[error("Invalid {kind} name '{name}': u! prefix is only valid for type names")]
85 InvalidName { kind: ExtensionKind, name: String },
86}
87
88#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct CompoundName {
96 name: String,
98 index: usize,
100}
101
102impl CompoundName {
103 pub fn new(name: impl Into<String>) -> Self {
104 let name = name.into();
105 let index = name.find(':').unwrap_or(name.len());
106 Self { name, index }
107 }
108
109 pub fn base(&self) -> &str {
111 &self.name[..self.index]
112 }
113
114 pub fn full(&self) -> &str {
116 &self.name
117 }
118
119 pub fn has_signature(&self) -> bool {
121 self.index < self.name.len()
122 }
123
124 pub fn matches(&self, pattern: &str) -> bool {
129 if pattern.contains(':') {
130 self.full() == pattern
131 } else {
132 self.base() == pattern
133 }
134 }
135}
136
137impl fmt::Display for CompoundName {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 f.write_str(&self.name)
140 }
141}
142
143#[derive(Default, Debug, Clone, PartialEq)]
146pub struct SimpleExtensions {
147 urns: BTreeMap<u32, String>,
149 extensions: BTreeMap<(u32, ExtensionKind), (u32, CompoundName)>,
151}
152
153impl SimpleExtensions {
154 pub fn new() -> Self {
155 Self::default()
156 }
157
158 pub fn from_extensions<'a>(
159 urns: impl IntoIterator<Item = &'a pext::SimpleExtensionUrn>,
160 extensions: impl IntoIterator<Item = &'a pext::SimpleExtensionDeclaration>,
161 ) -> (Self, Vec<InsertError>) {
162 let mut exts = Self::new();
166
167 let mut errors = Vec::<InsertError>::new();
168
169 for urn in urns {
170 if let Err(e) = exts.add_extension_urn(urn.urn.clone(), urn.extension_urn_anchor) {
171 errors.push(e);
172 }
173 }
174
175 for extension in extensions {
176 match &extension.mapping_type {
177 Some(MappingType::ExtensionType(t)) => {
178 if let Err(e) = exts.add_extension(
179 ExtensionKind::Type,
180 t.extension_urn_reference,
181 t.type_anchor,
182 t.name.clone(),
183 ) {
184 errors.push(e);
185 }
186 }
187 Some(MappingType::ExtensionFunction(f)) => {
188 if let Err(e) = exts.add_extension(
189 ExtensionKind::Function,
190 f.extension_urn_reference,
191 f.function_anchor,
192 f.name.clone(),
193 ) {
194 errors.push(e);
195 }
196 }
197 Some(MappingType::ExtensionTypeVariation(v)) => {
198 if let Err(e) = exts.add_extension(
199 ExtensionKind::TypeVariation,
200 v.extension_urn_reference,
201 v.type_variation_anchor,
202 v.name.clone(),
203 ) {
204 errors.push(e);
205 }
206 }
207 None => {
208 errors.push(InsertError::MissingMappingType);
209 }
210 }
211 }
212
213 (exts, errors)
214 }
215
216 pub fn add_extension_urn(&mut self, urn: String, anchor: u32) -> Result<(), InsertError> {
217 match self.urns.entry(anchor) {
218 Entry::Occupied(e) => {
219 return Err(InsertError::DuplicateUrnAnchor {
220 anchor,
221 prev: e.get().clone(),
222 name: urn,
223 });
224 }
225 Entry::Vacant(e) => {
226 e.insert(urn);
227 }
228 }
229 Ok(())
230 }
231
232 pub fn add_extension(
233 &mut self,
234 kind: ExtensionKind,
235 urn: u32,
236 anchor: u32,
237 name: String,
238 ) -> Result<(), InsertError> {
239 let name = if kind == ExtensionKind::Type {
243 name.strip_prefix("u!").map(str::to_string).unwrap_or(name)
244 } else if name.starts_with("u!") {
245 return Err(InsertError::InvalidName { kind, name });
246 } else {
247 name
248 };
249 let missing_urn = !self.urns.contains_key(&urn);
250
251 let prev = match self.extensions.entry((anchor, kind)) {
252 Entry::Occupied(e) => Some(e.get().1.full().to_string()),
253 Entry::Vacant(v) => {
254 v.insert((urn, CompoundName::new(name.clone())));
255 None
256 }
257 };
258
259 match (missing_urn, prev) {
260 (true, Some(prev)) => Err(InsertError::DuplicateAndMissingUrn {
261 kind,
262 anchor,
263 prev,
264 name,
265 urn,
266 }),
267 (false, Some(prev)) => Err(InsertError::DuplicateAnchor {
268 kind,
269 anchor,
270 prev,
271 name,
272 }),
273 (true, None) => Err(InsertError::MissingUrn {
274 kind,
275 anchor,
276 name,
277 urn,
278 }),
279 (false, None) => Ok(()),
280 }
281 }
282
283 pub fn is_empty(&self) -> bool {
284 self.urns.is_empty() && self.extensions.is_empty()
285 }
286
287 pub fn to_extension_urns(&self) -> Vec<pext::SimpleExtensionUrn> {
289 self.urns
290 .iter()
291 .map(|(anchor, urn)| pext::SimpleExtensionUrn {
292 extension_urn_anchor: *anchor,
293 urn: urn.clone(),
294 })
295 .collect()
296 }
297
298 pub fn to_extension_declarations(&self) -> Vec<pext::SimpleExtensionDeclaration> {
300 self.extensions
301 .iter()
302 .map(|((anchor, kind), (urn_ref, name))| {
303 let mapping_type = match kind {
304 ExtensionKind::Function => MappingType::ExtensionFunction(
305 pext::simple_extension_declaration::ExtensionFunction {
306 extension_urn_reference: *urn_ref,
307 function_anchor: *anchor,
308 name: name.full().to_string(),
309 },
310 ),
311 ExtensionKind::Type => MappingType::ExtensionType(
312 pext::simple_extension_declaration::ExtensionType {
313 extension_urn_reference: *urn_ref,
314 type_anchor: *anchor,
315 name: name.full().to_string(),
316 },
317 ),
318 ExtensionKind::TypeVariation => MappingType::ExtensionTypeVariation(
319 pext::simple_extension_declaration::ExtensionTypeVariation {
320 extension_urn_reference: *urn_ref,
321 type_variation_anchor: *anchor,
322 name: name.full().to_string(),
323 },
324 ),
325 };
326 pext::SimpleExtensionDeclaration {
327 mapping_type: Some(mapping_type),
328 }
329 })
330 .collect()
331 }
332
333 pub fn write<W: fmt::Write>(&self, w: &mut W, indent: &str) -> fmt::Result {
337 if self.is_empty() {
338 return Ok(());
340 }
341
342 writeln!(w, "{EXTENSIONS_HEADER}")?;
343 if !self.urns.is_empty() {
344 writeln!(w, "{EXTENSION_URNS_HEADER}")?;
345 for (anchor, urn) in &self.urns {
346 writeln!(w, "{indent}@{anchor:3}: {urn}")?;
347 }
348 }
349
350 let kinds_and_headers = [
351 (ExtensionKind::Function, EXTENSION_FUNCTIONS_HEADER),
352 (ExtensionKind::Type, EXTENSION_TYPES_HEADER),
353 (
354 ExtensionKind::TypeVariation,
355 EXTENSION_TYPE_VARIATIONS_HEADER,
356 ),
357 ];
358 for (kind, header) in kinds_and_headers {
359 let mut filtered = self
360 .extensions
361 .iter()
362 .filter(|((_a, k), _)| *k == kind)
363 .peekable();
364 if filtered.peek().is_none() {
365 continue;
366 }
367
368 writeln!(w, "{header}")?;
369 for ((anchor, _), (urn_ref, name)) in filtered {
370 writeln!(w, "{indent}#{anchor:3} @{urn_ref:3}: {name}")?;
371 }
372 }
373 Ok(())
374 }
375
376 pub fn to_string(&self, indent: &str) -> String {
377 let mut output = String::new();
378 self.write(&mut output, indent).unwrap();
379 output
380 }
381}
382
383#[derive(Error, Debug, Clone, PartialEq)]
384pub enum MissingReference {
385 #[error("Missing URN for {0}")]
386 MissingUrn(u32),
387 #[error("Missing anchor for {0}: {1}")]
388 MissingAnchor(ExtensionKind, u32),
389 #[error("Missing name for {0}: {1}")]
390 MissingName(ExtensionKind, String),
391 #[error("Mismatched {0}: {1}#{2}")]
392 Mismatched(ExtensionKind, String, u32),
394 #[error("Duplicate name without anchor for {0}: {1}")]
395 DuplicateName(ExtensionKind, String),
396}
397
398#[derive(Debug, Clone, PartialEq)]
399pub struct SimpleExtension {
400 pub kind: ExtensionKind,
401 pub name: String,
402 pub anchor: u32,
403 pub urn: u32,
404}
405
406pub struct ResolvedFunction<'a> {
408 pub anchor: u32,
409 pub urn: u32,
410 pub name: &'a CompoundName,
412 pub base_name_unique: bool,
415 pub name_unique: bool,
418}
419
420impl SimpleExtensions {
421 pub fn find_urn(&self, anchor: u32) -> Result<&str, MissingReference> {
422 self.urns
423 .get(&anchor)
424 .map(String::as_str)
425 .ok_or(MissingReference::MissingUrn(anchor))
426 }
427
428 pub fn find_by_anchor(
429 &self,
430 kind: ExtensionKind,
431 anchor: u32,
432 ) -> Result<(u32, &CompoundName), MissingReference> {
433 let &(urn, ref name) = self
434 .extensions
435 .get(&(anchor, kind))
436 .ok_or(MissingReference::MissingAnchor(kind, anchor))?;
437
438 Ok((urn, name))
439 }
440
441 pub fn find_by_name(&self, kind: ExtensionKind, name: &str) -> Result<u32, MissingReference> {
442 let mut matches = self
443 .extensions
444 .iter()
445 .filter(move |((_a, k), (_, n))| *k == kind && n.full() == name)
446 .map(|((anchor, _), _)| *anchor);
447
448 let anchor = matches
449 .next()
450 .ok_or(MissingReference::MissingName(kind, name.to_string()))?;
451
452 match matches.next() {
453 Some(_) => Err(MissingReference::DuplicateName(kind, name.to_string())),
454 None => Ok(anchor),
455 }
456 }
457
458 pub fn is_name_unique(
463 &self,
464 kind: ExtensionKind,
465 anchor: u32,
466 name: &str,
467 ) -> Result<bool, MissingReference> {
468 let mut found = false;
469 let mut other = false;
470 for (&(a, k), (_, n)) in self.extensions.iter() {
471 if k != kind {
472 continue;
473 }
474
475 if a == anchor {
476 found = true;
477 if n.full() != name {
478 return Err(MissingReference::Mismatched(kind, name.to_string(), anchor));
479 }
480 continue;
481 }
482
483 if n.full() != name {
484 continue;
486 }
487
488 other = true;
490 if found {
491 break;
492 }
493 }
494
495 match (found, other) {
496 (true, false) => Ok(true),
498 (true, true) => Ok(false),
500 (false, _) => Err(MissingReference::MissingAnchor(kind, anchor)),
502 }
503 }
504
505 pub fn lookup_function(&self, anchor: u32) -> Result<ResolvedFunction<'_>, MissingReference> {
509 let (urn, name) = self.find_by_anchor(ExtensionKind::Function, anchor)?;
510 let name_unique = self.is_name_unique(ExtensionKind::Function, anchor, name.full())?;
511 let base_name_unique = self.is_base_name_unique(ExtensionKind::Function, anchor)?;
512 Ok(ResolvedFunction {
513 anchor,
514 urn,
515 name,
516 name_unique,
517 base_name_unique,
518 })
519 }
520
521 pub fn resolve_function(
530 &self,
531 name: &str,
532 anchor: Option<u32>,
533 ) -> Result<ResolvedFunction<'_>, MissingReference> {
534 let resolved_anchor = match anchor {
535 Some(a) => {
536 let (_, stored) = self.find_by_anchor(ExtensionKind::Function, a)?;
537 if stored.matches(name) {
538 a
539 } else {
540 return Err(MissingReference::Mismatched(
541 ExtensionKind::Function,
542 name.to_string(),
543 a,
544 ));
545 }
546 }
547 None => {
548 if name.contains(':') {
549 self.find_by_name(ExtensionKind::Function, name)?
550 } else {
551 self.find_by_base_name(ExtensionKind::Function, name)?
552 }
553 }
554 };
555 self.lookup_function(resolved_anchor)
556 }
557
558 fn is_base_name_unique(
559 &self,
560 kind: ExtensionKind,
561 anchor: u32,
562 ) -> Result<bool, MissingReference> {
563 let (_, name) = self.find_by_anchor(kind, anchor)?;
564 let my_base = name.base();
565
566 let other_exists = self
567 .extensions
568 .iter()
569 .any(|(&(a, k), (_, n))| k == kind && a != anchor && n.base() == my_base);
570
571 Ok(!other_exists)
572 }
573
574 fn find_by_base_name(&self, kind: ExtensionKind, base: &str) -> Result<u32, MissingReference> {
575 let mut matches = self
576 .extensions
577 .iter()
578 .filter(|&(&(_a, k), (_, n))| k == kind && n.matches(base))
579 .map(|(&(anchor, _), _)| anchor);
580
581 let anchor = matches
582 .next()
583 .ok_or_else(|| MissingReference::MissingName(kind, base.to_string()))?;
584
585 match matches.next() {
586 Some(_) => Err(MissingReference::DuplicateName(kind, base.to_string())),
587 None => Ok(anchor),
588 }
589 }
590}
591
592#[cfg(test)]
593mod tests {
594 use pext::simple_extension_declaration::{
595 ExtensionFunction, ExtensionType, ExtensionTypeVariation, MappingType,
596 };
597 use substrait::proto::extensions as pext;
598
599 use super::*;
600
601 fn new_urn(anchor: u32, urn_str: &str) -> pext::SimpleExtensionUrn {
602 pext::SimpleExtensionUrn {
603 extension_urn_anchor: anchor,
604 urn: urn_str.to_string(),
605 }
606 }
607
608 fn new_ext_fn(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
609 pext::SimpleExtensionDeclaration {
610 mapping_type: Some(MappingType::ExtensionFunction(ExtensionFunction {
611 extension_urn_reference: urn_ref,
612 function_anchor: anchor,
613 name: name.to_string(),
614 })),
615 }
616 }
617
618 fn new_ext_type(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
619 pext::SimpleExtensionDeclaration {
620 mapping_type: Some(MappingType::ExtensionType(ExtensionType {
621 extension_urn_reference: urn_ref,
622 type_anchor: anchor,
623 name: name.to_string(),
624 })),
625 }
626 }
627
628 fn new_type_var(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
629 pext::SimpleExtensionDeclaration {
630 mapping_type: Some(MappingType::ExtensionTypeVariation(
631 ExtensionTypeVariation {
632 extension_urn_reference: urn_ref,
633 type_variation_anchor: anchor,
634 name: name.to_string(),
635 },
636 )),
637 }
638 }
639
640 fn assert_no_errors(errs: &[InsertError]) {
641 for err in errs {
642 println!("Error: {err:?}");
643 }
644 assert!(errs.is_empty());
645 }
646
647 fn unwrap_new_extensions<'a>(
648 urns: impl IntoIterator<Item = &'a pext::SimpleExtensionUrn>,
649 extensions: impl IntoIterator<Item = &'a pext::SimpleExtensionDeclaration>,
650 ) -> SimpleExtensions {
651 let (exts, errs) = SimpleExtensions::from_extensions(urns, extensions);
652 assert_no_errors(&errs);
653 exts
654 }
655
656 #[test]
657 fn test_extension_lookup_empty() {
658 let lookup = SimpleExtensions::new();
659 assert!(lookup.find_urn(1).is_err());
660 assert!(lookup.find_by_anchor(ExtensionKind::Function, 1).is_err());
661 assert!(lookup.find_by_anchor(ExtensionKind::Type, 1).is_err());
662 assert!(
663 lookup
664 .find_by_anchor(ExtensionKind::TypeVariation, 1)
665 .is_err()
666 );
667 assert!(lookup.find_by_name(ExtensionKind::Function, "any").is_err());
668 assert!(lookup.find_by_name(ExtensionKind::Type, "any").is_err());
669 assert!(
670 lookup
671 .find_by_name(ExtensionKind::TypeVariation, "any")
672 .is_err()
673 );
674 }
675
676 #[test]
677 fn test_from_extensions_basic() {
678 let urns = vec![new_urn(1, "urn1"), new_urn(2, "urn2")];
679 let extensions = vec![
680 new_ext_fn(10, 1, "func1"),
681 new_ext_type(20, 1, "type1"),
682 new_type_var(30, 2, "var1"),
683 ];
684 let exts = unwrap_new_extensions(&urns, &extensions);
685
686 assert_eq!(exts.find_urn(1).unwrap(), "urn1");
687 assert_eq!(exts.find_urn(2).unwrap(), "urn2");
688 assert!(exts.find_urn(3).is_err());
689
690 let (urn, name) = exts.find_by_anchor(ExtensionKind::Function, 10).unwrap();
691 assert_eq!(name.full(), "func1");
692 assert_eq!(urn, 1);
693 assert!(exts.find_by_anchor(ExtensionKind::Function, 11).is_err());
694
695 let (urn, name) = exts.find_by_anchor(ExtensionKind::Type, 20).unwrap();
696 assert_eq!(name.full(), "type1");
697 assert_eq!(urn, 1);
698 assert!(exts.find_by_anchor(ExtensionKind::Type, 21).is_err());
699
700 let (urn, name) = exts
701 .find_by_anchor(ExtensionKind::TypeVariation, 30)
702 .unwrap();
703 assert_eq!(name.full(), "var1");
704 assert_eq!(urn, 2);
705 assert!(
706 exts.find_by_anchor(ExtensionKind::TypeVariation, 31)
707 .is_err()
708 );
709 }
710
711 #[test]
712 fn test_from_extensions_duplicates() {
713 let urns = vec![
714 new_urn(1, "urn_old"),
715 new_urn(1, "urn_new"),
716 new_urn(2, "second"),
717 ];
718 let extensions = vec![
719 new_ext_fn(10, 1, "func_old"),
720 new_ext_fn(10, 2, "func_new"), new_ext_fn(11, 3, "func_missing"),
722 ];
723 let (exts, errs) = SimpleExtensions::from_extensions(&urns, &extensions);
724 assert_eq!(
725 errs,
726 vec![
727 InsertError::DuplicateUrnAnchor {
728 anchor: 1,
729 name: "urn_new".to_string(),
730 prev: "urn_old".to_string()
731 },
732 InsertError::DuplicateAnchor {
733 kind: ExtensionKind::Function,
734 anchor: 10,
735 prev: "func_old".to_string(),
736 name: "func_new".to_string()
737 },
738 InsertError::MissingUrn {
739 kind: ExtensionKind::Function,
740 anchor: 11,
741 name: "func_missing".to_string(),
742 urn: 3,
743 },
744 ]
745 );
746
747 assert_eq!(exts.find_urn(1).unwrap(), "urn_old");
749 let (urn, name) = exts.find_by_anchor(ExtensionKind::Function, 10).unwrap();
750 assert_eq!(urn, 1);
751 assert_eq!(name.full(), "func_old");
752 }
753
754 #[test]
755 fn test_from_extensions_invalid_mapping_type() {
756 let extensions = vec![pext::SimpleExtensionDeclaration { mapping_type: None }];
757
758 let (_exts, errs) = SimpleExtensions::from_extensions(vec![], &extensions);
759 assert_eq!(errs.len(), 1);
760 let err = &errs[0];
761 assert_eq!(err, &InsertError::MissingMappingType);
762 }
763
764 #[test]
765 fn test_find_by_name() {
766 let urns = vec![new_urn(1, "urn1")];
767 let extensions = vec![
768 new_ext_fn(10, 1, "name1"),
769 new_ext_fn(11, 1, "name2"),
770 new_ext_fn(12, 1, "name1"), new_ext_type(20, 1, "type_name1"),
772 new_type_var(30, 1, "var_name1"),
773 ];
774 let exts = unwrap_new_extensions(&urns, &extensions);
775
776 let err = exts
777 .find_by_name(ExtensionKind::Function, "name1")
778 .unwrap_err();
779 assert_eq!(
780 err,
781 MissingReference::DuplicateName(ExtensionKind::Function, "name1".to_string())
782 );
783
784 let found = exts.find_by_name(ExtensionKind::Function, "name2").unwrap();
785 assert_eq!(found, 11);
786
787 let found = exts
788 .find_by_name(ExtensionKind::Type, "type_name1")
789 .unwrap();
790 assert_eq!(found, 20);
791
792 let err = exts
793 .find_by_name(ExtensionKind::Type, "non_existent_type_name")
794 .unwrap_err();
795 assert_eq!(
796 err,
797 MissingReference::MissingName(
798 ExtensionKind::Type,
799 "non_existent_type_name".to_string()
800 )
801 );
802
803 let found = exts
804 .find_by_name(ExtensionKind::TypeVariation, "var_name1")
805 .unwrap();
806 assert_eq!(found, 30);
807
808 let err = exts
809 .find_by_name(ExtensionKind::TypeVariation, "non_existent_var_name")
810 .unwrap_err();
811 assert_eq!(
812 err,
813 MissingReference::MissingName(
814 ExtensionKind::TypeVariation,
815 "non_existent_var_name".to_string()
816 )
817 );
818 }
819
820 #[test]
821 fn test_display_extension_lookup_empty() {
822 let lookup = SimpleExtensions::new();
823 let mut output = String::new();
824 lookup.write(&mut output, " ").unwrap();
825 let expected = r"";
826 assert_eq!(output, expected.trim_start());
827 }
828
829 #[test]
830 fn test_display_extension_lookup_with_content() {
831 let urns = vec![
832 new_urn(1, "/my/urn1"),
833 new_urn(42, "/another/urn"),
834 new_urn(4091, "/big/anchor"),
835 ];
836 let extensions = vec![
837 new_ext_fn(10, 1, "my_func"),
838 new_ext_type(20, 1, "my_type"),
839 new_type_var(30, 42, "my_var"),
840 new_ext_fn(11, 42, "another_func"),
841 new_ext_fn(108812, 4091, "big_func"),
842 ];
843 let exts = unwrap_new_extensions(&urns, &extensions);
844 let display_str = exts.to_string(" ");
845
846 let expected = r"
847=== Extensions
848URNs:
849 @ 1: /my/urn1
850 @ 42: /another/urn
851 @4091: /big/anchor
852Functions:
853 # 10 @ 1: my_func
854 # 11 @ 42: another_func
855 #108812 @4091: big_func
856Types:
857 # 20 @ 1: my_type
858Type Variations:
859 # 30 @ 42: my_var
860";
861 assert_eq!(display_str, expected.trim_start());
862 }
863
864 #[test]
865 fn test_extensions_output() {
866 let mut extensions = SimpleExtensions::new();
868 extensions
869 .add_extension_urn("/urn/common".to_string(), 1)
870 .unwrap();
871 extensions
872 .add_extension_urn("/urn/specific_funcs".to_string(), 2)
873 .unwrap();
874 extensions
875 .add_extension(ExtensionKind::Function, 1, 10, "func_a".to_string())
876 .unwrap();
877 extensions
878 .add_extension(ExtensionKind::Function, 2, 11, "func_b_special".to_string())
879 .unwrap();
880 extensions
881 .add_extension(ExtensionKind::Type, 1, 20, "SomeType".to_string())
882 .unwrap();
883 extensions
884 .add_extension(ExtensionKind::TypeVariation, 2, 30, "VarX".to_string())
885 .unwrap();
886
887 let output = extensions.to_string(" ");
889
890 let expected_output = r#"
892=== Extensions
893URNs:
894 @ 1: /urn/common
895 @ 2: /urn/specific_funcs
896Functions:
897 # 10 @ 1: func_a
898 # 11 @ 2: func_b_special
899Types:
900 # 20 @ 1: SomeType
901Type Variations:
902 # 30 @ 2: VarX
903"#;
904
905 assert_eq!(output, expected_output.trim_start());
906 }
907
908 #[test]
909 fn test_compound_name_full_zero_arg_type_signature() {
910 let n = CompoundName::new("add:");
912 assert_eq!(n.full(), "add:");
913 assert_eq!(n.base(), "add");
914 assert!(n.matches("add:"));
916 assert!(!n.matches("add:i64_i64"));
917 assert!(n.matches("add"));
919 }
920
921 #[test]
922 fn test_compound_name_with_signature() {
923 let n = CompoundName::new("equal:any_any");
924 assert_eq!(n.full(), "equal:any_any");
925 assert_eq!(n.base(), "equal");
926
927 let n2 = CompoundName::new("regexp_match_substring:str_str_i64");
928 assert_eq!(n2.base(), "regexp_match_substring");
929 assert_eq!(n2.full(), "regexp_match_substring:str_str_i64");
930
931 let n3 = CompoundName::new("add:i64_i64");
932 assert_eq!(n3.base(), "add");
933 }
934
935 fn make_overloaded_extensions() -> SimpleExtensions {
938 let urns = vec![new_urn(1, "urn:comparison")];
939 let extensions = vec![
940 new_ext_fn(1, 1, "equal:any_any"),
941 new_ext_fn(2, 1, "equal:str_str"),
942 new_ext_fn(3, 1, "add:i64_i64"),
943 ];
944 unwrap_new_extensions(&urns, &extensions)
945 }
946
947 #[test]
948 fn test_lookup_function_uniqueness_flags() {
949 let exts = make_overloaded_extensions();
953
954 let r1 = exts.lookup_function(1).unwrap();
955 assert_eq!(r1.name.full(), "equal:any_any");
956 assert!(!r1.base_name_unique, "two 'equal' overloads");
957 assert!(r1.name_unique, "compound name 'equal:any_any' is unique");
958
959 let r2 = exts.lookup_function(2).unwrap();
960 assert_eq!(r2.name.full(), "equal:str_str");
961 assert!(!r2.base_name_unique);
962 assert!(r2.name_unique);
963
964 let r3 = exts.lookup_function(3).unwrap();
965 assert_eq!(r3.name.full(), "add:i64_i64");
966 assert!(r3.base_name_unique, "only one 'add' overload");
967 assert!(r3.name_unique, "compound name appears only once");
968 }
969
970 #[test]
971 fn test_lookup_function_missing_anchor() {
972 let exts = SimpleExtensions::new();
973 assert!(exts.lookup_function(99).is_err());
974 }
975
976 #[test]
977 fn test_lookup_function_plain_name_overloaded_across_urns() {
978 let urns = vec![new_urn(1, "urn1"), new_urn(2, "urn2")];
980 let extensions = vec![
981 new_ext_fn(1, 1, "duplicated"),
982 new_ext_fn(2, 2, "duplicated"),
983 ];
984 let exts = unwrap_new_extensions(&urns, &extensions);
985
986 let r = exts.lookup_function(1).unwrap();
987 assert!(!r.base_name_unique);
988 assert!(!r.name_unique);
989 }
990
991 #[test]
992 fn test_lookup_function_different_base_names_each_unique() {
993 let urns = vec![new_urn(1, "urn1")];
995 let extensions = vec![
996 new_ext_fn(1, 1, "equal:any_any"),
997 new_ext_fn(2, 1, "like:str_str"),
998 ];
999 let exts = unwrap_new_extensions(&urns, &extensions);
1000
1001 assert!(exts.lookup_function(1).unwrap().base_name_unique);
1002 assert!(exts.lookup_function(2).unwrap().base_name_unique);
1003 }
1004
1005 fn make_resolve_extensions() -> SimpleExtensions {
1008 let urns = vec![new_urn(1, "test_urn")];
1009 let extensions = vec![
1010 new_ext_fn(1, 1, "equal:any_any"),
1011 new_ext_fn(2, 1, "equal:str_str"),
1012 new_ext_fn(3, 1, "add:i64_i64"),
1013 new_ext_fn(4, 1, "add:"),
1014 ];
1015 unwrap_new_extensions(&urns, &extensions)
1016 }
1017
1018 #[test]
1019 fn test_resolve_function_with_anchor() {
1020 let exts = make_resolve_extensions();
1022
1023 assert_eq!(
1025 exts.resolve_function("equal:any_any", Some(1))
1026 .unwrap()
1027 .anchor,
1028 1
1029 );
1030
1031 assert_eq!(exts.resolve_function("add", Some(3)).unwrap().anchor, 3);
1033 assert_eq!(exts.resolve_function("add", Some(4)).unwrap().anchor, 4);
1034
1035 assert!(exts.resolve_function("add:", Some(3)).is_err());
1037
1038 assert!(exts.resolve_function("add", Some(1)).is_err());
1040
1041 assert!(exts.resolve_function("equal:any_any", Some(2)).is_err());
1043 }
1044
1045 #[test]
1046 fn test_resolve_function_without_anchor() {
1047 let exts = make_resolve_extensions();
1049
1050 assert_eq!(
1051 exts.resolve_function("equal:any_any", None).unwrap().anchor,
1052 1
1053 );
1054 assert_eq!(
1055 exts.resolve_function("equal:str_str", None).unwrap().anchor,
1056 2
1057 );
1058 }
1059
1060 #[test]
1061 fn test_resolve_function_without_anchor_full_sig() {
1062 let exts = make_resolve_extensions();
1064
1065 assert_eq!(exts.resolve_function("add:", None).unwrap().anchor, 4);
1066 assert_eq!(
1067 exts.resolve_function("add:i64_i64", None).unwrap().anchor,
1068 3
1069 );
1070
1071 assert!(exts.resolve_function("equal:", None).is_err());
1073 }
1074
1075 #[test]
1076 fn test_resolve_function_without_anchor_no_sig() {
1077 let exts = make_resolve_extensions();
1079
1080 assert!(exts.resolve_function("add", None).is_err());
1082 assert!(exts.resolve_function("equal", None).is_err());
1083 }
1084
1085 #[test]
1086 fn test_resolve_function_plain_stored_name() {
1087 let urns = vec![new_urn(1, "urn")];
1089 let extensions = vec![new_ext_fn(10, 1, "coalesce")];
1090 let exts = unwrap_new_extensions(&urns, &extensions);
1091 assert_eq!(exts.resolve_function("coalesce", None).unwrap().anchor, 10);
1092 }
1093
1094 #[test]
1095 fn test_resolve_function_not_found() {
1096 let exts = SimpleExtensions::new();
1097 assert!(exts.resolve_function("nonexistent", None).is_err());
1098 }
1099
1100 #[test]
1101 fn test_compound_name_roundtrip_in_extensions_section() {
1102 let urns = vec![new_urn(1, "substrait:functions_comparison")];
1105 let extensions = vec![
1106 new_ext_fn(1, 1, "equal:any_any"),
1107 new_ext_fn(2, 1, "equal:str_str"),
1108 ];
1109 let exts = unwrap_new_extensions(&urns, &extensions);
1110
1111 let text = exts.to_string(" ");
1112 assert!(
1113 text.contains("equal:any_any"),
1114 "compound name must appear in output"
1115 );
1116 assert!(
1117 text.contains("equal:str_str"),
1118 "compound name must appear in output"
1119 );
1120 }
1121
1122 #[test]
1123 fn test_insert_error_invalid_name_type_variation() {
1124 let mut exts = SimpleExtensions::new();
1126 exts.add_extension_urn("urn:example".to_string(), 1)
1127 .unwrap();
1128 let err = exts
1129 .add_extension(ExtensionKind::TypeVariation, 1, 30, "u!myvar".to_string())
1130 .unwrap_err();
1131 assert_eq!(
1132 err,
1133 InsertError::InvalidName {
1134 kind: ExtensionKind::TypeVariation,
1135 name: "u!myvar".to_string()
1136 }
1137 );
1138 }
1139}