use std::{collections::BTreeSet, path::PathBuf, sync::Arc};
use crate::api::Version;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ProviderId(String);
impl ProviderId {
pub fn new(value: impl Into<String>) -> Result<Self, ContractError> {
let value = value.into();
if value.is_empty() || value.len() > 128 || !value.bytes().all(valid_identifier_byte) {
return Err(ContractError::InvalidIdentifier);
}
Ok(Self(value))
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
const fn valid_identifier_byte(byte: u8) -> bool {
byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'-' | b'_')
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Feature(String);
impl Feature {
pub fn new(value: impl Into<String>) -> Result<Self, ContractError> {
let value = value.into();
if value.is_empty() || value.len() > 64 || !value.bytes().all(valid_identifier_byte) {
return Err(ContractError::InvalidFeature);
}
Ok(Self(value))
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExtensionCapability {
pub provider: ProviderId,
pub versions: Vec<Version>,
pub features: BTreeSet<Feature>,
pub hotplug: bool,
pub limits: ExtensionLimits,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExtensionSpec {
pub provider: ProviderId,
pub version: Version,
pub required: bool,
pub required_features: BTreeSet<Feature>,
pub optional_features: BTreeSet<Feature>,
pub config: ExtensionConfig,
pub namespace: Vec<NamespaceEntry>,
pub services: Vec<ServiceRegistration>,
pub memory: Vec<MemoryRequirement>,
pub environment: Vec<(std::ffi::OsString, std::ffi::OsString)>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExtensionConfig {
pub schema: String,
pub bytes: Vec<u8>,
}
impl ExtensionConfig {
#[must_use]
pub fn empty(schema: impl Into<String>) -> Self {
Self {
schema: schema.into(),
bytes: Vec::new(),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Metadata {
pub mode: u32,
pub uid: u32,
pub gid: u32,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum NamespaceEntry {
Directory(DirectoryEntry),
File(FileEntry),
Symlink(SymlinkEntry),
Device(DeviceEntry),
HostBind(HostBindEntry),
Socket(SocketEntry),
Service(ServiceEntry),
}
impl NamespaceEntry {
#[must_use]
pub fn path(&self) -> &std::path::Path {
match self {
Self::Directory(value) => &value.path,
Self::File(value) => &value.path,
Self::Symlink(value) => &value.path,
Self::Device(value) => &value.path,
Self::HostBind(value) => &value.path,
Self::Socket(value) => &value.path,
Self::Service(value) => &value.path,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DirectoryEntry {
pub path: PathBuf,
pub metadata: Metadata,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FileEntry {
pub path: PathBuf,
pub metadata: Metadata,
pub source: FileSource,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FileSource {
Immutable(Arc<[u8]>),
Mutable(Arc<[u8]>),
Shared(SharedBytesId),
Host(PathBuf),
Generated(GeneratorId),
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SharedBytesId(pub u64);
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct GeneratorId(pub u64);
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SymlinkEntry {
pub path: PathBuf,
pub target: PathBuf,
pub uid: u32,
pub gid: u32,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DeviceKind {
Character,
Block,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DeviceEntry {
pub path: PathBuf,
pub metadata: Metadata,
pub kind: DeviceKind,
pub major: u32,
pub minor: u32,
pub service: Option<ServiceId>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BindAccess {
ReadOnly,
ReadWrite,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HostBindEntry {
pub path: PathBuf,
pub host: PathBuf,
pub access: BindAccess,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SocketEntry {
pub path: PathBuf,
pub host: PathBuf,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ServiceEntry {
pub path: PathBuf,
pub metadata: Metadata,
pub service: ServiceId,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ServiceId(pub u64);
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ServiceRegistration {
pub id: ServiceId,
pub operations: BTreeSet<HandleOperation>,
pub max_request_bytes: u32,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum HandleOperation {
Read,
Write,
PositionedIo,
Seek,
Truncate,
Metadata,
Ioctl,
Map,
Poll,
Transfer,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Sharing {
Private,
Shared,
CopyOnWrite,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Inheritance {
Retain,
Duplicate,
Invalidate,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MemoryRequirement {
pub size: u64,
pub alignment: u64,
pub protections: Protections,
pub sharing: Sharing,
pub inheritance: Inheritance,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Protections {
pub read: bool,
pub write: bool,
pub execute: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExtensionSelection {
pub provider: ProviderId,
pub version: Version,
pub features: BTreeSet<Feature>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ExtensionLimits {
pub namespace_entries: u32,
pub services: u32,
pub mappings: u32,
pub queued_events: u32,
pub request_bytes: u32,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ContractError {
InvalidIdentifier,
InvalidFeature,
DuplicateProvider,
}