Skip to content

Commit

Permalink
path is finished
Browse files Browse the repository at this point in the history
  • Loading branch information
brunoczim committed Sep 13, 2023
1 parent 4356cb3 commit 43819cd
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 13 deletions.
10 changes: 10 additions & 0 deletions src/location/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ impl Component {
Ok(Self::from_box_unchecked(input))
}

pub fn raw_contents(&self) -> &str {
&self.contents
}

pub(crate) const fn from_ref_unchecked(input: &str) -> &Self {
unsafe { mem::transmute(input) }
}
Expand All @@ -93,3 +97,9 @@ impl TryFrom<Box<str>> for Box<Component> {
Component::parse_boxed(input)
}
}

impl AsRef<Self> for Component {
fn as_ref(&self) -> &Self {
self
}
}
10 changes: 10 additions & 0 deletions src/location/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ impl Id {
Ok(Self::from_box_unchecked(input))
}

pub fn raw_contents(&self) -> &str {
&self.contents
}

pub(crate) const fn from_ref_unchecked(input: &str) -> &Self {
unsafe { mem::transmute(input) }
}
Expand All @@ -81,3 +85,9 @@ impl TryFrom<Box<str>> for Box<Id> {
Id::parse_boxed(input)
}
}

impl AsRef<Self> for Id {
fn as_ref(&self) -> &Self {
self
}
}
137 changes: 124 additions & 13 deletions src/location/path.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use super::component::{Component, InvalidComponent};
use std::{error::Error, fmt, mem, str};
use std::{error::Error, fmt, mem, ops::Deref, str};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InvalidPath {
MissingInitialBar,
InvalidComponent(InvalidComponent),
}

Expand All @@ -16,9 +15,6 @@ impl From<InvalidComponent> for InvalidPath {
impl fmt::Display for InvalidPath {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::MissingInitialBar => {
write!(fmtr, "missing initial bar '/' in path")
},
Self::InvalidComponent(error) => fmt::Display::fmt(error, fmtr),
}
}
Expand All @@ -27,7 +23,6 @@ impl fmt::Display for InvalidPath {
impl Error for InvalidPath {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::MissingInitialBar => None,
Self::InvalidComponent(error) => Some(error),
}
}
Expand All @@ -40,14 +35,13 @@ pub struct Path {
}

impl Path {
pub const ROOT: &Self = Self::from_ref_unchecked("/");
pub const ROOT: &Self = Self::from_ref_unchecked("");

pub fn parse(input: &str) -> Result<&Self, InvalidPath> {
let stripped =
input.strip_prefix("/").ok_or(InvalidPath::MissingInitialBar)?;

for component_str in stripped.split('/') {
Component::parse(component_str)?;
if !input.is_empty() {
for component_str in input.split('/') {
Component::parse(component_str)?;
}
}

Ok(Self::from_ref_unchecked(input))
Expand All @@ -58,12 +52,31 @@ impl Path {
Ok(Self::from_box_uncheckedd(input))
}

pub fn is_root(&self) -> bool {
self.contents.is_empty()
}

pub fn raw_contents(&self) -> &str {
&self.contents
}

pub fn components(&self) -> Components {
let mut inner = self.contents.split('/');
inner.next();
if self.contents.is_empty() {
inner.next();
}
Components { inner }
}

pub fn popped(&self) -> Option<&Self> {
let (popped_str, _) = self.contents.rsplit_once('/')?;
Some(Self::from_ref_unchecked(popped_str))
}

pub fn to_buf(&self) -> PathBuf {
PathBuf { contents: String::from(&self.contents) }
}

pub(crate) const fn from_ref_unchecked(input: &str) -> &Self {
unsafe { mem::transmute(input) }
}
Expand Down Expand Up @@ -98,6 +111,12 @@ impl<'path> IntoIterator for &'path Path {
}
}

impl AsRef<Self> for Path {
fn as_ref(&self) -> &Self {
self
}
}

#[derive(Debug, Clone)]
pub struct Components<'path> {
inner: str::Split<'path, char>,
Expand All @@ -116,3 +135,95 @@ impl<'path> DoubleEndedIterator for Components<'path> {
self.inner.next_back().map(Component::from_ref_unchecked)
}
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PathBuf {
contents: String,
}

impl PathBuf {
pub const ROOT: Self = Self { contents: String::new() };

pub fn as_path(&self) -> &Path {
Path::from_ref_unchecked(&self.contents)
}

pub fn pop(&mut self) -> bool {
if self.is_root() {
false
} else {
let i = self
.contents
.char_indices()
.rfind(|(_, ch)| *ch == '/')
.map(|(i, _)| i)
.unwrap_or(0);
self.contents.replace_range(i .., "");
true
}
}

pub fn push(&mut self, component: &Component) {
if !self.is_root() {
self.contents.push('/');
}
self.contents.push_str(component.raw_contents());
}

pub fn push_str(&mut self, component_str: &str) {
self.try_push_str(component_str)
.expect("could not make a path component of a string")
}

pub fn try_push_str(
&mut self,
component_str: &str,
) -> Result<(), InvalidComponent> {
self.push(Component::parse(component_str)?);
Ok(())
}

pub fn append(mut self, component: &Component) -> Self {
self.push(component);
self
}

pub fn try_append_str(
mut self,
component_str: &str,
) -> Result<Self, InvalidComponent> {
self.try_push_str(component_str)?;
Ok(self)
}

pub fn append_str(mut self, component_str: &str) -> Self {
self.push_str(component_str);
self
}
}

impl<'path> From<&'path Path> for PathBuf {
fn from(path: &'path Path) -> Self {
path.to_buf()
}
}

impl AsRef<Self> for PathBuf {
fn as_ref(&self) -> &Self {
self
}
}

impl AsRef<Path> for PathBuf {
fn as_ref(&self) -> &Path {
self.as_path()
}
}

impl Deref for PathBuf {
type Target = Path;

fn deref(&self) -> &Self::Target {
self.as_path()
}
}

0 comments on commit 43819cd

Please sign in to comment.