use anyhow::{Result, bail}; use strum::IntoStaticStr; use crate::{BytesExt, scheme::{AsScheme, SchemeRef}}; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, IntoStaticStr)] #[strum(serialize_all = "kebab-case")] pub enum SchemeKind { Regular, Search, Archive, Sftp, } impl From for SchemeKind where T: AsScheme, { fn from(value: T) -> Self { match value.as_scheme() { SchemeRef::Regular { .. } => Self::Regular, SchemeRef::Search { .. } => Self::Search, SchemeRef::Archive { .. } => Self::Archive, SchemeRef::Sftp { .. } => Self::Sftp, } } } impl TryFrom<&[u8]> for SchemeKind { type Error = anyhow::Error; fn try_from(value: &[u8]) -> Result { match value { b"regular" => Ok(Self::Regular), b"search" => Ok(Self::Search), b"archive" => Ok(Self::Archive), b"sftp" => Ok(Self::Sftp), _ => bail!("invalid scheme kind: {}", String::from_utf8_lossy(value)), } } } impl SchemeKind { #[inline] pub fn is_local(self) -> bool { match self { Self::Regular | Self::Search => true, Self::Archive | Self::Sftp => false, } } #[inline] pub fn is_remote(self) -> bool { match self { Self::Regular | Self::Search | Self::Archive => false, Self::Sftp => true, } } #[inline] pub fn is_virtual(self) -> bool { match self { Self::Regular | Self::Search => false, Self::Archive | Self::Sftp => true, } } #[inline] pub(super) fn offset(self, tilde: bool) -> usize { 3 + Into::<&str>::into(self).len() + tilde as usize } pub fn parse(bytes: &[u8]) -> Result> { let Some((kind, _)) = bytes.split_seq_once(b"://") else { return Ok(None); }; Ok(Some(if let Some(stripped) = kind.strip_suffix(b"~") { (Self::try_from(stripped)?, true) } else { (Self::try_from(kind)?, false) })) } }