Codex Handbook
app-server-client/src/path.rs 58 lines
//! Paths resolved using the app-server host's platform rules.use std::fmt;#[derive(Clone, Debug, PartialEq, Eq)]pub struct AppServerPath(String);impl AppServerPath {    pub fn from_app_server(path: impl Into<String>) -> Self {        Self(path.into())    }    pub fn from_absolute_str(raw: &str) -> Option<Self> {        (raw.starts_with('/') || is_windows_absolute_path(raw)).then(|| Self(raw.to_string()))    }    pub fn as_str(&self) -> &str {        &self.0    }    pub fn components(&self) -> Vec<&str> {        let separators = if is_windows_absolute_path(&self.0) {            &['/', '\\'][..]        } else {            &['/'][..]        };        self.0            .split(separators)            .filter(|part| !part.is_empty())            .collect()    }    pub fn join(&self, segment: impl AsRef<str>) -> Self {        let is_windows = is_windows_absolute_path(&self.0);        let (path, separator) = if is_windows {            (self.0.trim_end_matches(['/', '\\']), '\\')        } else {            (self.0.trim_end_matches('/'), '/')        };        Self(format!("{path}{separator}{}", segment.as_ref()))    }}impl fmt::Display for AppServerPath {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        self.0.fmt(f)    }}fn is_windows_absolute_path(path: &str) -> bool {    let bytes = path.as_bytes();    (bytes.len() >= 3        && bytes[0].is_ascii_alphabetic()        && bytes[1] == b':'        && matches!(bytes[2], b'\\' | b'/'))        || path.starts_with("\\\\")        || path.starts_with("//")}