///|
/// Describes a normalized filesystem path value.
///
/// `join` accepts a relative path so implementations can preserve their path
/// form without revalidating the result.
pub(open) trait Path {
/// Parses and normalizes a string, raising when it does not match the implementation's absolute or relative form.
fn from_string(String) -> Self raise
/// Returns the normalized filesystem-path string.
fn to_string(Self) -> String
/// Joins a normalized relative path while preserving the receiver's path form.
fn join(Self, RelativePath) -> Self
}
///|
/// A normalized absolute filesystem path.
pub struct AbsolutePath {
/// The normalized absolute path, exposed as a public readonly field.
path : @moon_path.Path
} derive(Debug, Eq)
///|
/// Constructs a normalized absolute path.
pub fn AbsolutePath::AbsolutePath(path : @moon_path.Path) -> AbsolutePath raise {
let normalized = path.normalize()
guard normalized.is_absolute() else { fail("absolute path required") }
{ path: normalized }
}
///|
pub impl Path for AbsolutePath with fn from_string(value) {
AbsolutePath::AbsolutePath(@moon_path.Path(value))
}
///|
pub extend AbsolutePath with Path::{from_string, to_string}
///|
pub impl Path for AbsolutePath with fn to_string(self) {
self.path.to_string()
}
///|
pub impl Path for AbsolutePath with fn join(self, relative) {
// The underlying join normalizes the result. A RelativePath operand preserves
// the absolute form, so rerunning the raising constructor is unnecessary.
AbsolutePath::{ path: self.path.join(relative.path) }
}
///|
pub impl ToJson for AbsolutePath with fn to_json(self) {
self.path.to_string().to_json()
}
///|
pub extend AbsolutePath with ToJson::{to_json}
///|
pub impl @json.FromJson for AbsolutePath with fn from_json(json, path) {
let value : String = @json.from_json(json, path~)
AbsolutePath::from_string(value) catch {
_ => raise @json.JsonDecodeError((path, "absolute path required"))
}
}
///|
/// A normalized relative filesystem path.
pub struct RelativePath {
/// The normalized relative path, exposed as a public readonly field.
path : @moon_path.Path
} derive(Debug, Eq)
///|
/// Constructs a normalized relative path.
pub fn RelativePath::RelativePath(path : @moon_path.Path) -> RelativePath raise {
let normalized = path.normalize()
guard !normalized.is_absolute() else { fail("relative path required") }
{ path: normalized }
}
///|
pub impl Path for RelativePath with fn from_string(value) {
RelativePath::RelativePath(@moon_path.Path(value))
}
///|
pub extend RelativePath with Path::{from_string, to_string}
///|
pub impl Path for RelativePath with fn to_string(self) {
self.path.to_string()
}
///|
pub impl Path for RelativePath with fn join(self, relative) {
// The underlying join normalizes the result. A RelativePath operand preserves
// the relative form, so rerunning the raising constructor is unnecessary.
RelativePath::{ path: self.path.join(relative.path) }
}
///|
pub impl ToJson for RelativePath with fn to_json(self) {
self.path.to_string().to_json()
}
///|
pub extend RelativePath with ToJson::{to_json}
///|
pub impl @json.FromJson for RelativePath with fn from_json(json, path) {
let value : String = @json.from_json(json, path~)
RelativePath::from_string(value) catch {
_ => raise @json.JsonDecodeError((path, "relative path required"))
}
}