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 pext::simple_extension_declaration::ExtensionFunction {
280 extension_urn_reference: *urn_ref,
281 function_anchor: *anchor,
282 name: name.full().to_string(),
283 },
284 ),
285 ExtensionKind::Type => MappingType::ExtensionType(
286 pext::simple_extension_declaration::ExtensionType {
287 extension_urn_reference: *urn_ref,
288 type_anchor: *anchor,
289 name: name.full().to_string(),
290 },
291 ),
292 ExtensionKind::TypeVariation => MappingType::ExtensionTypeVariation(
293 pext::simple_extension_declaration::ExtensionTypeVariation {
294 extension_urn_reference: *urn_ref,
295 type_variation_anchor: *anchor,
296 name: name.full().to_string(),
297 },
298 ),
299 };
300 pext::SimpleExtensionDeclaration {
301 mapping_type: Some(mapping_type),
302 }
303 })
304 .collect()
305 }
306
307 pub fn write<W: fmt::Write>(&self, w: &mut W, indent: &str) -> fmt::Result {
311 if self.is_empty() {
312 return Ok(());
314 }
315
316 writeln!(w, "{EXTENSIONS_HEADER}")?;
317 if !self.urns.is_empty() {
318 writeln!(w, "{EXTENSION_URNS_HEADER}")?;
319 for (anchor, urn) in &self.urns {
320 writeln!(w, "{indent}@{anchor:3}: {urn}")?;
321 }
322 }
323
324 let kinds_and_headers = [
325 (ExtensionKind::Function, EXTENSION_FUNCTIONS_HEADER),
326 (ExtensionKind::Type, EXTENSION_TYPES_HEADER),
327 (
328 ExtensionKind::TypeVariation,
329 EXTENSION_TYPE_VARIATIONS_HEADER,
330 ),
331 ];
332 for (kind, header) in kinds_and_headers {
333 let mut filtered = self
334 .extensions
335 .iter()
336 .filter(|((_a, k), _)| *k == kind)
337 .peekable();
338 if filtered.peek().is_none() {
339 continue;
340 }
341
342 writeln!(w, "{header}")?;
343 for ((anchor, _), (urn_ref, name)) in filtered {
344 writeln!(w, "{indent}#{anchor:3} @{urn_ref:3}: {name}")?;
345 }
346 }
347 Ok(())
348 }
349
350 pub fn to_string(&self, indent: &str) -> String {
351 let mut output = String::new();
352 self.write(&mut output, indent).unwrap();
353 output
354 }
355}
356
357#[derive(Error, Debug, Clone, PartialEq)]
358pub enum MissingReference {
359 #[error("Missing URN for {0}")]
360 MissingUrn(u32),
361 #[error("Missing anchor for {0}: {1}")]
362 MissingAnchor(ExtensionKind, u32),
363 #[error("Missing name for {0}: {1}")]
364 MissingName(ExtensionKind, String),
365 #[error("Mismatched {0}: {1}#{2}")]
366 Mismatched(ExtensionKind, String, u32),
368 #[error("Duplicate name without anchor for {0}: {1}")]
369 DuplicateName(ExtensionKind, String),
370}
371
372#[derive(Debug, Clone, PartialEq)]
373pub struct SimpleExtension {
374 pub kind: ExtensionKind,
375 pub name: String,
376 pub anchor: u32,
377 pub urn: u32,
378}
379
380pub struct ResolvedFunction<'a> {
382 pub anchor: u32,
383 pub urn: u32,
384 pub name: &'a CompoundName,
386 pub base_name_unique: bool,
389 pub name_unique: bool,
392}
393
394impl SimpleExtensions {
395 pub fn find_urn(&self, anchor: u32) -> Result<&str, MissingReference> {
396 self.urns
397 .get(&anchor)
398 .map(String::as_str)
399 .ok_or(MissingReference::MissingUrn(anchor))
400 }
401
402 pub fn find_by_anchor(
403 &self,
404 kind: ExtensionKind,
405 anchor: u32,
406 ) -> Result<(u32, &CompoundName), MissingReference> {
407 let &(urn, ref name) = self
408 .extensions
409 .get(&(anchor, kind))
410 .ok_or(MissingReference::MissingAnchor(kind, anchor))?;
411
412 Ok((urn, name))
413 }
414
415 pub fn find_by_name(&self, kind: ExtensionKind, name: &str) -> Result<u32, MissingReference> {
416 let mut matches = self
417 .extensions
418 .iter()
419 .filter(move |((_a, k), (_, n))| *k == kind && n.full() == name)
420 .map(|((anchor, _), _)| *anchor);
421
422 let anchor = matches
423 .next()
424 .ok_or(MissingReference::MissingName(kind, name.to_string()))?;
425
426 match matches.next() {
427 Some(_) => Err(MissingReference::DuplicateName(kind, name.to_string())),
428 None => Ok(anchor),
429 }
430 }
431
432 pub fn is_name_unique(
437 &self,
438 kind: ExtensionKind,
439 anchor: u32,
440 name: &str,
441 ) -> Result<bool, MissingReference> {
442 let mut found = false;
443 let mut other = false;
444 for (&(a, k), (_, n)) in self.extensions.iter() {
445 if k != kind {
446 continue;
447 }
448
449 if a == anchor {
450 found = true;
451 if n.full() != name {
452 return Err(MissingReference::Mismatched(kind, name.to_string(), anchor));
453 }
454 continue;
455 }
456
457 if n.full() != name {
458 continue;
460 }
461
462 other = true;
464 if found {
465 break;
466 }
467 }
468
469 match (found, other) {
470 (true, false) => Ok(true),
472 (true, true) => Ok(false),
474 (false, _) => Err(MissingReference::MissingAnchor(kind, anchor)),
476 }
477 }
478
479 pub fn lookup_function(&self, anchor: u32) -> Result<ResolvedFunction<'_>, MissingReference> {
483 let (urn, name) = self.find_by_anchor(ExtensionKind::Function, anchor)?;
484 let name_unique = self.is_name_unique(ExtensionKind::Function, anchor, name.full())?;
485 let base_name_unique = self.is_base_name_unique(ExtensionKind::Function, anchor)?;
486 Ok(ResolvedFunction {
487 anchor,
488 urn,
489 name,
490 name_unique,
491 base_name_unique,
492 })
493 }
494
495 pub fn resolve_function(
507 &self,
508 name: &str,
509 anchor: Option<u32>,
510 ) -> Result<ResolvedFunction<'_>, MissingReference> {
511 let resolved_anchor = match anchor {
512 Some(a) => {
513 let (_, stored) = self.find_by_anchor(ExtensionKind::Function, a)?;
514 if stored.full() == name || stored.base() == name {
515 a
516 } else {
517 return Err(MissingReference::Mismatched(
518 ExtensionKind::Function,
519 name.to_string(),
520 a,
521 ));
522 }
523 }
524 None => match self.find_by_name(ExtensionKind::Function, name) {
525 Ok(a) => a,
526 Err(MissingReference::MissingName(_, _)) if !name.contains(':') => {
527 self.find_by_base_name(ExtensionKind::Function, name)?
528 }
529 Err(e) => return Err(e),
530 },
531 };
532 self.lookup_function(resolved_anchor)
533 }
534
535 fn is_base_name_unique(
536 &self,
537 kind: ExtensionKind,
538 anchor: u32,
539 ) -> Result<bool, MissingReference> {
540 let (_, name) = self.find_by_anchor(kind, anchor)?;
541 let my_base = name.base();
542
543 let other_exists = self
544 .extensions
545 .iter()
546 .any(|(&(a, k), (_, n))| k == kind && a != anchor && n.base() == my_base);
547
548 Ok(!other_exists)
549 }
550
551 fn find_by_base_name(&self, kind: ExtensionKind, base: &str) -> Result<u32, MissingReference> {
552 let mut matches = self
553 .extensions
554 .iter()
555 .filter(|&(&(_a, k), (_, n))| k == kind && n.base() == base)
556 .map(|(&(anchor, _), _)| anchor);
557
558 let anchor = matches
559 .next()
560 .ok_or_else(|| MissingReference::MissingName(kind, base.to_string()))?;
561
562 match matches.next() {
563 Some(_) => Err(MissingReference::DuplicateName(kind, base.to_string())),
564 None => Ok(anchor),
565 }
566 }
567}
568
569#[cfg(test)]
570mod tests {
571 use pext::simple_extension_declaration::{
572 ExtensionFunction, ExtensionType, ExtensionTypeVariation, MappingType,
573 };
574 use substrait::proto::extensions as pext;
575
576 use super::*;
577
578 fn new_urn(anchor: u32, urn_str: &str) -> pext::SimpleExtensionUrn {
579 pext::SimpleExtensionUrn {
580 extension_urn_anchor: anchor,
581 urn: urn_str.to_string(),
582 }
583 }
584
585 fn new_ext_fn(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
586 pext::SimpleExtensionDeclaration {
587 mapping_type: Some(MappingType::ExtensionFunction(ExtensionFunction {
588 extension_urn_reference: urn_ref,
589 function_anchor: anchor,
590 name: name.to_string(),
591 })),
592 }
593 }
594
595 fn new_ext_type(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
596 pext::SimpleExtensionDeclaration {
597 mapping_type: Some(MappingType::ExtensionType(ExtensionType {
598 extension_urn_reference: urn_ref,
599 type_anchor: anchor,
600 name: name.to_string(),
601 })),
602 }
603 }
604
605 fn new_type_var(anchor: u32, urn_ref: u32, name: &str) -> pext::SimpleExtensionDeclaration {
606 pext::SimpleExtensionDeclaration {
607 mapping_type: Some(MappingType::ExtensionTypeVariation(
608 ExtensionTypeVariation {
609 extension_urn_reference: urn_ref,
610 type_variation_anchor: anchor,
611 name: name.to_string(),
612 },
613 )),
614 }
615 }
616
617 fn assert_no_errors(errs: &[InsertError]) {
618 for err in errs {
619 println!("Error: {err:?}");
620 }
621 assert!(errs.is_empty());
622 }
623
624 fn unwrap_new_extensions<'a>(
625 urns: impl IntoIterator<Item = &'a pext::SimpleExtensionUrn>,
626 extensions: impl IntoIterator<Item = &'a pext::SimpleExtensionDeclaration>,
627 ) -> SimpleExtensions {
628 let (exts, errs) = SimpleExtensions::from_extensions(urns, extensions);
629 assert_no_errors(&errs);
630 exts
631 }
632
633 #[test]
634 fn test_extension_lookup_empty() {
635 let lookup = SimpleExtensions::new();
636 assert!(lookup.find_urn(1).is_err());
637 assert!(lookup.find_by_anchor(ExtensionKind::Function, 1).is_err());
638 assert!(lookup.find_by_anchor(ExtensionKind::Type, 1).is_err());
639 assert!(
640 lookup
641 .find_by_anchor(ExtensionKind::TypeVariation, 1)
642 .is_err()
643 );
644 assert!(lookup.find_by_name(ExtensionKind::Function, "any").is_err());
645 assert!(lookup.find_by_name(ExtensionKind::Type, "any").is_err());
646 assert!(
647 lookup
648 .find_by_name(ExtensionKind::TypeVariation, "any")
649 .is_err()
650 );
651 }
652
653 #[test]
654 fn test_from_extensions_basic() {
655 let urns = vec![new_urn(1, "urn1"), new_urn(2, "urn2")];
656 let extensions = vec![
657 new_ext_fn(10, 1, "func1"),
658 new_ext_type(20, 1, "type1"),
659 new_type_var(30, 2, "var1"),
660 ];
661 let exts = unwrap_new_extensions(&urns, &extensions);
662
663 assert_eq!(exts.find_urn(1).unwrap(), "urn1");
664 assert_eq!(exts.find_urn(2).unwrap(), "urn2");
665 assert!(exts.find_urn(3).is_err());
666
667 let (urn, name) = exts.find_by_anchor(ExtensionKind::Function, 10).unwrap();
668 assert_eq!(name.full(), "func1");
669 assert_eq!(urn, 1);
670 assert!(exts.find_by_anchor(ExtensionKind::Function, 11).is_err());
671
672 let (urn, name) = exts.find_by_anchor(ExtensionKind::Type, 20).unwrap();
673 assert_eq!(name.full(), "type1");
674 assert_eq!(urn, 1);
675 assert!(exts.find_by_anchor(ExtensionKind::Type, 21).is_err());
676
677 let (urn, name) = exts
678 .find_by_anchor(ExtensionKind::TypeVariation, 30)
679 .unwrap();
680 assert_eq!(name.full(), "var1");
681 assert_eq!(urn, 2);
682 assert!(
683 exts.find_by_anchor(ExtensionKind::TypeVariation, 31)
684 .is_err()
685 );
686 }
687
688 #[test]
689 fn test_from_extensions_duplicates() {
690 let urns = vec![
691 new_urn(1, "urn_old"),
692 new_urn(1, "urn_new"),
693 new_urn(2, "second"),
694 ];
695 let extensions = vec![
696 new_ext_fn(10, 1, "func_old"),
697 new_ext_fn(10, 2, "func_new"), new_ext_fn(11, 3, "func_missing"),
699 ];
700 let (exts, errs) = SimpleExtensions::from_extensions(&urns, &extensions);
701 assert_eq!(
702 errs,
703 vec![
704 InsertError::DuplicateUrnAnchor {
705 anchor: 1,
706 name: "urn_new".to_string(),
707 prev: "urn_old".to_string()
708 },
709 InsertError::DuplicateAnchor {
710 kind: ExtensionKind::Function,
711 anchor: 10,
712 prev: "func_old".to_string(),
713 name: "func_new".to_string()
714 },
715 InsertError::MissingUrn {
716 kind: ExtensionKind::Function,
717 anchor: 11,
718 name: "func_missing".to_string(),
719 urn: 3,
720 },
721 ]
722 );
723
724 assert_eq!(exts.find_urn(1).unwrap(), "urn_old");
726 let (urn, name) = exts.find_by_anchor(ExtensionKind::Function, 10).unwrap();
727 assert_eq!(urn, 1);
728 assert_eq!(name.full(), "func_old");
729 }
730
731 #[test]
732 fn test_from_extensions_invalid_mapping_type() {
733 let extensions = vec![pext::SimpleExtensionDeclaration { mapping_type: None }];
734
735 let (_exts, errs) = SimpleExtensions::from_extensions(vec![], &extensions);
736 assert_eq!(errs.len(), 1);
737 let err = &errs[0];
738 assert_eq!(err, &InsertError::MissingMappingType);
739 }
740
741 #[test]
742 fn test_find_by_name() {
743 let urns = vec![new_urn(1, "urn1")];
744 let extensions = vec![
745 new_ext_fn(10, 1, "name1"),
746 new_ext_fn(11, 1, "name2"),
747 new_ext_fn(12, 1, "name1"), new_ext_type(20, 1, "type_name1"),
749 new_type_var(30, 1, "var_name1"),
750 ];
751 let exts = unwrap_new_extensions(&urns, &extensions);
752
753 let err = exts
754 .find_by_name(ExtensionKind::Function, "name1")
755 .unwrap_err();
756 assert_eq!(
757 err,
758 MissingReference::DuplicateName(ExtensionKind::Function, "name1".to_string())
759 );
760
761 let found = exts.find_by_name(ExtensionKind::Function, "name2").unwrap();
762 assert_eq!(found, 11);
763
764 let found = exts
765 .find_by_name(ExtensionKind::Type, "type_name1")
766 .unwrap();
767 assert_eq!(found, 20);
768
769 let err = exts
770 .find_by_name(ExtensionKind::Type, "non_existent_type_name")
771 .unwrap_err();
772 assert_eq!(
773 err,
774 MissingReference::MissingName(
775 ExtensionKind::Type,
776 "non_existent_type_name".to_string()
777 )
778 );
779
780 let found = exts
781 .find_by_name(ExtensionKind::TypeVariation, "var_name1")
782 .unwrap();
783 assert_eq!(found, 30);
784
785 let err = exts
786 .find_by_name(ExtensionKind::TypeVariation, "non_existent_var_name")
787 .unwrap_err();
788 assert_eq!(
789 err,
790 MissingReference::MissingName(
791 ExtensionKind::TypeVariation,
792 "non_existent_var_name".to_string()
793 )
794 );
795 }
796
797 #[test]
798 fn test_display_extension_lookup_empty() {
799 let lookup = SimpleExtensions::new();
800 let mut output = String::new();
801 lookup.write(&mut output, " ").unwrap();
802 let expected = r"";
803 assert_eq!(output, expected.trim_start());
804 }
805
806 #[test]
807 fn test_display_extension_lookup_with_content() {
808 let urns = vec![
809 new_urn(1, "/my/urn1"),
810 new_urn(42, "/another/urn"),
811 new_urn(4091, "/big/anchor"),
812 ];
813 let extensions = vec![
814 new_ext_fn(10, 1, "my_func"),
815 new_ext_type(20, 1, "my_type"),
816 new_type_var(30, 42, "my_var"),
817 new_ext_fn(11, 42, "another_func"),
818 new_ext_fn(108812, 4091, "big_func"),
819 ];
820 let exts = unwrap_new_extensions(&urns, &extensions);
821 let display_str = exts.to_string(" ");
822
823 let expected = r"
824=== Extensions
825URNs:
826 @ 1: /my/urn1
827 @ 42: /another/urn
828 @4091: /big/anchor
829Functions:
830 # 10 @ 1: my_func
831 # 11 @ 42: another_func
832 #108812 @4091: big_func
833Types:
834 # 20 @ 1: my_type
835Type Variations:
836 # 30 @ 42: my_var
837";
838 assert_eq!(display_str, expected.trim_start());
839 }
840
841 #[test]
842 fn test_extensions_output() {
843 let mut extensions = SimpleExtensions::new();
845 extensions
846 .add_extension_urn("/urn/common".to_string(), 1)
847 .unwrap();
848 extensions
849 .add_extension_urn("/urn/specific_funcs".to_string(), 2)
850 .unwrap();
851 extensions
852 .add_extension(ExtensionKind::Function, 1, 10, "func_a".to_string())
853 .unwrap();
854 extensions
855 .add_extension(ExtensionKind::Function, 2, 11, "func_b_special".to_string())
856 .unwrap();
857 extensions
858 .add_extension(ExtensionKind::Type, 1, 20, "SomeType".to_string())
859 .unwrap();
860 extensions
861 .add_extension(ExtensionKind::TypeVariation, 2, 30, "VarX".to_string())
862 .unwrap();
863
864 let output = extensions.to_string(" ");
866
867 let expected_output = r#"
869=== Extensions
870URNs:
871 @ 1: /urn/common
872 @ 2: /urn/specific_funcs
873Functions:
874 # 10 @ 1: func_a
875 # 11 @ 2: func_b_special
876Types:
877 # 20 @ 1: SomeType
878Type Variations:
879 # 30 @ 2: VarX
880"#;
881
882 assert_eq!(output, expected_output.trim_start());
883 }
884
885 #[test]
886 fn test_compound_name_plain() {
887 let n = CompoundName::new("add");
888 assert_eq!(n.full(), "add");
889 assert_eq!(n.base(), "add");
890 assert!(!n.has_signature());
891
892 let n2 = CompoundName::new("coalesce");
893 assert_eq!(n2.full(), "coalesce");
894 assert_eq!(n2.base(), "coalesce");
895 }
896
897 #[test]
898 fn test_compound_name_with_signature() {
899 let n = CompoundName::new("equal:any_any");
900 assert_eq!(n.full(), "equal:any_any");
901 assert_eq!(n.base(), "equal");
902 assert!(n.has_signature());
903
904 let n2 = CompoundName::new("regexp_match_substring:str_str_i64");
905 assert_eq!(n2.base(), "regexp_match_substring");
906 assert_eq!(n2.full(), "regexp_match_substring:str_str_i64");
907 assert!(n2.has_signature());
908
909 let n3 = CompoundName::new("add:i64_i64");
910 assert_eq!(n3.base(), "add");
911 }
912
913 #[test]
914 fn test_compound_name_trailing_colon() {
915 let n = CompoundName::new("foo:");
917 assert_eq!(n.base(), "foo");
918 assert_eq!(n.full(), "foo:");
919 assert!(n.has_signature());
920 }
921
922 fn make_overloaded_extensions() -> SimpleExtensions {
925 let urns = vec![new_urn(1, "urn:comparison")];
926 let extensions = vec![
927 new_ext_fn(1, 1, "equal:any_any"),
928 new_ext_fn(2, 1, "equal:str_str"),
929 new_ext_fn(3, 1, "add:i64_i64"),
930 ];
931 unwrap_new_extensions(&urns, &extensions)
932 }
933
934 #[test]
935 fn test_lookup_function_uniqueness_flags() {
936 let exts = make_overloaded_extensions();
940
941 let r1 = exts.lookup_function(1).unwrap();
942 assert_eq!(r1.name.full(), "equal:any_any");
943 assert!(!r1.base_name_unique, "two 'equal' overloads");
944 assert!(r1.name_unique, "compound name 'equal:any_any' is unique");
945
946 let r2 = exts.lookup_function(2).unwrap();
947 assert_eq!(r2.name.full(), "equal:str_str");
948 assert!(!r2.base_name_unique);
949 assert!(r2.name_unique);
950
951 let r3 = exts.lookup_function(3).unwrap();
952 assert_eq!(r3.name.full(), "add:i64_i64");
953 assert!(r3.base_name_unique, "only one 'add' overload");
954 assert!(r3.name_unique, "compound name appears only once");
955 }
956
957 #[test]
958 fn test_lookup_function_missing_anchor() {
959 let exts = SimpleExtensions::new();
960 assert!(exts.lookup_function(99).is_err());
961 }
962
963 #[test]
964 fn test_lookup_function_plain_name_overloaded_across_urns() {
965 let urns = vec![new_urn(1, "urn1"), new_urn(2, "urn2")];
967 let extensions = vec![
968 new_ext_fn(1, 1, "duplicated"),
969 new_ext_fn(2, 2, "duplicated"),
970 ];
971 let exts = unwrap_new_extensions(&urns, &extensions);
972
973 let r = exts.lookup_function(1).unwrap();
974 assert!(!r.base_name_unique);
975 assert!(!r.name_unique);
976 }
977
978 #[test]
979 fn test_lookup_function_different_base_names_each_unique() {
980 let urns = vec![new_urn(1, "urn1")];
982 let extensions = vec![
983 new_ext_fn(1, 1, "equal:any_any"),
984 new_ext_fn(2, 1, "like:str_str"),
985 ];
986 let exts = unwrap_new_extensions(&urns, &extensions);
987
988 assert!(exts.lookup_function(1).unwrap().base_name_unique);
989 assert!(exts.lookup_function(2).unwrap().base_name_unique);
990 }
991
992 fn make_resolve_extensions() -> SimpleExtensions {
995 let urns = vec![new_urn(1, "test_urn")];
997 let extensions = vec![
998 new_ext_fn(1, 1, "equal:any_any"),
999 new_ext_fn(2, 1, "equal:str_str"),
1000 new_ext_fn(3, 1, "add:i64_i64"),
1001 ];
1002 unwrap_new_extensions(&urns, &extensions)
1003 }
1004
1005 #[test]
1006 fn test_resolve_function_with_anchor() {
1007 let exts = make_resolve_extensions();
1009
1010 assert_eq!(
1012 exts.resolve_function("equal:any_any", Some(1))
1013 .unwrap()
1014 .anchor,
1015 1
1016 );
1017
1018 assert_eq!(exts.resolve_function("equal", Some(1)).unwrap().anchor, 1);
1020
1021 assert!(exts.resolve_function("like", Some(1)).is_err());
1023 }
1024
1025 #[test]
1026 fn test_resolve_function_without_anchor() {
1027 let exts = make_resolve_extensions();
1029
1030 assert_eq!(
1032 exts.resolve_function("equal:any_any", None).unwrap().anchor,
1033 1
1034 );
1035 assert_eq!(
1036 exts.resolve_function("equal:str_str", None).unwrap().anchor,
1037 2
1038 );
1039
1040 assert_eq!(exts.resolve_function("add", None).unwrap().anchor, 3);
1042
1043 assert!(exts.resolve_function("equal", None).is_err());
1045 }
1046
1047 #[test]
1048 fn test_resolve_function_plain_stored_name() {
1049 let urns = vec![new_urn(1, "urn")];
1051 let extensions = vec![new_ext_fn(10, 1, "coalesce")];
1052 let exts = unwrap_new_extensions(&urns, &extensions);
1053 assert_eq!(exts.resolve_function("coalesce", None).unwrap().anchor, 10);
1054 }
1055
1056 #[test]
1057 fn test_resolve_function_not_found() {
1058 let exts = SimpleExtensions::new();
1059 assert!(exts.resolve_function("nonexistent", None).is_err());
1060 }
1061
1062 #[test]
1063 fn test_compound_name_roundtrip_in_extensions_section() {
1064 let urns = vec![new_urn(1, "substrait:functions_comparison")];
1067 let extensions = vec![
1068 new_ext_fn(1, 1, "equal:any_any"),
1069 new_ext_fn(2, 1, "equal:str_str"),
1070 ];
1071 let exts = unwrap_new_extensions(&urns, &extensions);
1072
1073 let text = exts.to_string(" ");
1074 assert!(
1075 text.contains("equal:any_any"),
1076 "compound name must appear in output"
1077 );
1078 assert!(
1079 text.contains("equal:str_str"),
1080 "compound name must appear in output"
1081 );
1082 }
1083}