Skip to main content
Glama

microsandbox

by microsandbox
path_segment.rs8.41 kB
use std::{ ffi::{OsStr, OsString}, fmt::{self, Display}, path::{Component, Path, PathBuf}, str::FromStr, }; use crate::MicrosandboxError; //-------------------------------------------------------------------------------------------------- // Types //-------------------------------------------------------------------------------------------------- /// Represents a single segment of a path. /// /// This struct provides a way to represent and manipulate individual components /// of a path, ensuring they are valid path segments. #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct PathSegment(OsString); //-------------------------------------------------------------------------------------------------- // Methods //-------------------------------------------------------------------------------------------------- impl PathSegment { /// Returns the OS string representation of the segment. pub fn as_os_str(&self) -> &OsStr { &self.0 } /// Returns the bytes representation of the segment. pub fn as_bytes(&self) -> &[u8] { self.as_os_str().as_encoded_bytes() } /// Returns the length of the segment in bytes. pub fn len(&self) -> usize { self.as_bytes().len() } /// Returns `true` if the segment is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } } //-------------------------------------------------------------------------------------------------- // Trait Implementations //-------------------------------------------------------------------------------------------------- impl FromStr for PathSegment { type Err = MicrosandboxError; fn from_str(s: &str) -> Result<Self, Self::Err> { PathSegment::try_from(s) } } impl Display for PathSegment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0.to_string_lossy()) } } impl TryFrom<&str> for PathSegment { type Error = MicrosandboxError; fn try_from(value: &str) -> Result<Self, Self::Error> { if value.is_empty() { return Err(MicrosandboxError::EmptyPathSegment); } #[cfg(unix)] { if value.contains('/') { return Err(MicrosandboxError::InvalidPathComponent(value.to_string())); } } #[cfg(windows)] { if value.contains('/') || value.contains('\\') { return Err(MicrosandboxError::InvalidPathComponent(value.to_string())); } } // At this point the string does not contain any separator characters let mut components = Path::new(value).components(); let component = components .next() .ok_or_else(|| MicrosandboxError::InvalidPathComponent(value.to_string()))?; // Ensure there are no additional components if components.next().is_some() { return Err(MicrosandboxError::InvalidPathComponent(value.to_string())); } match component { Component::Normal(comp) => Ok(PathSegment(comp.to_os_string())), _ => Err(MicrosandboxError::InvalidPathComponent(value.to_string())), } } } impl<'a> TryFrom<Component<'a>> for PathSegment { type Error = MicrosandboxError; fn try_from(component: Component<'a>) -> Result<Self, Self::Error> { PathSegment::try_from(&component) } } impl<'a> TryFrom<&Component<'a>> for PathSegment { type Error = MicrosandboxError; fn try_from(component: &Component<'a>) -> Result<Self, Self::Error> { match component { Component::Normal(component) => Ok(PathSegment(component.to_os_string())), _ => Err(MicrosandboxError::InvalidPathComponent( component.as_os_str().to_string_lossy().into_owned(), )), } } } impl<'a> From<&'a PathSegment> for Component<'a> { fn from(segment: &'a PathSegment) -> Self { Component::Normal(segment.as_os_str()) } } impl From<PathSegment> for PathBuf { #[inline] fn from(segment: PathSegment) -> Self { PathBuf::from(segment.0) } } impl AsRef<[u8]> for PathSegment { #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl AsRef<OsStr> for PathSegment { #[inline] fn as_ref(&self) -> &OsStr { self.as_os_str() } } impl AsRef<Path> for PathSegment { #[inline] fn as_ref(&self) -> &Path { Path::new(self.as_os_str()) } } //-------------------------------------------------------------------------------------------------- // Tests //-------------------------------------------------------------------------------------------------- #[cfg(test)] mod tests { use super::*; #[test] fn test_segment_as_os_str() { let segment = PathSegment::from_str("example").unwrap(); assert_eq!(segment.as_os_str(), OsStr::new("example")); } #[test] fn test_segment_as_bytes() { let segment = PathSegment::from_str("example").unwrap(); assert_eq!(segment.as_bytes(), b"example"); } #[test] fn test_segment_len() { let segment = PathSegment::from_str("example").unwrap(); assert_eq!(segment.len(), 7); } #[test] fn test_segment_display() { let segment = PathSegment::from_str("example").unwrap(); assert_eq!(format!("{}", segment), "example"); } #[test] fn test_segment_try_from_str() { assert!(PathSegment::try_from("example").is_ok()); assert!(PathSegment::from_str("example").is_ok()); assert!("example".parse::<PathSegment>().is_ok()); // Negative cases assert!(PathSegment::from_str("").is_err()); assert!(PathSegment::from_str(".").is_err()); assert!(PathSegment::from_str("..").is_err()); assert!(".".parse::<PathSegment>().is_err()); assert!("..".parse::<PathSegment>().is_err()); assert!("".parse::<PathSegment>().is_err()); assert!(PathSegment::try_from(".").is_err()); assert!(PathSegment::try_from("..").is_err()); assert!(PathSegment::try_from("/").is_err()); assert!(PathSegment::try_from("").is_err()); } #[test] fn test_segment_from_path_segment_to_component() { let segment = PathSegment::from_str("example").unwrap(); assert_eq!( Component::from(&segment), Component::Normal(OsStr::new("example")) ); } #[test] fn test_segment_from_path_segment_to_path_buf() { let segment = PathSegment::from_str("example").unwrap(); assert_eq!(PathBuf::from(segment), PathBuf::from("example")); } #[test] fn test_segment_normal_with_special_characters() { assert!(PathSegment::try_from("file.txt").is_ok()); assert!(PathSegment::try_from("file-name").is_ok()); assert!(PathSegment::try_from("file_name").is_ok()); assert!(PathSegment::try_from("file name").is_ok()); assert!(PathSegment::try_from("file:name").is_ok()); assert!(PathSegment::try_from("file*name").is_ok()); assert!(PathSegment::try_from("file?name").is_ok()); } #[test] #[cfg(unix)] fn test_segment_with_unix_separator() { // On Unix systems, forward slash is the main separator assert!(PathSegment::try_from("file/name").is_err()); assert!(PathSegment::try_from("/").is_err()); assert!(PathSegment::try_from("///").is_err()); assert!(PathSegment::try_from("name/").is_err()); assert!(PathSegment::try_from("/name").is_err()); } #[test] #[cfg(windows)] fn test_segment_with_windows_separators() { // On Windows, both forward slash and backslash are separators assert!(PathSegment::try_from("file\\name").is_err()); assert!(PathSegment::try_from("file/name").is_err()); assert!(PathSegment::try_from("\\").is_err()); assert!(PathSegment::try_from("/").is_err()); assert!(PathSegment::try_from("\\\\\\").is_err()); assert!(PathSegment::try_from("///").is_err()); assert!(PathSegment::try_from("name\\").is_err()); assert!(PathSegment::try_from("name/").is_err()); assert!(PathSegment::try_from("\\name").is_err()); assert!(PathSegment::try_from("/name").is_err()); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/microsandbox/microsandbox'

If you have feedback or need assistance with the MCP directory API, please join our Discord server