#![forbid(unsafe_code)]
#![deny(missing_docs)]
use std::sync::Arc;
use sim_kernel::{Env, Factory, RuntimeObject, Symbol, Value, error::Result};
mod time;
pub use time::{
DeterministicTime, MonotonicClock, MonotonicTimestamp, PlatformTime, SystemWallClock, Timer,
WallClock, WallTimestamp,
};
pub type ProviderId = Symbol;
pub type ServiceId = Symbol;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DeclaredLimit {
pub resource: Symbol,
pub maximum: u64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SanitizedProvenance {
pub provider: ProviderId,
pub service: ServiceId,
pub revision: Option<Symbol>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HostPortCard {
pub service: ServiceId,
pub limits: Vec<DeclaredLimit>,
pub provenance: SanitizedProvenance,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum HostRefusal {
Unsupported,
Denied,
Unavailable,
Suspended,
Invalid,
BudgetExhausted,
Cancelled,
ProviderFault,
}
pub type HostResult<T> = core::result::Result<T, HostRefusal>;
pub trait HostPort: RuntimeObject {
fn host_port_card(&self) -> &HostPortCard;
}
pub fn bind_host_port<P>(
factory: &dyn Factory,
parent: Arc<Env>,
binding: Symbol,
port: Arc<P>,
) -> Result<Env>
where
P: HostPort + 'static,
{
let mut child = Env::child(parent);
let opaque: Arc<dyn RuntimeObject> = port;
child.define(binding, factory.opaque(opaque)?);
Ok(child)
}
pub fn host_port_value(env: &Env, binding: &Symbol) -> Option<Value> {
env.get(binding)
}
#[cfg(test)]
mod tests {
use std::{any::Any, sync::Arc};
use sim_kernel::{Cx, DefaultFactory, Object, ObjectCompat};
use super::*;
struct FictionalPort {
card: HostPortCard,
}
impl Object for FictionalPort {
fn display(&self, _cx: &mut Cx) -> Result<String> {
Ok("#<fictional-host-port>".into())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ObjectCompat for FictionalPort {}
impl HostPort for FictionalPort {
fn host_port_card(&self) -> &HostPortCard {
&self.card
}
}
#[test]
fn fictional_open_ids_bind_as_an_opaque_child_value() {
let provider = Symbol::qualified("fictional-provider", "orbital");
let service = Symbol::qualified("fictional-service", "weather-on-mars");
let port = Arc::new(FictionalPort {
card: HostPortCard {
service: service.clone(),
limits: vec![DeclaredLimit {
resource: Symbol::qualified("calls", "request"),
maximum: 7,
}],
provenance: SanitizedProvenance {
provider: provider.clone(),
service,
revision: Some(Symbol::new("prototype-9")),
},
},
});
let binding = Symbol::qualified("host-port", "weather");
let parent = Arc::new(Env::default());
let child = bind_host_port(&DefaultFactory, parent.clone(), binding.clone(), port)
.expect("opaque binding");
let value = host_port_value(&child, &binding).expect("local port");
let recovered = value
.object()
.downcast_ref::<FictionalPort>()
.expect("domain type remains recoverable");
assert_eq!(recovered.card.provenance.provider, provider);
assert!(parent.get(&binding).is_none());
}
#[test]
fn common_refusal_vocabulary_is_exhaustive_and_mechanical() {
let refusals = [
HostRefusal::Unsupported,
HostRefusal::Denied,
HostRefusal::Unavailable,
HostRefusal::Suspended,
HostRefusal::Invalid,
HostRefusal::BudgetExhausted,
HostRefusal::Cancelled,
HostRefusal::ProviderFault,
];
assert_eq!(refusals.len(), 8);
}
}