substrait/
urn.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Extension URNs
4
5use std::{error::Error, fmt, str::FromStr};
6
7/// Extension URN
8#[derive(Clone, Debug, PartialEq, Eq, Hash)]
9pub struct Urn {
10    /// Represents the organization or entity providing the extension and
11    /// should follow [reverse domain name convention](https://en.wikipedia.org/wiki/Reverse_domain_name_notation)
12    /// (e.g., `io.substrait`, `com.example`, `org.apache.arrow`) to prevent
13    /// name collisions.
14    pub owner: String,
15
16    /// The specific identifier for the extension (e.g.,
17    /// `functions_arithmetic`, `custom_types`).
18    pub id: String,
19}
20
21impl fmt::Display for Urn {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        write!(f, "extension:{}:{}", self.owner, self.id)
24    }
25}
26
27/// Invalid Urn
28#[derive(Debug, PartialEq)]
29pub struct InvalidUrn;
30
31impl fmt::Display for InvalidUrn {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "invalid urn")
34    }
35}
36
37impl Error for InvalidUrn {}
38
39impl FromStr for Urn {
40    type Err = InvalidUrn;
41
42    fn from_str(s: &str) -> Result<Self, Self::Err> {
43        if let Some(("extension", segments)) = s.split_once(":")
44            && let Some((owner, id)) = segments.split_once(":")
45            && !owner.is_empty()
46            && !id.is_empty()
47        {
48            Ok(Urn {
49                owner: owner.to_string(),
50                id: id.to_string(),
51            })
52        } else {
53            Err(InvalidUrn)
54        }
55    }
56}