use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use std::ffi::{OsStr, OsString};
use pi_atom::Atom;
use crate::FileType;
#[non_exhaustive]
pub enum EntryName {
Native(OsString),
Remote(Atom),
}
impl Clone for EntryName {
fn clone(&self) -> Self {
match self {
Self::Native(name) => Self::Native(name.clone()),
Self::Remote(name) => Self::Remote(name.clone()),
}
}
}
impl fmt::Debug for EntryName {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Native(name) => formatter
.debug_tuple("Native")
.field(name)
.finish(),
Self::Remote(name) => formatter
.debug_tuple("Remote")
.field(&name.as_str())
.finish(),
}
}
}
impl fmt::Display for EntryName {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Native(name) => formatter.write_str(&name.to_string_lossy()),
Self::Remote(name) => formatter.write_str(name.as_str()),
}
}
}
impl PartialEq for EntryName {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Native(left), Self::Native(right)) => left == right,
(Self::Remote(left), Self::Remote(right)) => left == right,
_ => false,
}
}
}
impl Eq for EntryName {}
impl PartialOrd for EntryName {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for EntryName {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Self::Native(left), Self::Native(right)) => left.cmp(right),
(Self::Native(_), Self::Remote(_)) => Ordering::Less,
(Self::Remote(_), Self::Native(_)) => Ordering::Greater,
(Self::Remote(left), Self::Remote(right)) => left.cmp(right),
}
}
}
impl Hash for EntryName {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
match self {
Self::Native(name) => {
0_u8.hash(state);
name.hash(state);
}
Self::Remote(name) => {
1_u8.hash(state);
name.hash(state);
}
}
}
}
impl From<OsString> for EntryName {
fn from(name: OsString) -> Self {
Self::Native(name)
}
}
impl From<&OsStr> for EntryName {
fn from(name: &OsStr) -> Self {
Self::Native(name.to_os_string())
}
}
impl From<Atom> for EntryName {
fn from(name: Atom) -> Self {
Self::Remote(name)
}
}
#[non_exhaustive]
pub struct DirectoryEntry<L> {
pub name: EntryName,
pub locator: L,
pub file_type_hint: Option<FileType>,
}
impl<L> DirectoryEntry<L> {
#[must_use]
pub fn new(name: EntryName, locator: L, file_type_hint: Option<FileType>) -> Self {
Self {
name,
locator,
file_type_hint,
}
}
}
impl<L> Clone for DirectoryEntry<L>
where
L: Clone,
{
fn clone(&self) -> Self {
Self::new(
self.name.clone(),
self.locator.clone(),
self.file_type_hint.clone(),
)
}
}
impl<L> fmt::Debug for DirectoryEntry<L>
where
L: fmt::Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("DirectoryEntry")
.field("name", &self.name)
.field("locator", &self.locator)
.field("file_type_hint", &self.file_type_hint)
.finish()
}
}
impl<L> fmt::Display for DirectoryEntry<L>
where
L: fmt::Display,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{} at {}", self.name, self.locator)?;
match &self.file_type_hint {
Some(file_type) => write!(formatter, ", type hint: {file_type}"),
None => formatter.write_str(", type hint: unavailable"),
}
}
}
impl<L> PartialEq for DirectoryEntry<L>
where
L: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.locator == other.locator
&& self.file_type_hint == other.file_type_hint
}
}
impl<L> Eq for DirectoryEntry<L> where L: Eq {}
impl<L> PartialOrd for DirectoryEntry<L>
where
L: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self.name.cmp(&other.name) {
Ordering::Equal => {}
ordering => return Some(ordering),
}
match self.locator.partial_cmp(&other.locator)? {
Ordering::Equal => self.file_type_hint.partial_cmp(&other.file_type_hint),
ordering => Some(ordering),
}
}
}
impl<L> Ord for DirectoryEntry<L>
where
L: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.name
.cmp(&other.name)
.then_with(|| self.locator.cmp(&other.locator))
.then_with(|| self.file_type_hint.cmp(&other.file_type_hint))
}
}
impl<L> Hash for DirectoryEntry<L>
where
L: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.name.hash(state);
self.locator.hash(state);
self.file_type_hint.hash(state);
}
}