use crate::{ExecutionBoundary, SemanticType};
pub const EFFECT_CAPABILITY_REGISTRY_VERSION: u32 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CapabilityId(pub &'static str);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CapabilityOperationId(pub &'static str);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StaticCapabilityPath(pub &'static str);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapabilityOperationKind {
MemberAssignment,
MethodCall,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapabilityValueContract {
String,
SerializableDiagnosticValue,
}
impl CapabilityValueContract {
#[must_use]
pub const fn semantic_type(self) -> Option<SemanticType> {
match self {
Self::String => Some(SemanticType::String),
Self::SerializableDiagnosticValue => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapabilityParameters {
Fixed(&'static [CapabilityValueContract]),
Variadic(CapabilityValueContract),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapabilityResultPolicy {
Void,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArgumentSerializationPolicy {
None,
Structural,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RuntimeCapabilityLowering(pub &'static str);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CapabilitySignature {
pub parameters: CapabilityParameters,
pub result: CapabilityResultPolicy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CapabilityOperation {
pub id: CapabilityOperationId,
pub static_path: StaticCapabilityPath,
pub kind: CapabilityOperationKind,
pub signature: CapabilitySignature,
pub boundary: ExecutionBoundary,
pub argument_serialization: ArgumentSerializationPolicy,
pub runtime_lowering: RuntimeCapabilityLowering,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CapabilityDefinition {
pub id: CapabilityId,
pub root: &'static str,
pub boundary: ExecutionBoundary,
pub operations: &'static [CapabilityOperation],
pub provenance: BuiltinCapabilityProvenance,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BuiltinCapabilityProvenance {
EffectCapabilityRegistryV1,
}
const STRING_PARAMETER: &[CapabilityValueContract] = &[CapabilityValueContract::String];
const STRING_PAIR_PARAMETERS: &[CapabilityValueContract] = &[
CapabilityValueContract::String,
CapabilityValueContract::String,
];
const DOCUMENT_OPERATIONS: &[CapabilityOperation] = &[CapabilityOperation {
id: CapabilityOperationId("builtin.browser.document.title.assign"),
static_path: StaticCapabilityPath("document.title"),
kind: CapabilityOperationKind::MemberAssignment,
signature: CapabilitySignature {
parameters: CapabilityParameters::Fixed(STRING_PARAMETER),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::None,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.document.title.assign"),
}];
const CONSOLE_OPERATIONS: &[CapabilityOperation] = &[
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.console.log"),
static_path: StaticCapabilityPath("console.log"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Variadic(
CapabilityValueContract::SerializableDiagnosticValue,
),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::Structural,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.console.log"),
},
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.console.info"),
static_path: StaticCapabilityPath("console.info"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Variadic(
CapabilityValueContract::SerializableDiagnosticValue,
),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::Structural,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.console.info"),
},
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.console.warn"),
static_path: StaticCapabilityPath("console.warn"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Variadic(
CapabilityValueContract::SerializableDiagnosticValue,
),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::Structural,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.console.warn"),
},
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.console.error"),
static_path: StaticCapabilityPath("console.error"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Variadic(
CapabilityValueContract::SerializableDiagnosticValue,
),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::Structural,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.console.error"),
},
];
const LOCAL_STORAGE_OPERATIONS: &[CapabilityOperation] = &[
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.local_storage.set_item"),
static_path: StaticCapabilityPath("localStorage.setItem"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Fixed(STRING_PAIR_PARAMETERS),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::None,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.local_storage.set_item"),
},
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.local_storage.remove_item"),
static_path: StaticCapabilityPath("localStorage.removeItem"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Fixed(STRING_PARAMETER),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::None,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.local_storage.remove_item"),
},
];
const SESSION_STORAGE_OPERATIONS: &[CapabilityOperation] = &[
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.session_storage.set_item"),
static_path: StaticCapabilityPath("sessionStorage.setItem"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Fixed(STRING_PAIR_PARAMETERS),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::None,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.session_storage.set_item"),
},
CapabilityOperation {
id: CapabilityOperationId("builtin.browser.session_storage.remove_item"),
static_path: StaticCapabilityPath("sessionStorage.removeItem"),
kind: CapabilityOperationKind::MethodCall,
signature: CapabilitySignature {
parameters: CapabilityParameters::Fixed(STRING_PARAMETER),
result: CapabilityResultPolicy::Void,
},
boundary: ExecutionBoundary::Client,
argument_serialization: ArgumentSerializationPolicy::None,
runtime_lowering: RuntimeCapabilityLowering("builtin.browser.session_storage.remove_item"),
},
];
const DEFINITIONS: &[CapabilityDefinition] = &[
CapabilityDefinition {
id: CapabilityId("builtin.browser.document"),
root: "document",
boundary: ExecutionBoundary::Client,
operations: DOCUMENT_OPERATIONS,
provenance: BuiltinCapabilityProvenance::EffectCapabilityRegistryV1,
},
CapabilityDefinition {
id: CapabilityId("builtin.browser.console"),
root: "console",
boundary: ExecutionBoundary::Client,
operations: CONSOLE_OPERATIONS,
provenance: BuiltinCapabilityProvenance::EffectCapabilityRegistryV1,
},
CapabilityDefinition {
id: CapabilityId("builtin.browser.local_storage"),
root: "localStorage",
boundary: ExecutionBoundary::Client,
operations: LOCAL_STORAGE_OPERATIONS,
provenance: BuiltinCapabilityProvenance::EffectCapabilityRegistryV1,
},
CapabilityDefinition {
id: CapabilityId("builtin.browser.session_storage"),
root: "sessionStorage",
boundary: ExecutionBoundary::Client,
operations: SESSION_STORAGE_OPERATIONS,
provenance: BuiltinCapabilityProvenance::EffectCapabilityRegistryV1,
},
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EffectCapabilityRegistry;
impl EffectCapabilityRegistry {
#[must_use]
pub const fn version(self) -> u32 {
EFFECT_CAPABILITY_REGISTRY_VERSION
}
#[must_use]
pub const fn definitions(self) -> &'static [CapabilityDefinition] {
DEFINITIONS
}
#[must_use]
pub fn operation(self, id: CapabilityOperationId) -> Option<&'static CapabilityOperation> {
self.definitions()
.iter()
.flat_map(|definition| definition.operations)
.find(|operation| operation.id == id)
}
#[must_use]
pub fn operation_at(
self,
path: &str,
kind: CapabilityOperationKind,
) -> Option<&'static CapabilityOperation> {
self.definitions()
.iter()
.flat_map(|definition| definition.operations)
.find(|operation| operation.kind == kind && operation.static_path.0 == path)
}
}
pub const EFFECT_CAPABILITY_REGISTRY: EffectCapabilityRegistry = EffectCapabilityRegistry;
#[cfg(test)]
mod tests {
use super::{
CapabilityOperationKind, EFFECT_CAPABILITY_REGISTRY, EFFECT_CAPABILITY_REGISTRY_VERSION,
};
#[test]
fn registry_v1_exposes_only_the_initial_exact_static_operations() {
let registry = EFFECT_CAPABILITY_REGISTRY;
assert_eq!(registry.version(), EFFECT_CAPABILITY_REGISTRY_VERSION);
assert_eq!(registry.definitions().len(), 4);
assert_eq!(
registry
.operation_at("document.title", CapabilityOperationKind::MemberAssignment)
.expect("document title operation")
.id
.0,
"builtin.browser.document.title.assign"
);
assert!(registry
.operation_at("window.console.log", CapabilityOperationKind::MethodCall)
.is_none());
assert!(registry
.operation_at("analytics.track", CapabilityOperationKind::MethodCall)
.is_none());
}
}