# Utilities & Patterns This document covers common utilities and patterns used throughout the StartOS codebase. ## Util Module (`core/src/util/`) The `util` module contains reusable utilities. Key submodules: | Module | Purpose | |--------|---------| | `actor/` | Actor pattern implementation for concurrent state management | | `collections/` | Custom collection types | | `crypto.rs` | Cryptographic utilities (encryption, hashing) | | `future.rs` | Future/async utilities | | `io.rs` | File I/O helpers (create_file, canonicalize, etc.) | | `iter.rs` | Iterator extensions | | `net.rs` | Network utilities | | `rpc.rs` | RPC helpers | | `rpc_client.rs` | RPC client utilities | | `serde.rs` | Serialization helpers (Base64, display/fromstr, etc.) | | `sync.rs` | Synchronization primitives (SyncMutex, etc.) | ## Command Invocation (`Invoke` trait) The `Invoke` trait provides a clean way to run external commands with error handling: ```rust use crate::util::Invoke; // Simple invocation tokio::process::Command::new("ls") .arg("-la") .invoke(ErrorKind::Filesystem) .await?; // With timeout tokio::process::Command::new("slow-command") .timeout(Some(Duration::from_secs(30))) .invoke(ErrorKind::Timeout) .await?; // With input let mut input = Cursor::new(b"input data"); tokio::process::Command::new("cat") .input(Some(&mut input)) .invoke(ErrorKind::Filesystem) .await?; // Piped commands tokio::process::Command::new("cat") .arg("file.txt") .pipe(&mut tokio::process::Command::new("grep").arg("pattern")) .invoke(ErrorKind::Filesystem) .await?; ``` ## Guard Pattern Guards ensure cleanup happens when they go out of scope. ### `GeneralGuard` / `GeneralBoxedGuard` For arbitrary cleanup actions: ```rust use crate::util::GeneralGuard; let guard = GeneralGuard::new(|| { println!("Cleanup runs on drop"); }); // Do work... // Explicit drop with action guard.drop(); // Or skip the action // guard.drop_without_action(); ``` ### `FileLock` File-based locking with automatic unlock: ```rust use crate::util::FileLock; let lock = FileLock::new("/path/to/lockfile", true).await?; // blocking=true // Lock held until dropped or explicitly unlocked lock.unlock().await?; ``` ## Mount Guard Pattern (`core/src/disk/mount/guard.rs`) RAII guards for filesystem mounts. Ensures filesystems are unmounted when guards are dropped. ### `MountGuard` Basic mount guard: ```rust use crate::disk::mount::guard::MountGuard; use crate::disk::mount::filesystem::{MountType, ReadOnly}; let guard = MountGuard::mount(&filesystem, "/mnt/target", ReadOnly).await?; // Use the mounted filesystem at guard.path() do_something(guard.path()).await?; // Explicit unmount (or auto-unmounts on drop) guard.unmount(false).await?; // false = don't delete mountpoint ``` ### `TmpMountGuard` Reference-counted temporary mount (mounts to `/media/startos/tmp/`): ```rust use crate::disk::mount::guard::TmpMountGuard; use crate::disk::mount::filesystem::ReadOnly; // Multiple clones share the same mount let guard1 = TmpMountGuard::mount(&filesystem, ReadOnly).await?; let guard2 = guard1.clone(); // Mount stays alive while any guard exists // Auto-unmounts when last guard is dropped ``` ### `GenericMountGuard` trait All mount guards implement this trait: ```rust pub trait GenericMountGuard: std::fmt::Debug + Send + Sync + 'static { fn path(&self) -> &Path; fn unmount(self) -> impl Future> + Send; } ``` ### `SubPath` Wraps a mount guard to point to a subdirectory: ```rust use crate::disk::mount::guard::SubPath; let mount = TmpMountGuard::mount(&filesystem, ReadOnly).await?; let subdir = SubPath::new(mount, "data/subdir"); // subdir.path() returns the full path including subdirectory ``` ## FileSystem Implementations (`core/src/disk/mount/filesystem/`) Various filesystem types that can be mounted: | Type | Description | |------|-------------| | `bind.rs` | Bind mounts | | `block_dev.rs` | Block device mounts | | `cifs.rs` | CIFS/SMB network shares | | `ecryptfs.rs` | Encrypted filesystem | | `efivarfs.rs` | EFI variables | | `httpdirfs.rs` | HTTP directory as filesystem | | `idmapped.rs` | ID-mapped mounts | | `label.rs` | Mount by label | | `loop_dev.rs` | Loop device mounts | | `overlayfs.rs` | Overlay filesystem | ## Other Useful Utilities ### `Apply` / `ApplyRef` traits Fluent method chaining: ```rust use crate::util::Apply; let result = some_value .apply(|v| transform(v)) .apply(|v| another_transform(v)); ``` ### `Container` Async-safe optional container: ```rust use crate::util::Container; let container = Container::new(None); container.set(value).await; let taken = container.take().await; ``` ### `HashWriter` Write data while computing hash: ```rust use crate::util::HashWriter; use sha2::Sha256; let writer = HashWriter::new(Sha256::new(), file); // Write data... let (hasher, file) = writer.finish(); let hash = hasher.finalize(); ``` ### `Never` type Uninhabited type for impossible cases: ```rust use crate::util::Never; fn impossible() -> Never { // This function can never return } let never: Never = impossible(); never.absurd::() // Can convert to any type ``` ### `MaybeOwned<'a, T>` Either borrowed or owned data: ```rust use crate::util::MaybeOwned; fn accept_either(data: MaybeOwned<'_, String>) { // Use &*data to access the value } accept_either(MaybeOwned::from(&existing_string)); accept_either(MaybeOwned::from(owned_string)); ``` ### `new_guid()` Generate a random GUID: ```rust use crate::util::new_guid; let guid = new_guid(); // Returns InternedString ```