gix_validate/
reference.rs1use bstr::{BStr, BString, ByteSlice};
2
3pub mod name {
5 use std::convert::Infallible;
6
7 #[derive(Debug, thiserror::Error)]
9 #[allow(missing_docs)]
10 pub enum Error {
11 #[error("A reference must be a valid tag name as well")]
12 Tag(#[from] crate::tag::name::Error),
13 #[error("Standalone references must be all uppercased, like 'HEAD'")]
14 SomeLowercase,
15 }
16
17 impl From<Infallible> for Error {
18 fn from(_: Infallible) -> Self {
19 unreachable!("this impl is needed to allow passing a known valid partial path as parameter")
20 }
21 }
22}
23
24pub fn name(path: &BStr) -> Result<&BStr, name::Error> {
27 match validate(path, Mode::Complete)? {
28 None => Ok(path),
29 Some(_) => {
30 unreachable!("Without sanitization, there is no chance a sanitized version is returned.")
31 }
32 }
33}
34
35pub fn name_partial(path: &BStr) -> Result<&BStr, name::Error> {
38 match validate(path, Mode::Partial)? {
39 None => Ok(path),
40 Some(_) => {
41 unreachable!("Without sanitization, there is no chance a sanitized version is returned.")
42 }
43 }
44}
45
46pub fn name_partial_or_sanitize(path: &BStr) -> BString {
51 validate(path, Mode::PartialSanitize)
52 .expect("BUG: errors cannot happen as any issue is fixed instantly")
53 .expect("we always rebuild the path")
54}
55
56enum Mode {
57 Complete,
58 Partial,
59 PartialSanitize,
61}
62
63fn validate(path: &BStr, mode: Mode) -> Result<Option<BString>, name::Error> {
64 let out = crate::tag::name_inner(
65 path,
66 match mode {
67 Mode::Complete | Mode::Partial => crate::tag::Mode::Validate,
68 Mode::PartialSanitize => crate::tag::Mode::Sanitize,
69 },
70 )?;
71 if let Mode::Complete = mode {
72 let input = out.as_ref().map_or(path, |b| b.as_bstr());
73 let saw_slash = input.find_byte(b'/').is_some();
74 if !saw_slash && !input.iter().all(|c| c.is_ascii_uppercase() || *c == b'_') {
75 return Err(name::Error::SomeLowercase);
76 }
77 }
78 Ok(out)
79}