use serde::{Deserialize, Serialize};
use crate::capability::Capability;
use crate::component::ComponentId;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct ActionId(String);
impl ActionId {
#[must_use]
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ActionKey {
pub component_id: ComponentId,
pub action_id: ActionId,
}
impl ActionKey {
#[must_use]
pub fn canonical_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(32 + self.action_id.as_bytes().len());
bytes.extend_from_slice(self.component_id.as_bytes());
bytes.extend_from_slice(self.action_id.as_bytes());
bytes
}
}
impl Ord for ActionKey {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.component_id
.as_bytes()
.cmp(other.component_id.as_bytes())
.then_with(|| self.action_id.as_bytes().cmp(other.action_id.as_bytes()))
}
}
impl PartialOrd for ActionKey {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct SchemaSource(String);
impl SchemaSource {
#[must_use]
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct ActionDeclaration {
pub id: ActionId,
pub description: String,
pub request_schema: SchemaSource,
pub response_schema: SchemaSource,
pub requirements: Vec<Capability>,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct ActionIncarnation(u64);
impl ActionIncarnation {
#[must_use]
pub const fn new(value: u64) -> Self {
Self(value)
}
#[must_use]
pub const fn ordinal(self) -> u64 {
self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ActionRow {
pub key: ActionKey,
pub component_name: String,
pub description: String,
pub request_schema: SchemaSource,
pub response_schema: SchemaSource,
pub requirements: Vec<Capability>,
pub incarnation: ActionIncarnation,
}
impl ActionRow {
#[must_use]
pub fn dispatch_ordinal(&self) -> u64 {
let mut hasher = blake3::Hasher::new();
hasher.update(b"frame/action-dispatch/v1");
hasher.update(&self.key.canonical_bytes());
hasher.update(&self.incarnation.ordinal().to_le_bytes());
let digest = hasher.finalize();
let mut raw = [0u8; 8];
raw.copy_from_slice(&digest.as_bytes()[..8]);
u64::from_le_bytes(raw)
}
}