Skip to main content
Glama

microsandbox

by microsandbox
path_pair.rs7.06 kB
use std::{fmt, str::FromStr}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use typed_path::Utf8UnixPathBuf; use crate::MicrosandboxError; //-------------------------------------------------------------------------------------------------- // Types //-------------------------------------------------------------------------------------------------- /// Represents a path mapping between host and guest systems, following Docker's volume mapping convention. /// /// ## Format /// The path pair can be specified in two formats: /// - `host:guest` - Maps a host path to a different guest path (e.g., "/host/path:/container/path") /// - `path` or `path:path` - Maps the same path on both host and guest (e.g., "/data" or "/data:/data") /// /// ## Examples /// /// Creating path pairs: /// ``` /// use microsandbox_core::config::PathPair; /// use typed_path::Utf8UnixPathBuf; /// /// // Same path on host and guest (/data:/data) /// let same_path = PathPair::with_same("/data".into()); /// /// // Different paths (host /host/data maps to guest /container/data) /// let distinct_paths = PathPair::with_distinct( /// "/host/data".into(), /// "/container/data".into() /// ); /// /// // Parse from string /// let from_str = "/host/data:/container/data".parse::<PathPair>().unwrap(); /// assert_eq!(from_str, distinct_paths); /// ``` #[derive(Debug, Clone, PartialEq, Eq)] pub enum PathPair { /// The guest path and host path are distinct. Distinct { /// The host path. host: Utf8UnixPathBuf, /// The guest path. guest: Utf8UnixPathBuf, }, /// The guest path and host path are the same. Same(Utf8UnixPathBuf), } //-------------------------------------------------------------------------------------------------- // Methods //-------------------------------------------------------------------------------------------------- impl PathPair { /// Creates a new `PathPair` with the same host and guest path. pub fn with_same(path: Utf8UnixPathBuf) -> Self { Self::Same(path) } /// Creates a new `PathPair` with distinct host and guest paths. pub fn with_distinct(host: Utf8UnixPathBuf, guest: Utf8UnixPathBuf) -> Self { Self::Distinct { host, guest } } /// Returns the host path. pub fn get_host(&self) -> &Utf8UnixPathBuf { match self { Self::Distinct { host, .. } | Self::Same(host) => host, } } /// Returns the guest path. pub fn get_guest(&self) -> &Utf8UnixPathBuf { match self { Self::Distinct { guest, .. } | Self::Same(guest) => guest, } } } //-------------------------------------------------------------------------------------------------- // Trait Implementations //-------------------------------------------------------------------------------------------------- impl FromStr for PathPair { type Err = MicrosandboxError; fn from_str(s: &str) -> Result<Self, Self::Err> { if s.is_empty() { return Err(MicrosandboxError::InvalidPathPair(s.to_string())); } if s.contains(':') { let (host, guest) = s.split_once(':').unwrap(); if guest.is_empty() || host.is_empty() { return Err(MicrosandboxError::InvalidPathPair(s.to_string())); } if guest == host { return Ok(Self::Same(host.into())); } else { return Ok(Self::Distinct { host: host.into(), guest: guest.into(), }); } } Ok(Self::Same(s.into())) } } impl fmt::Display for PathPair { /// Formats the path pair following the format "host:guest". fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Distinct { host, guest } => { write!(f, "{}:{}", host, guest) } Self::Same(path) => write!(f, "{}:{}", path, path), } } } impl Serialize for PathPair { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { serializer.serialize_str(&self.to_string()) } } impl<'de> Deserialize<'de> for PathPair { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; Self::from_str(&s).map_err(serde::de::Error::custom) } } //-------------------------------------------------------------------------------------------------- // Tests //-------------------------------------------------------------------------------------------------- #[cfg(test)] mod tests { use super::*; #[test] fn test_path_pair_from_str() { // Test same paths assert_eq!( "/data".parse::<PathPair>().unwrap(), PathPair::Same("/data".into()) ); assert_eq!( "/data:/data".parse::<PathPair>().unwrap(), PathPair::Same("/data".into()) ); // Test distinct paths (host:guest format) assert_eq!( "/host/data:/container/data".parse::<PathPair>().unwrap(), PathPair::Distinct { host: "/host/data".into(), guest: "/container/data".into() } ); // Test invalid formats assert!("".parse::<PathPair>().is_err()); assert!(":".parse::<PathPair>().is_err()); assert!(":/data".parse::<PathPair>().is_err()); assert!("/data:".parse::<PathPair>().is_err()); } #[test] fn test_path_pair_display() { // Test same paths assert_eq!(PathPair::Same("/data".into()).to_string(), "/data:/data"); // Test distinct paths (host:guest format) assert_eq!( PathPair::Distinct { host: "/host/data".into(), guest: "/container/data".into() } .to_string(), "/host/data:/container/data" ); } #[test] fn test_path_pair_getters() { // Test same paths let same = PathPair::Same("/data".into()); assert_eq!(same.get_host().as_str(), "/data"); assert_eq!(same.get_guest().as_str(), "/data"); // Test distinct paths let distinct = PathPair::Distinct { host: "/host/data".into(), guest: "/container/data".into(), }; assert_eq!(distinct.get_host().as_str(), "/host/data"); assert_eq!(distinct.get_guest().as_str(), "/container/data"); } #[test] fn test_path_pair_constructors() { assert_eq!( PathPair::with_same("/data".into()), PathPair::Same("/data".into()) ); assert_eq!( PathPair::with_distinct("/host/data".into(), "/container/data".into()), PathPair::Distinct { host: "/host/data".into(), guest: "/container/data".into() } ); } }

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