summaryrefslogtreecommitdiffstats
path: root/vendor/gix-validate/src/reference.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-validate/src/reference.rs')
-rw-r--r--vendor/gix-validate/src/reference.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/vendor/gix-validate/src/reference.rs b/vendor/gix-validate/src/reference.rs
new file mode 100644
index 000000000..eb1f25a81
--- /dev/null
+++ b/vendor/gix-validate/src/reference.rs
@@ -0,0 +1,75 @@
+///
+pub mod name {
+ use std::convert::Infallible;
+
+ /// The error used in [name()][super::name()] and [name_partial()][super::name_partial()]
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("A reference must be a valid tag name as well")]
+ Tag(#[from] crate::tag::name::Error),
+ #[error("Standalone references must be all uppercased, like 'HEAD'")]
+ SomeLowercase,
+ #[error("A reference name must not start with a slash '/'")]
+ StartsWithSlash,
+ #[error("Multiple slashes in a row are not allowed as they may change the reference's meaning")]
+ RepeatedSlash,
+ #[error("Names must not be a single '.', but may contain it.")]
+ SingleDot,
+ }
+
+ impl From<Infallible> for Error {
+ fn from(_: Infallible) -> Self {
+ unreachable!("this impl is needed to allow passing a known valid partial path as parameter")
+ }
+ }
+}
+
+use bstr::BStr;
+
+/// Validate a reference name running all the tests in the book. This disallows lower-case references, but allows
+/// ones like `HEAD`.
+pub fn name(path: &BStr) -> Result<&BStr, name::Error> {
+ validate(path, Mode::Complete)
+}
+
+/// Validate a partial reference name. As it is assumed to be partial, names like `some-name` is allowed
+/// even though these would be disallowed with when using [`name()`].
+pub fn name_partial(path: &BStr) -> Result<&BStr, name::Error> {
+ validate(path, Mode::Partial)
+}
+
+enum Mode {
+ Complete,
+ Partial,
+}
+
+fn validate(path: &BStr, mode: Mode) -> Result<&BStr, name::Error> {
+ crate::tagname(path)?;
+ if path[0] == b'/' {
+ return Err(name::Error::StartsWithSlash);
+ }
+ let mut previous = 0;
+ let mut one_before_previous = 0;
+ let mut saw_slash = false;
+ for byte in path.iter() {
+ match *byte {
+ b'/' if previous == b'.' && one_before_previous == b'/' => return Err(name::Error::SingleDot),
+ b'/' if previous == b'/' => return Err(name::Error::RepeatedSlash),
+ _ => {}
+ }
+
+ if *byte == b'/' {
+ saw_slash = true;
+ }
+ one_before_previous = previous;
+ previous = *byte;
+ }
+
+ if let Mode::Complete = mode {
+ if !saw_slash && !path.iter().all(|c| c.is_ascii_uppercase() || *c == b'_') {
+ return Err(name::Error::SomeLowercase);
+ }
+ }
+ Ok(path)
+}