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}