use crate::{windows::WindowsComponents, ParseError};
use std::{
cmp,
convert::TryFrom,
hash::{Hash, Hasher},
};
#[derive(Copy, Clone, Debug, Eq)]
pub struct WindowsPrefixComponent<'a> {
pub(crate) raw: &'a [u8],
pub(crate) parsed: WindowsPrefix<'a>,
}
impl<'a> WindowsPrefixComponent<'a> {
pub fn kind(&self) -> WindowsPrefix<'a> {
self.parsed
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.raw.len()
}
pub fn as_bytes(&self) -> &'a [u8] {
self.raw
}
}
impl<'a> TryFrom<&'a [u8]> for WindowsPrefixComponent<'a> {
type Error = ParseError;
fn try_from(path: &'a [u8]) -> Result<Self, Self::Error> {
let mut components = WindowsComponents::new(path);
let prefix = components
.next()
.and_then(|c| c.prefix())
.ok_or("not a prefix")?;
if components.next().is_some() {
return Err("contains more than prefix");
}
Ok(prefix)
}
}
impl<'a, const N: usize> TryFrom<&'a [u8; N]> for WindowsPrefixComponent<'a> {
type Error = ParseError;
fn try_from(path: &'a [u8; N]) -> Result<Self, Self::Error> {
Self::try_from(path.as_slice())
}
}
impl<'a> TryFrom<&'a str> for WindowsPrefixComponent<'a> {
type Error = ParseError;
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
Self::try_from(s.as_bytes())
}
}
impl<'a> cmp::PartialEq for WindowsPrefixComponent<'a> {
#[inline]
fn eq(&self, other: &WindowsPrefixComponent<'a>) -> bool {
cmp::PartialEq::eq(&self.parsed, &other.parsed)
}
}
impl<'a> cmp::PartialOrd for WindowsPrefixComponent<'a> {
#[inline]
fn partial_cmp(&self, other: &WindowsPrefixComponent<'a>) -> Option<cmp::Ordering> {
cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed)
}
}
impl cmp::Ord for WindowsPrefixComponent<'_> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
cmp::Ord::cmp(&self.parsed, &other.parsed)
}
}
impl Hash for WindowsPrefixComponent<'_> {
fn hash<H: Hasher>(&self, h: &mut H) {
self.parsed.hash(h);
}
}
#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub enum WindowsPrefix<'a> {
Verbatim(&'a [u8]),
VerbatimUNC(&'a [u8], &'a [u8]),
VerbatimDisk(u8),
DeviceNS(&'a [u8]),
UNC(&'a [u8], &'a [u8]),
Disk(u8),
}
impl<'a> TryFrom<&'a [u8]> for WindowsPrefix<'a> {
type Error = ParseError;
fn try_from(path: &'a [u8]) -> Result<Self, Self::Error> {
Ok(WindowsPrefixComponent::try_from(path)?.kind())
}
}
impl<'a, const N: usize> TryFrom<&'a [u8; N]> for WindowsPrefix<'a> {
type Error = ParseError;
fn try_from(path: &'a [u8; N]) -> Result<Self, Self::Error> {
Self::try_from(path.as_slice())
}
}
impl<'a> TryFrom<&'a str> for WindowsPrefix<'a> {
type Error = ParseError;
fn try_from(path: &'a str) -> Result<Self, Self::Error> {
Self::try_from(path.as_bytes())
}
}
impl<'a> WindowsPrefix<'a> {
#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
use self::WindowsPrefix::*;
match *self {
Verbatim(x) => 4 + x.len(),
VerbatimUNC(x, y) => 8 + x.len() + if !y.is_empty() { 1 + y.len() } else { 0 },
VerbatimDisk(_) => 6,
UNC(x, y) => 2 + x.len() + if !y.is_empty() { 1 + y.len() } else { 0 },
DeviceNS(x) => 4 + x.len(),
Disk(_) => 2,
}
}
#[inline]
pub fn is_verbatim(&self) -> bool {
use self::WindowsPrefix::*;
matches!(*self, Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..))
}
}