use std::collections::BTreeMap;
use vyre_megakernel::{
Artifact, ArtifactValueId, Digest, TargetPayload, TargetPayloadFormat, TargetProfile,
};
use super::BackendError;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DeviceIdentity {
pub backend: &'static str,
pub device: String,
pub generation: u64,
}
pub trait Device: Send + Sync {
fn identity(&self) -> &DeviceIdentity;
fn target_format(&self) -> &TargetPayloadFormat;
fn target_profile(&self) -> &TargetProfile;
fn is_healthy(&self) -> bool;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BoundResource {
Host(Vec<u8>),
Resident(super::Resource),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BindingSet {
artifact: Digest,
resources: BTreeMap<ArtifactValueId, BoundResource>,
invocation_grid: Option<[u32; 3]>,
}
impl BindingSet {
#[must_use]
pub const fn new(artifact: Digest) -> Self {
Self {
artifact,
resources: BTreeMap::new(),
invocation_grid: None,
}
}
#[must_use]
pub const fn artifact(&self) -> Digest {
self.artifact
}
pub fn insert(&mut self, value: ArtifactValueId, resource: BoundResource) {
self.resources.insert(value, resource);
}
#[must_use]
pub const fn resources(&self) -> &BTreeMap<ArtifactValueId, BoundResource> {
&self.resources
}
pub fn set_invocation_grid(&mut self, grid: [u32; 3]) -> Result<(), BackendError> {
if let Some(axis) = grid.iter().position(|extent| *extent == 0) {
return Err(BackendError::InvalidProgram {
fix: format!(
"Fix: invocation grid axis {axis} must be positive, got {}.",
grid[axis]
),
});
}
self.invocation_grid = Some(grid);
Ok(())
}
#[must_use]
pub const fn invocation_grid(&self) -> Option<[u32; 3]> {
self.invocation_grid
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Completion {
pub artifact: Digest,
pub outputs: BTreeMap<ArtifactValueId, Vec<u8>>,
pub retained: BTreeMap<ArtifactValueId, Vec<u8>>,
pub device_ns: Option<u64>,
}
pub trait Submission: Send + Sync {
fn is_ready(&self) -> bool;
fn wait(self: Box<Self>) -> Result<Completion, BackendError>;
}
pub trait ArtifactInstance: Send + Sync {
fn artifact(&self) -> Digest;
fn payload(&self) -> Digest;
fn device(&self) -> &DeviceIdentity;
fn submit(&self, bindings: BindingSet) -> Result<Box<dyn Submission>, BackendError>;
}
pub trait ArtifactMaterializer: Send + Sync {
fn device(&self) -> &dyn Device;
fn allocate_resident(&self, _byte_len: usize) -> Result<super::Resource, BackendError> {
Err(BackendError::UnsupportedFeature {
name: "artifact resident buffer allocation".to_string(),
backend: self.device().identity().backend.to_string(),
})
}
fn upload_resident(
&self,
_resource: &super::Resource,
_bytes: &[u8],
) -> Result<(), BackendError> {
Err(BackendError::UnsupportedFeature {
name: "artifact resident buffer upload".to_string(),
backend: self.device().identity().backend.to_string(),
})
}
fn upload_resident_at(
&self,
resource: &super::Resource,
offset_bytes: usize,
bytes: &[u8],
) -> Result<(), BackendError> {
if offset_bytes == 0 {
return self.upload_resident(resource, bytes);
}
Err(BackendError::UnsupportedFeature {
name: "artifact resident ranged upload".to_string(),
backend: self.device().identity().backend.to_string(),
})
}
fn free_resident(&self, _resource: super::Resource) -> Result<(), BackendError> {
Err(BackendError::UnsupportedFeature {
name: "artifact resident buffer free".to_string(),
backend: self.device().identity().backend.to_string(),
})
}
fn materialize(
&self,
artifact: &Artifact,
payload: &TargetPayload,
) -> Result<Box<dyn ArtifactInstance>, BackendError>;
}