// Copyright © 2022 The Radicle Link Contributors // // This file is part of radicle-link, distributed under the GPLv3 with Radicle // Linking Exception. For full terms see the included LICENSE file. use crate::{name, Qualified, RefStr}; /// A literal [`RefStr`]. /// /// Types implementing [`Lit`] must be [`name::Component`]s, and provide a /// conversion from a component _iff_ the component's [`RefStr`] representation /// is equal to [`Lit::NAME`]. Because these morphisms can only be guaranteed /// axiomatically, the trait can not currently be implemented by types outside /// of this crate. /// /// [`Lit`] types are useful for efficiently creating known-valid [`Qualified`] /// refs, and sometimes for pattern matching. pub trait Lit: Sized + sealed::Sealed { const SELF: Self; const NAME: &'static RefStr; #[inline] fn from_component(c: &name::Component) -> Option { (c.as_ref() == Self::NAME).then_some(Self::SELF) } } impl From for &'static RefStr { #[inline] fn from(_: T) -> Self { T::NAME } } mod sealed { pub trait Sealed {} } /// All known literal [`RefStr`]s. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub enum KnownLit { Refs, Heads, Namespaces, Remotes, Tags, Notes, } impl KnownLit { #[inline] pub fn from_component(c: &name::Component) -> Option { let c: &RefStr = c.as_ref(); if c == Refs::NAME { Some(Self::Refs) } else if c == Heads::NAME { Some(Self::Heads) } else if c == Namespaces::NAME { Some(Self::Namespaces) } else if c == Remotes::NAME { Some(Self::Remotes) } else if c == Tags::NAME { Some(Self::Tags) } else if c == Notes::NAME { Some(Self::Notes) } else { None } } } impl From for name::Component<'_> { #[inline] fn from(k: KnownLit) -> Self { match k { KnownLit::Refs => Refs.into(), KnownLit::Heads => Heads.into(), KnownLit::Namespaces => Namespaces.into(), KnownLit::Remotes => Remotes.into(), KnownLit::Tags => Tags.into(), KnownLit::Notes => Notes.into(), } } } /// Either a [`KnownLit`] or a [`name::Component`] pub enum SomeLit<'a> { Known(KnownLit), Any(name::Component<'a>), } impl SomeLit<'_> { pub fn known(self) -> Option { match self { Self::Known(k) => Some(k), _ => None, } } } impl<'a> From> for SomeLit<'a> { #[inline] fn from(c: name::Component<'a>) -> Self { match KnownLit::from_component(&c) { Some(k) => Self::Known(k), None => Self::Any(c), } } } pub type RefsHeads = (Refs, Heads, T); pub type RefsTags = (Refs, Tags, T); pub type RefsNotes = (Refs, Notes, T); pub type RefsRemotes = (Refs, Remotes, T); pub type RefsNamespaces<'a, T> = (Refs, Namespaces, T, Qualified<'a>); #[inline] pub fn refs_heads>(name: T) -> RefsHeads { (Refs, Heads, name) } #[inline] pub fn refs_tags>(name: T) -> RefsTags { (Refs, Tags, name) } #[inline] pub fn refs_notes>(name: T) -> RefsNotes { (Refs, Notes, name) } #[inline] pub fn refs_remotes>(name: T) -> RefsRemotes { (Refs, Remotes, name) } #[inline] pub fn refs_namespaces<'a, 'b, T>(namespace: T, name: Qualified<'b>) -> RefsNamespaces<'b, T> where T: Into>, { (Refs, Namespaces, namespace, name) } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Refs; impl Lit for Refs { const SELF: Self = Self; const NAME: &'static RefStr = name::REFS; } impl sealed::Sealed for Refs {} #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Heads; impl Lit for Heads { const SELF: Self = Self; const NAME: &'static RefStr = name::HEADS; } impl sealed::Sealed for Heads {} #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Namespaces; impl Lit for Namespaces { const SELF: Self = Self; const NAME: &'static RefStr = name::NAMESPACES; } impl sealed::Sealed for Namespaces {} #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Remotes; impl Lit for Remotes { const SELF: Self = Self; const NAME: &'static RefStr = name::REMOTES; } impl sealed::Sealed for Remotes {} #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Tags; impl Lit for Tags { const SELF: Self = Self; const NAME: &'static RefStr = name::TAGS; } impl sealed::Sealed for Tags {} #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Notes; impl Lit for Notes { const SELF: Self = Self; const NAME: &'static RefStr = name::NOTES; } impl sealed::Sealed for Notes {}