use super::{
DecodedGuestString, DecodedWorkspacePath, GuestDecodeError, GuestDecodeField, GuestDecodeLimits,
};
use crate::plugin::{CapabilityAtom, PluginCapabilityRef, WitCapability};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DecodedCapabilityRef {
BufferObserve,
BufferProposeEdit,
WorkspaceObserve(DecodedWorkspacePath),
WorkspaceArtifactWrite(DecodedWorkspacePath),
StatusPublish,
}
impl DecodedCapabilityRef {
pub fn from_guest(
capability: &[u8],
path: Option<&[u8]>,
limits: GuestDecodeLimits,
) -> Result<Self, GuestDecodeError> {
let capability_text =
DecodedGuestString::from_bytes(GuestDecodeField::Capability, capability, limits)?;
let capability = WitCapability::try_from(capability_text.as_str()).map_err(|()| {
GuestDecodeError::UnknownCapability {
byte_len: capability_text.byte_len(),
}
})?;
Self::from_atom(capability.atom(), path, limits)
}
#[must_use]
pub const fn as_ref(&self) -> PluginCapabilityRef<'_> {
match self {
Self::BufferObserve => PluginCapabilityRef::BufferObserve,
Self::BufferProposeEdit => PluginCapabilityRef::BufferProposeEdit,
Self::WorkspaceObserve(path) => PluginCapabilityRef::WorkspaceObserve(path.as_ref()),
Self::WorkspaceArtifactWrite(path) => {
PluginCapabilityRef::WorkspaceArtifactWrite(path.as_ref())
}
Self::StatusPublish => PluginCapabilityRef::StatusPublish,
}
}
#[must_use]
pub const fn atom(&self) -> CapabilityAtom {
match self {
Self::BufferObserve => CapabilityAtom::BufferObserve,
Self::BufferProposeEdit => CapabilityAtom::BufferProposeEdit,
Self::WorkspaceObserve(_path) => CapabilityAtom::WorkspaceObserve,
Self::WorkspaceArtifactWrite(_path) => CapabilityAtom::WorkspaceArtifactWrite,
Self::StatusPublish => CapabilityAtom::StatusPublish,
}
}
fn from_atom(
atom: CapabilityAtom,
path: Option<&[u8]>,
limits: GuestDecodeLimits,
) -> Result<Self, GuestDecodeError> {
match atom {
CapabilityAtom::BufferObserve => scalar_capability(atom, path, Self::BufferObserve),
CapabilityAtom::BufferProposeEdit => {
scalar_capability(atom, path, Self::BufferProposeEdit)
}
CapabilityAtom::StatusPublish => scalar_capability(atom, path, Self::StatusPublish),
CapabilityAtom::WorkspaceObserve => Ok(Self::WorkspaceObserve(
workspace_capability_path(atom, path, limits)?,
)),
CapabilityAtom::WorkspaceArtifactWrite => Ok(Self::WorkspaceArtifactWrite(
workspace_capability_path(atom, path, limits)?,
)),
}
}
}
fn scalar_capability(
atom: CapabilityAtom,
path: Option<&[u8]>,
decoded: DecodedCapabilityRef,
) -> Result<DecodedCapabilityRef, GuestDecodeError> {
if path.is_some() {
return Err(GuestDecodeError::UnexpectedWorkspacePath {
capability: atom.shape(),
});
}
Ok(decoded)
}
fn workspace_capability_path(
atom: CapabilityAtom,
path: Option<&[u8]>,
limits: GuestDecodeLimits,
) -> Result<DecodedWorkspacePath, GuestDecodeError> {
let capability = atom.shape();
let path = path.ok_or(GuestDecodeError::MissingWorkspacePath { capability })?;
DecodedWorkspacePath::from_bytes(capability_field(atom), path, limits)
}
const fn capability_field(atom: CapabilityAtom) -> GuestDecodeField {
match atom {
CapabilityAtom::BufferObserve => GuestDecodeField::BufferObservePath,
CapabilityAtom::BufferProposeEdit => GuestDecodeField::BufferProposeEditPath,
CapabilityAtom::WorkspaceObserve => GuestDecodeField::WorkspaceObservePath,
CapabilityAtom::WorkspaceArtifactWrite => GuestDecodeField::WorkspaceArtifactWritePath,
CapabilityAtom::StatusPublish => GuestDecodeField::StatusPublishPath,
}
}