use crate::cx::Cx;
use crate::cx::cap::CapSet;
use std::sync::Arc;
pub type WebCaps = CapSet<false, true, false, true, false>;
pub type GrpcCaps = CapSet<true, true, false, true, false>;
pub type BackgroundCaps = CapSet<true, true, false, false, false>;
pub type PureCaps = CapSet<false, false, false, false, false>;
pub type EntropyCaps = CapSet<false, false, true, false, false>;
#[derive(Debug, Clone)]
pub struct WebContext {
cx: Arc<Cx<WebCaps>>,
request_id: u64,
}
impl WebContext {
#[must_use]
pub fn new<Caps>(cx: &Arc<Cx<Caps>>, request_id: u64) -> Self
where
WebCaps: crate::cx::cap::SubsetOf<Caps>,
{
Self {
cx: narrow(cx),
request_id,
}
}
#[must_use]
#[inline]
pub fn cx(&self) -> &Cx<WebCaps> {
&self.cx
}
#[must_use]
#[inline]
pub fn request_id(&self) -> u64 {
self.request_id
}
}
#[derive(Debug, Clone)]
pub struct GrpcContext {
cx: Arc<Cx<GrpcCaps>>,
method: String,
}
impl GrpcContext {
#[must_use]
pub fn new<Caps>(cx: &Arc<Cx<Caps>>, method: String) -> Self
where
GrpcCaps: crate::cx::cap::SubsetOf<Caps>,
{
Self {
cx: narrow(cx),
method,
}
}
#[must_use]
#[inline]
pub fn cx(&self) -> &Cx<GrpcCaps> {
&self.cx
}
#[must_use]
#[inline]
pub fn method(&self) -> &str {
&self.method
}
}
#[derive(Debug, Clone)]
pub struct BackgroundContext {
cx: Arc<Cx<BackgroundCaps>>,
task_name: String,
}
impl BackgroundContext {
#[must_use]
pub fn new<Caps>(cx: &Arc<Cx<Caps>>, task_name: String) -> Self
where
BackgroundCaps: crate::cx::cap::SubsetOf<Caps>,
{
Self {
cx: narrow(cx),
task_name,
}
}
#[must_use]
#[inline]
pub fn cx(&self) -> &Cx<BackgroundCaps> {
&self.cx
}
#[must_use]
#[inline]
pub fn task_name(&self) -> &str {
&self.task_name
}
}
#[must_use]
#[inline]
pub fn narrow<From, To: crate::cx::cap::SubsetOf<From>>(cx: &Arc<Cx<From>>) -> Arc<Cx<To>> {
Arc::new(cx.as_ref().retype::<To>())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cx::cap;
#[test]
fn web_caps_have_time_and_io() {
fn requires_time<C: cap::HasTime>() {}
fn requires_io<C: cap::HasIo>() {}
requires_time::<WebCaps>();
requires_io::<WebCaps>();
}
#[test]
fn web_caps_lack_spawn() {
}
#[test]
fn grpc_caps_have_spawn_time_io() {
fn requires_spawn<C: cap::HasSpawn>() {}
fn requires_time<C: cap::HasTime>() {}
fn requires_io<C: cap::HasIo>() {}
requires_spawn::<GrpcCaps>();
requires_time::<GrpcCaps>();
requires_io::<GrpcCaps>();
}
#[test]
fn background_caps_have_spawn_time() {
fn requires_spawn<C: cap::HasSpawn>() {}
fn requires_time<C: cap::HasTime>() {}
requires_spawn::<BackgroundCaps>();
requires_time::<BackgroundCaps>();
}
#[test]
fn pure_caps_have_nothing() {
let _: PureCaps = cap::None::default();
}
#[test]
fn wrapper_provides_access() {
fn requires_time<C: cap::HasTime>(_: &Cx<C>) {}
fn requires_io<C: cap::HasIo>(_: &Cx<C>) {}
fn requires_spawn<C: cap::HasSpawn>(_: &Cx<C>) {}
let full_cx = Arc::new(Cx::for_testing());
let web = WebContext::new(&full_cx, 7);
let grpc = GrpcContext::new(&full_cx, "svc/method".to_string());
let background = BackgroundContext::new(&full_cx, "worker".to_string());
requires_time(web.cx());
requires_io(web.cx());
requires_time(grpc.cx());
requires_io(grpc.cx());
requires_spawn(grpc.cx());
requires_time(background.cx());
requires_spawn(background.cx());
assert_eq!(web.request_id(), 7);
assert_eq!(grpc.method(), "svc/method");
assert_eq!(background.task_name(), "worker");
assert_eq!(std::mem::size_of::<WebCaps>(), 0);
assert_eq!(std::mem::size_of::<GrpcCaps>(), 0);
assert_eq!(std::mem::size_of::<BackgroundCaps>(), 0);
}
#[test]
fn narrow_preserves_runtime_identity() {
let full_cx = Arc::new(Cx::for_testing());
let web_cx: Arc<Cx<WebCaps>> = narrow(&full_cx);
let grpc_cx: Arc<Cx<GrpcCaps>> = narrow(&full_cx);
assert!(Arc::ptr_eq(&full_cx.inner, &web_cx.inner));
assert!(Arc::ptr_eq(&full_cx.inner, &grpc_cx.inner));
}
}