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
85#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct CompoundName {
92 name: String,
94 index: usize,
96}
97
98impl CompoundName {
99 pub fn new(name: impl Into<String>) -> Self {
100 let name = name.into();
101 let index = name.find(':').unwrap_or(name.len());
102 Self { name, index }
103 }
104
105 pub fn base(&self) -> &str {
107 &self.name[..self.index]
108 }
109
110 pub fn full(&self) -> &str {
112 &self.name
113 }
114
115 pub fn has_signature(&self) -> bool {
117 self.index < self.name.len()
118 }
119}
120
121impl fmt::Display for CompoundName {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.write_str(&self.name)
124 }
125}
126
127#[derive(Default, Debug, Clone, PartialEq)]
130pub struct SimpleExtensions {
131 urns: BTreeMap<u32, String>,
133 extensions: BTreeMap<(u32, ExtensionKind), (u32, CompoundName)>,
135}
136
137impl SimpleExtensions {
138 pub fn new() -> Self {
139 Self::default()
140 }
141
142 pub fn from_extensions<'a>(
143 urns: impl IntoIterator<Item = &'a pext::SimpleExtensionUrn>,
144 extensions: impl IntoIterator<Item = &'a pext::SimpleExtensionDeclaration>,
145 ) -> (Self, Vec<InsertError>) {
146 let mut exts = Self::new();
150
151 let mut errors = Vec::<InsertError>::new();
152
153 for urn in urns {
154 if let Err(e) = exts.add_extension_urn(urn.urn.clone(), urn.extension_urn_anchor) {
155 errors.push(e);
156 }
157 }
158
159 for extension in extensions {
160 match &extension.mapping_type {
161 Some(MappingType::ExtensionType(t)) => {
162 if let Err(e) = exts.add_extension(
163 ExtensionKind::Type,
164 t.extension_urn_reference,
165 t.type_anchor,
166 t.name.clone(),
167 ) {
168 errors.push(e);
169 }
170 }
171 Some(MappingType::ExtensionFunction(f)) => {
172 if let Err(e) = exts.add_extension(
173 ExtensionKind::Function,
174 f.extension_urn_reference,
175 f.function_anchor,
176 f.name.clone(),
177 ) {
178 errors.push(e);
179 }
180 }
181 Some(MappingType::ExtensionTypeVariation(v)) => {
182 if let Err(e) = exts.add_extension(
183 ExtensionKind::TypeVariation,
184 v.extension_urn_reference,
185 v.type_variation_anchor,
186 v.name.clone(),
187 ) {
188 errors.push(e);
189 }
190 }
191 None => {
192 errors.push(InsertError::MissingMappingType);
193 }
194 }
195 }
196
197 (exts, errors)
198 }
199
200 pub fn add_extension_urn(&mut self, urn: String, anchor: u32) -> Result<(), InsertError> {
201 match self.urns.entry(anchor) {
202 Entry::Occupied(e) => {
203 return Err(InsertError::DuplicateUrnAnchor {
204 anchor,
205 prev: e.get().clone(),
206 name: urn,
207 });
208 }
209 Entry::Vacant(e) => {
210 e.insert(urn);
211 }
212 }
213 Ok(())
214 }
215
216 pub fn add_extension(
217 &mut self,
218 kind: ExtensionKind,
219 urn: u32,
220 anchor: u32,
221 name: String,
222 ) -> Result<(), InsertError> {
223 let missing_urn = !self.urns.contains_key(&urn);
224
225 let prev = match self.extensions.entry((anchor, kind)) {
226 Entry::Occupied(e) => Some(e.get().1.full().to_string()),
227 Entry::Vacant(v) => {
228 v.insert((urn, CompoundName::new(name.clone())));
229 None
230 }
231 };
232
233 match (missing_urn, prev) {
234 (true, Some(prev)) => Err(InsertError::DuplicateAndMissingUrn {
235 kind,
236 anchor,
237 prev,
238 name,
239 urn,
240 }),
241 (false, Some(prev)) => Err(InsertError::DuplicateAnchor {
242 kind,
243 anchor,
244 prev,
245 name,
246 }),
247 (true, None) => Err(InsertError::MissingUrn {
248 kind,
249 anchor,
250 name,
251 urn,
252 }),
253 (false, None) => Ok(()),
254 }
255 }
256
257 pub fn is_empty(&self) -> bool {
258 self.urns.is_empty() && self.extensions.is_empty()
259 }
260
261 pub fn to_extension_urns(&self) -> Vec<pext::SimpleExtensionUrn> {
263 self.urns
264 .iter()
265 .map(|(anchor, urn)| pext::SimpleExtensionUrn {
266 extension_urn_anchor: *anchor,
267 urn: urn.clone(),
268 })
269 .collect()
270 }
271
272 pub fn to_extension_declarations(&self) -> Vec<pext::SimpleExtensionDeclaration> {
274 self.extensions
275 .iter()
276 .map(|((anchor, kind), (urn_ref, name))| {
277 let mapping_type = match kind {
278 ExtensionKind::Function => MappingType::ExtensionFunction(
279 #[allow(deprecated)]
280 pext::simple_extension_declaration::ExtensionFunction {
281 extension_urn_reference: *urn_ref,
282 extension_uri_reference: Default::default(), function_anchor: *anchor,
284 name: name.full().to_string(),
285 },
286 ),
287 ExtensionKind::Type => MappingType::ExtensionType(
288 #[allow(deprecated)]
289 pext::simple_extension_declaration::ExtensionType {
290 extension_urn_reference: *urn_ref,
291 extension_uri_reference: Default::default(), type_anchor: *anchor,
293 name: name.full().to_string(),
294 },
295 ),
296 ExtensionKind::TypeVariation => MappingType::ExtensionTypeVariation(
297 #[allow(deprecated)]
298 pext::simple_extension_declaration::ExtensionTypeVariation {
299 extension_urn_reference: *urn_ref,
300 extension_uri_reference: Default::default(), type_variation_anchor: *anchor,
302 name: name.full().to_string(),
303 },
304 ),
305 };
306 pext::SimpleExtensionDeclaration {
307 mapping_type: Some(mapping_type),
308 }
309 })
310 .collect()
311 }
312
313 pub fn write<W: fmt::Write>(&self, w: &mut W, indent: &str) -> fmt::Result {
317 if self.is_empty() {
318 return Ok(());
320 }
321
322 writeln!(w, "{EXTENSIONS_HEADER}")?;
323 if !self.urns.is_empty() {
324 writeln!(w, "{EXTENSION_URNS_HEADER}")?;
325 for (anchor, urn) in &self.urns {
326 writeln!(w, "{indent}@{anchor:3}: {urn}")?;
327 }
328 }
329
330 let kinds_and_headers = [
331 (ExtensionKind::Function, EXTENSION_FUNCTIONS_HEADER),
332 (ExtensionKind::Type, EXTENSION_TYPES_HEADER),
333 (
334 ExtensionKind::TypeVariation,
335 EXTENSION_TYPE_VARIATIONS_HEADER,
336 ),
337 ];
338 for (kind, header) in kinds_and_headers {
339 let mut filtered = self
340 .extensions
341 .iter()
342 .filter(|((_a, k), _)| *k == kind)
343 .peekable();
344 if filtered.peek().is_none() {
345 continue;
346 }
347
348 writeln!(w, "{header}")?;
349 for ((anchor, _), (urn_ref, name)) in filtered {
350 writeln!(w, "{indent}#{anchor:3} @{urn_ref:3}: {name}")?;
351 }
352 }
353 Ok(())
354 }
355
356 pub fn to_string(&self, indent: &str) -> String {
357 let mut output = String::new();
358 self.write(&mut output, indent).unwrap();
359 output
360 }
361}
362
363#[derive(Error, Debug, Clone, PartialEq)]
364pub enum MissingReference {
365 #[error("Missing URN for {0}")]
366 MissingUrn(u32),
367 #[error("Missing anchor for {0}: {1}")]
368 MissingAnchor(ExtensionKind, u32),
369 #[error("Missing name for {0}: {1}")]
370 MissingName(ExtensionKind, String),
371 #[error("Mismatched {0}: {1}#{2}")]
372 Mismatched(ExtensionKind, String, u32),
374 #[error("Duplicate name without anchor for {0}: {1}")]
375 DuplicateName(ExtensionKind, String),
376}
377
378#[derive(Debug, Clone, PartialEq)]
379pub struct SimpleExtension {
380 pub kind: ExtensionKind,
381 pub name: String,
382 pub anchor: u32,
383 pub urn: u32,
384}
385
386pub struct ResolvedFunction<'a> {
388 pub anchor: u32,
389 pub urn: u32,
390 pub name: &'a CompoundName,
392 pub base_name_unique: bool,
395 pub name_unique: bool,
398}
399
400impl SimpleExtensions {
401 pub fn find_urn(&self, anchor: u32) -> Result<&str, MissingReference> {
402 self.urns
403 .get(&anchor)
404 .map(String::as_str)
405 .ok_or(MissingReference::MissingUrn(anchor))
406 }
407
408 pub fn find_by_anchor(
409 &self,
410 kind: ExtensionKind,
411 anchor: u32,
412 ) -> Result<(u32, &CompoundName), MissingReference> {
413 let &(urn, ref name) = self
414 .extensions
415 .get(&(anchor, kind))
416 .ok_or(MissingReference::MissingAnchor(kind, anchor))?;
417
418 Ok((urn, name))
419 }
420
421 pub fn find_by_name(&self, kind: ExtensionKind, name: &str) -> Result<u32, MissingReference> {
422 let mut matches = self
423 .extensions
424 .iter()
425 .filter(move |((_a, k), (_, n))| *k == kind && n.full() == name)
426 .map(|((anchor, _), _)| *anchor);
427
428 let anchor = matches
429 .next()
430 .ok_or(MissingReference::MissingName(kind, name.to_string()))?;
431
432 match matches.next() {
433 Some(_) => Err(MissingReference::DuplicateName(kind, name.to_string())),
434 None => Ok(anchor),
435 }
436 }
437
438 pub fn is_name_unique(
443 &self,
444 kind: ExtensionKind,
445 anchor: u32,
446 name: &str,
447 ) -> Result<bool, MissingReference> {
448 let mut found = false;
449 let mut other = false;
450 for (&(a, k), (_, n)) in self.extensions.iter() {
451 if k != kind {
452 continue;
453 }
454
455 if a == anchor {
456 found = true;
457 if n.full() != name {
458 return Err(MissingReference::Mismatched(kind, name.to_string(), anchor));
459 }
460 continue;
461 }
462
463 if n.full() != name {
464 continue;
466 }
467
468 other = true;
470 if found {
471 break;
472 }
473 }
474
475 match (found, other) {
476 (true, false) => Ok(true),
478 (true, true) => Ok(false),
480 (false, _) => Err(MissingReference::MissingAnchor(kind, anchor)),
482 }
483 }
484
485 pub fn lookup_function(&self, anchor: u32) -> Result<ResolvedFunction<'_>, MissingReference> {
489 let (urn, name) = self.find_by_anchor(ExtensionKind::Function, anchor)?;
490 let name_unique = self.is_name_unique(ExtensionKind::Function, anchor, name.full())?;
491 let base_name_unique = self.is_base_name_unique(ExtensionKind::Function, anchor)?;
492 Ok(ResolvedFunction {
493 anchor,
494 urn,
495 name,
496 name_unique,
497 base_name_unique,
498 })
499 }
500
501 pub fn resolve_function(
513 &self,
514 name: &str,
515 anchor: Option<u32>,
516 ) -> Result<ResolvedFunction<'_>, MissingReference> {
517 let resolved_anchor = match anchor {
518 Some(a) => {
519 let (_, stored) = self.find_by_anchor(ExtensionKind::Function, a)?;
520 if stored.full() == name || stored.base() == name {
521 a
522 } else {
523 return Err(MissingReference::Mismatched(
524 ExtensionKind::Function,
525 name.to_string(),
526 a,
527 ));
528 }
529 }
530 None => match self.find_by_name(ExtensionKind::Function, name) {
531 Ok(a) => a,
532 Err(MissingReference::MissingName(_, _)) if !name.contains(':') => {
533 self.find_by_base_name(ExtensionKind::Function, name)?
534 }
535 Err(e) => return Err(e),
536 },
537 };
538 self.lookup_function(resolved_anchor)
539 }
540
541 fn is_base_name_unique(
542 &self,
543 kind: ExtensionKind,
544 anchor: u32,
545 ) -> Result<bool, MissingReference> {
546 let (_, name) = self.find_by_anchor(kind, anchor)?;
547 let my_base = name.base();
548
549 let other_exists = self
550 .extensions
551 .iter()
552 .any(|(&(a, k), (_, n))| k == kind && a != anchor && n.base() == my_base);
553
554 Ok(!other_exists)
555 }
556
557 fn find_by_base_name(&self, kind: ExtensionKind, base: &str) -> Result<u32, MissingReference> {
558 let mut matches = self
559 .extensions
560 .iter()
561 .filter(|&(&(_a, k), (_, n))| k == kind && n.base() == base)
562 .map(|(&(anchor, _), _)| anchor);
563
564 let anchor = matches
565 .next()
566 .ok_or_else(|| MissingReference::MissingName(kind, base.to_string()))?;
567
568 match matches.next() {
569 Some(_) => Err(MissingReference::DuplicateName(kind, base.to_string())),
570 None => Ok(anchor),
571 }
572 }
573}
574
575#[cfg(test)]
576mod tests {
577 use pext::simple_extension_declaration::{
578 ExtensionFunction, ExtensionType, ExtensionTypeVariation, MappingType,
579 };
580 use substrait::proto::extensions as pext;
581
582 use super::*;
583
584 fn new_urn(anchor: u32, urn_str: &str) -> pext::SimpleExtensionUrn {
585 pext::SimpleExtensionUrn {
586 extension_urn_anchor: anchor,
587 urn: urn_str.to_string(),
588 }
589 }
590
591 fn new_ext_fn(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
592 pext::SimpleExtensionDeclaration {
593 #[allow(deprecated)]
594 mapping_type: Some(MappingType::ExtensionFunction(ExtensionFunction {
595 extension_urn_reference: urn_ref,
596 extension_uri_reference: Default::default(), function_anchor: anchor,
598 name: name.to_string(),
599 })),
600 }
601 }
602
603 fn new_ext_type(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
604 #[allow(deprecated)]
605 pext::SimpleExtensionDeclaration {
606 mapping_type: Some(MappingType::ExtensionType(ExtensionType {
607 extension_urn_reference: urn_ref,
608 extension_uri_reference: Default::default(), type_anchor: anchor,
610 name: name.to_string(),
611 })),
612 }
613 }
614
615 fn new_type_var(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
616 pext::SimpleExtensionDeclaration {
617 #[allow(deprecated)]
618 mapping_type: Some(MappingType::ExtensionTypeVariation(
619 ExtensionTypeVariation {
620 extension_urn_reference: urn_ref,
621 extension_uri_reference: Default::default(), type_variation_anchor: anchor,
623 name: name.to_string(),
624 },
625 )),
626 }
627 }
628
629 fn assert_no_errors(errs: &[InsertError]) {
630 for err in errs {
631 println!("Error: {err:?}");
632 }
633 assert!(errs.is_empty());
634 }
635
636 fn unwrap_new_extensions<'a>(
637 urns: impl IntoIterator<Item = &'a pext::SimpleExtensionUrn>,
638 extensions: impl IntoIterator<Item = &'a pext::SimpleExtensionDeclaration>,
639 ) -> SimpleExtensions {
640 let (exts, errs) = SimpleExtensions::from_extensions(urns, extensions);
641 assert_no_errors(&errs);
642 exts
643 }
644
645 #[test]
646 fn test_extension_lookup_empty() {
647 let lookup = SimpleExtensions::new();
648 assert!(lookup.find_urn(1).is_err());
649 assert!(lookup.find_by_anchor(ExtensionKind::Function, 1).is_err());
650 assert!(lookup.find_by_anchor(ExtensionKind::Type, 1).is_err());
651 assert!(
652 lookup
653 .find_by_anchor(ExtensionKind::TypeVariation, 1)
654 .is_err()
655 );
656 assert!(lookup.find_by_name(ExtensionKind::Function, "any").is_err());
657 assert!(lookup.find_by_name(ExtensionKind::Type, "any").is_err());
658 assert!(
659 lookup
660 .find_by_name(ExtensionKind::TypeVariation, "any")
661 .is_err()
662 );
663 }
664
665 #[test]
666 fn test_from_extensions_basic() {
667 let urns = vec![new_urn(1, "urn1"), new_urn(2, "urn2")];
668 let extensions = vec![
669 new_ext_fn(10, 1, "func1"),
670 new_ext_type(20, 1, "type1"),
671 new_type_var(30, 2, "var1"),
672 ];
673 let exts = unwrap_new_extensions(&urns, &extensions);
674
675 assert_eq!(exts.find_urn(1).unwrap(), "urn1");
676 assert_eq!(exts.find_urn(2).unwrap(), "urn2");
677 assert!(exts.find_urn(3).is_err());
678
679 let (urn, name) = exts.find_by_anchor(ExtensionKind::Function, 10).unwrap();
680 assert_eq!(name.full(), "func1");
681 assert_eq!(urn, 1);
682 assert!(exts.find_by_anchor(ExtensionKind::Function, 11).is_err());
683
684 let (urn, name) = exts.find_by_anchor(ExtensionKind::Type, 20).unwrap();
685 assert_eq!(name.full(), "type1");
686 assert_eq!(urn, 1);
687 assert!(exts.find_by_anchor(ExtensionKind::Type, 21).is_err());
688
689 let (urn, name) = exts
690 .find_by_anchor(ExtensionKind::TypeVariation, 30)
691 .unwrap();
692 assert_eq!(name.full(), "var1");
693 assert_eq!(urn, 2);
694 assert!(
695 exts.find_by_anchor(ExtensionKind::TypeVariation, 31)
696 .is_err()
697 );
698 }
699
700 #[test]
701 fn test_from_extensions_duplicates() {
702 let urns = vec![
703 new_urn(1, "urn_old"),
704 new_urn(1, "urn_new"),
705 new_urn(2, "second"),
706 ];
707 let extensions = vec![
708 new_ext_fn(10, 1, "func_old"),
709 new_ext_fn(10, 2, "func_new"), new_ext_fn(11, 3, "func_missing"),
711 ];
712 let (exts, errs) = SimpleExtensions::from_extensions(&urns, &extensions);
713 assert_eq!(
714 errs,
715 vec![
716 InsertError::DuplicateUrnAnchor {
717 anchor: 1,
718 name: "urn_new".to_string(),
719 prev: "urn_old".to_string()
720 },
721 InsertError::DuplicateAnchor {
722 kind: ExtensionKind::Function,
723 anchor: 10,
724 prev: "func_old".to_string(),
725 name: "func_new".to_string()
726 },
727 InsertError::MissingUrn {
728 kind: ExtensionKind::Function,
729 anchor: 11,
730 name: "func_missing".to_string(),
731 urn: 3,
732 },
733 ]
734 );
735
736 assert_eq!(exts.find_urn(1).unwrap(), "urn_old");
738 let (urn, name) = exts.find_by_anchor(ExtensionKind::Function, 10).unwrap();
739 assert_eq!(urn, 1);
740 assert_eq!(name.full(), "func_old");
741 }
742
743 #[test]
744 fn test_from_extensions_invalid_mapping_type() {
745 let extensions = vec![pext::SimpleExtensionDeclaration { mapping_type: None }];
746
747 let (_exts, errs) = SimpleExtensions::from_extensions(vec![], &extensions);
748 assert_eq!(errs.len(), 1);
749 let err = &errs[0];
750 assert_eq!(err, &InsertError::MissingMappingType);
751 }
752
753 #[test]
754 fn test_find_by_name() {
755 let urns = vec![new_urn(1, "urn1")];
756 let extensions = vec![
757 new_ext_fn(10, 1, "name1"),
758 new_ext_fn(11, 1, "name2"),
759 new_ext_fn(12, 1, "name1"), new_ext_type(20, 1, "type_name1"),
761 new_type_var(30, 1, "var_name1"),
762 ];
763 let exts = unwrap_new_extensions(&urns, &extensions);
764
765 let err = exts
766 .find_by_name(ExtensionKind::Function, "name1")
767 .unwrap_err();
768 assert_eq!(
769 err,
770 MissingReference::DuplicateName(ExtensionKind::Function, "name1".to_string())
771 );
772
773 let found = exts.find_by_name(ExtensionKind::Function, "name2").unwrap();
774 assert_eq!(found, 11);
775
776 let found = exts
777 .find_by_name(ExtensionKind::Type, "type_name1")
778 .unwrap();
779 assert_eq!(found, 20);
780
781 let err = exts
782 .find_by_name(ExtensionKind::Type, "non_existent_type_name")
783 .unwrap_err();
784 assert_eq!(
785 err,
786 MissingReference::MissingName(
787 ExtensionKind::Type,
788 "non_existent_type_name".to_string()
789 )
790 );
791
792 let found = exts
793 .find_by_name(ExtensionKind::TypeVariation, "var_name1")
794 .unwrap();
795 assert_eq!(found, 30);
796
797 let err = exts
798 .find_by_name(ExtensionKind::TypeVariation, "non_existent_var_name")
799 .unwrap_err();
800 assert_eq!(
801 err,
802 MissingReference::MissingName(
803 ExtensionKind::TypeVariation,
804 "non_existent_var_name".to_string()
805 )
806 );
807 }
808
809 #[test]
810 fn test_display_extension_lookup_empty() {
811 let lookup = SimpleExtensions::new();
812 let mut output = String::new();
813 lookup.write(&mut output, " ").unwrap();
814 let expected = r"";
815 assert_eq!(output, expected.trim_start());
816 }
817
818 #[test]
819 fn test_display_extension_lookup_with_content() {
820 let urns = vec![
821 new_urn(1, "/my/urn1"),
822 new_urn(42, "/another/urn"),
823 new_urn(4091, "/big/anchor"),
824 ];
825 let extensions = vec![
826 new_ext_fn(10, 1, "my_func"),
827 new_ext_type(20, 1, "my_type"),
828 new_type_var(30, 42, "my_var"),
829 new_ext_fn(11, 42, "another_func"),
830 new_ext_fn(108812, 4091, "big_func"),
831 ];
832 let exts = unwrap_new_extensions(&urns, &extensions);
833 let display_str = exts.to_string(" ");
834
835 let expected = r"
836=== Extensions
837URNs:
838 @ 1: /my/urn1
839 @ 42: /another/urn
840 @4091: /big/anchor
841Functions:
842 # 10 @ 1: my_func
843 # 11 @ 42: another_func
844 #108812 @4091: big_func
845Types:
846 # 20 @ 1: my_type
847Type Variations:
848 # 30 @ 42: my_var
849";
850 assert_eq!(display_str, expected.trim_start());
851 }
852
853 #[test]
854 fn test_extensions_output() {
855 let mut extensions = SimpleExtensions::new();
857 extensions
858 .add_extension_urn("/urn/common".to_string(), 1)
859 .unwrap();
860 extensions
861 .add_extension_urn("/urn/specific_funcs".to_string(), 2)
862 .unwrap();
863 extensions
864 .add_extension(ExtensionKind::Function, 1, 10, "func_a".to_string())
865 .unwrap();
866 extensions
867 .add_extension(ExtensionKind::Function, 2, 11, "func_b_special".to_string())
868 .unwrap();
869 extensions
870 .add_extension(ExtensionKind::Type, 1, 20, "SomeType".to_string())
871 .unwrap();
872 extensions
873 .add_extension(ExtensionKind::TypeVariation, 2, 30, "VarX".to_string())
874 .unwrap();
875
876 let output = extensions.to_string(" ");
878
879 let expected_output = r#"
881=== Extensions
882URNs:
883 @ 1: /urn/common
884 @ 2: /urn/specific_funcs
885Functions:
886 # 10 @ 1: func_a
887 # 11 @ 2: func_b_special
888Types:
889 # 20 @ 1: SomeType
890Type Variations:
891 # 30 @ 2: VarX
892"#;
893
894 assert_eq!(output, expected_output.trim_start());
895 }
896
897 #[test]
898 fn test_compound_name_plain() {
899 let n = CompoundName::new("add");
900 assert_eq!(n.full(), "add");
901 assert_eq!(n.base(), "add");
902 assert!(!n.has_signature());
903
904 let n2 = CompoundName::new("coalesce");
905 assert_eq!(n2.full(), "coalesce");
906 assert_eq!(n2.base(), "coalesce");
907 }
908
909 #[test]
910 fn test_compound_name_with_signature() {
911 let n = CompoundName::new("equal:any_any");
912 assert_eq!(n.full(), "equal:any_any");
913 assert_eq!(n.base(), "equal");
914 assert!(n.has_signature());
915
916 let n2 = CompoundName::new("regexp_match_substring:str_str_i64");
917 assert_eq!(n2.base(), "regexp_match_substring");
918 assert_eq!(n2.full(), "regexp_match_substring:str_str_i64");
919 assert!(n2.has_signature());
920
921 let n3 = CompoundName::new("add:i64_i64");
922 assert_eq!(n3.base(), "add");
923 }
924
925 #[test]
926 fn test_compound_name_trailing_colon() {
927 let n = CompoundName::new("foo:");
929 assert_eq!(n.base(), "foo");
930 assert_eq!(n.full(), "foo:");
931 assert!(n.has_signature());
932 }
933
934 fn make_overloaded_extensions() -> SimpleExtensions {
937 let urns = vec![new_urn(1, "urn:comparison")];
938 let extensions = vec![
939 new_ext_fn(1, 1, "equal:any_any"),
940 new_ext_fn(2, 1, "equal:str_str"),
941 new_ext_fn(3, 1, "add:i64_i64"),
942 ];
943 unwrap_new_extensions(&urns, &extensions)
944 }
945
946 #[test]
947 fn test_lookup_function_uniqueness_flags() {
948 let exts = make_overloaded_extensions();
952
953 let r1 = exts.lookup_function(1).unwrap();
954 assert_eq!(r1.name.full(), "equal:any_any");
955 assert!(!r1.base_name_unique, "two 'equal' overloads");
956 assert!(r1.name_unique, "compound name 'equal:any_any' is unique");
957
958 let r2 = exts.lookup_function(2).unwrap();
959 assert_eq!(r2.name.full(), "equal:str_str");
960 assert!(!r2.base_name_unique);
961 assert!(r2.name_unique);
962
963 let r3 = exts.lookup_function(3).unwrap();
964 assert_eq!(r3.name.full(), "add:i64_i64");
965 assert!(r3.base_name_unique, "only one 'add' overload");
966 assert!(r3.name_unique, "compound name appears only once");
967 }
968
969 #[test]
970 fn test_lookup_function_missing_anchor() {
971 let exts = SimpleExtensions::new();
972 assert!(exts.lookup_function(99).is_err());
973 }
974
975 #[test]
976 fn test_lookup_function_plain_name_overloaded_across_urns() {
977 let urns = vec![new_urn(1, "urn1"), new_urn(2, "urn2")];
979 let extensions = vec![
980 new_ext_fn(1, 1, "duplicated"),
981 new_ext_fn(2, 2, "duplicated"),
982 ];
983 let exts = unwrap_new_extensions(&urns, &extensions);
984
985 let r = exts.lookup_function(1).unwrap();
986 assert!(!r.base_name_unique);
987 assert!(!r.name_unique);
988 }
989
990 #[test]
991 fn test_lookup_function_different_base_names_each_unique() {
992 let urns = vec![new_urn(1, "urn1")];
994 let extensions = vec![
995 new_ext_fn(1, 1, "equal:any_any"),
996 new_ext_fn(2, 1, "like:str_str"),
997 ];
998 let exts = unwrap_new_extensions(&urns, &extensions);
999
1000 assert!(exts.lookup_function(1).unwrap().base_name_unique);
1001 assert!(exts.lookup_function(2).unwrap().base_name_unique);
1002 }
1003
1004 fn make_resolve_extensions() -> SimpleExtensions {
1007 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 ];
1014 unwrap_new_extensions(&urns, &extensions)
1015 }
1016
1017 #[test]
1018 fn test_resolve_function_with_anchor() {
1019 let exts = make_resolve_extensions();
1021
1022 assert_eq!(
1024 exts.resolve_function("equal:any_any", Some(1))
1025 .unwrap()
1026 .anchor,
1027 1
1028 );
1029
1030 assert_eq!(exts.resolve_function("equal", Some(1)).unwrap().anchor, 1);
1032
1033 assert!(exts.resolve_function("like", Some(1)).is_err());
1035 }
1036
1037 #[test]
1038 fn test_resolve_function_without_anchor() {
1039 let exts = make_resolve_extensions();
1041
1042 assert_eq!(
1044 exts.resolve_function("equal:any_any", None).unwrap().anchor,
1045 1
1046 );
1047 assert_eq!(
1048 exts.resolve_function("equal:str_str", None).unwrap().anchor,
1049 2
1050 );
1051
1052 assert_eq!(exts.resolve_function("add", None).unwrap().anchor, 3);
1054
1055 assert!(exts.resolve_function("equal", None).is_err());
1057 }
1058
1059 #[test]
1060 fn test_resolve_function_plain_stored_name() {
1061 let urns = vec![new_urn(1, "urn")];
1063 let extensions = vec![new_ext_fn(10, 1, "coalesce")];
1064 let exts = unwrap_new_extensions(&urns, &extensions);
1065 assert_eq!(exts.resolve_function("coalesce", None).unwrap().anchor, 10);
1066 }
1067
1068 #[test]
1069 fn test_resolve_function_not_found() {
1070 let exts = SimpleExtensions::new();
1071 assert!(exts.resolve_function("nonexistent", None).is_err());
1072 }
1073
1074 #[test]
1075 fn test_compound_name_roundtrip_in_extensions_section() {
1076 let urns = vec![new_urn(1, "substrait:functions_comparison")];
1079 let extensions = vec![
1080 new_ext_fn(1, 1, "equal:any_any"),
1081 new_ext_fn(2, 1, "equal:str_str"),
1082 ];
1083 let exts = unwrap_new_extensions(&urns, &extensions);
1084
1085 let text = exts.to_string(" ");
1086 assert!(
1087 text.contains("equal:any_any"),
1088 "compound name must appear in output"
1089 );
1090 assert!(
1091 text.contains("equal:str_str"),
1092 "compound name must appear in output"
1093 );
1094 }
1095}