prost_types/
type_url.rs

1use super::*;
2
3/// URL/resource name that uniquely identifies the type of the serialized protocol buffer message,
4/// e.g. `type.googleapis.com/google.protobuf.Duration`.
5///
6/// This string must contain at least one "/" character.
7///
8/// The last segment of the URL's path must represent the fully qualified name of the type (as in
9/// `path/google.protobuf.Duration`). The name should be in a canonical form (e.g., leading "." is
10/// not accepted).
11///
12/// If no scheme is provided, `https` is assumed.
13///
14/// Schemes other than `http`, `https` (or the empty scheme) might be used with implementation
15/// specific semantics.
16#[derive(Debug, Eq, PartialEq)]
17pub(crate) struct TypeUrl<'a> {
18    /// Fully qualified name of the type, e.g. `google.protobuf.Duration`
19    pub(crate) full_name: &'a str,
20}
21
22impl<'a> TypeUrl<'a> {
23    pub(crate) fn new(s: &'a str) -> core::option::Option<Self> {
24        // Must contain at least one "/" character.
25        let slash_pos = s.rfind('/')?;
26
27        // The last segment of the URL's path must represent the fully qualified name
28        // of the type (as in `path/google.protobuf.Duration`)
29        let full_name = s.get((slash_pos + 1)..)?;
30
31        // The name should be in a canonical form (e.g., leading "." is not accepted).
32        if full_name.starts_with('.') {
33            return None;
34        }
35
36        Some(Self { full_name })
37    }
38}
39
40/// Compute the type URL for the given `google.protobuf` type, using `type.googleapis.com` as the
41/// authority for the URL.
42pub(crate) fn type_url_for<T: Name>() -> String {
43    format!("type.googleapis.com/{}.{}", T::PACKAGE, T::NAME)
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn check_type_url_parsing() {
52        let example_type_name = "google.protobuf.Duration";
53
54        let url = TypeUrl::new("type.googleapis.com/google.protobuf.Duration").unwrap();
55        assert_eq!(url.full_name, example_type_name);
56
57        let full_url =
58            TypeUrl::new("https://type.googleapis.com/google.protobuf.Duration").unwrap();
59        assert_eq!(full_url.full_name, example_type_name);
60
61        let relative_url = TypeUrl::new("/google.protobuf.Duration").unwrap();
62        assert_eq!(relative_url.full_name, example_type_name);
63
64        // The name should be in a canonical form (e.g., leading "." is not accepted).
65        assert_eq!(TypeUrl::new("/.google.protobuf.Duration"), None);
66
67        // Must contain at least one "/" character.
68        assert_eq!(TypeUrl::new("google.protobuf.Duration"), None);
69    }
70}