use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::types::binding::Binding;
use crate::types::capability::Capability;
use crate::types::execution::Execution;
use crate::types::gate::Gate;
use crate::types::goal::Goal;
use crate::types::meta::ObjectMeta;
use crate::types::plan::Plan;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Resource {
Goal(Goal),
Plan(Plan),
Capability(Capability),
Binding(Binding),
Execution(Execution),
Gate(Gate),
}
impl Resource {
pub fn kind(&self) -> &str {
match self {
Resource::Goal(_) => "Goal",
Resource::Plan(_) => "Plan",
Resource::Capability(_) => "Capability",
Resource::Binding(_) => "Binding",
Resource::Execution(_) => "Execution",
Resource::Gate(_) => "Gate",
}
}
pub fn metadata(&self) -> &ObjectMeta {
match self {
Resource::Goal(r) => &r.metadata,
Resource::Plan(r) => &r.metadata,
Resource::Capability(r) => &r.metadata,
Resource::Binding(r) => &r.metadata,
Resource::Execution(r) => &r.metadata,
Resource::Gate(r) => &r.metadata,
}
}
pub fn metadata_mut(&mut self) -> &mut ObjectMeta {
match self {
Resource::Goal(r) => &mut r.metadata,
Resource::Plan(r) => &mut r.metadata,
Resource::Capability(r) => &mut r.metadata,
Resource::Binding(r) => &mut r.metadata,
Resource::Execution(r) => &mut r.metadata,
Resource::Gate(r) => &mut r.metadata,
}
}
pub fn name(&self) -> &str {
&self.metadata().name
}
pub fn namespace(&self) -> &str {
&self.metadata().namespace
}
pub fn api_version(&self) -> &str {
match self {
Resource::Goal(r) => &r.api_version,
Resource::Plan(r) => &r.api_version,
Resource::Capability(r) => &r.api_version,
Resource::Binding(r) => &r.api_version,
Resource::Execution(r) => &r.api_version,
Resource::Gate(r) => &r.api_version,
}
}
}
impl From<Goal> for Resource {
fn from(goal: Goal) -> Self {
Resource::Goal(goal)
}
}
impl From<Plan> for Resource {
fn from(plan: Plan) -> Self {
Resource::Plan(plan)
}
}
impl From<Capability> for Resource {
fn from(capability: Capability) -> Self {
Resource::Capability(capability)
}
}
impl From<Binding> for Resource {
fn from(binding: Binding) -> Self {
Resource::Binding(binding)
}
}
impl From<Execution> for Resource {
fn from(execution: Execution) -> Self {
Resource::Execution(execution)
}
}
impl From<Gate> for Resource {
fn from(gate: Gate) -> Self {
Resource::Gate(gate)
}
}
impl TryFrom<Value> for Resource {
type Error = ResourceParseError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
let kind = value
.get("kind")
.and_then(|k| k.as_str())
.ok_or(ResourceParseError::MissingKind)?;
match kind {
"Goal" => {
let goal: Goal = serde_json::from_value(value)
.map_err(|e| ResourceParseError::DeserializationError(e.to_string()))?;
Ok(Resource::Goal(goal))
}
"Plan" => {
let plan: Plan = serde_json::from_value(value)
.map_err(|e| ResourceParseError::DeserializationError(e.to_string()))?;
Ok(Resource::Plan(plan))
}
"Capability" => {
let capability: Capability = serde_json::from_value(value)
.map_err(|e| ResourceParseError::DeserializationError(e.to_string()))?;
Ok(Resource::Capability(capability))
}
"Binding" => {
let binding: Binding = serde_json::from_value(value)
.map_err(|e| ResourceParseError::DeserializationError(e.to_string()))?;
Ok(Resource::Binding(binding))
}
"Execution" => {
let execution: Execution = serde_json::from_value(value)
.map_err(|e| ResourceParseError::DeserializationError(e.to_string()))?;
Ok(Resource::Execution(execution))
}
"Gate" => {
let gate: Gate = serde_json::from_value(value)
.map_err(|e| ResourceParseError::DeserializationError(e.to_string()))?;
Ok(Resource::Gate(gate))
}
_ => Err(ResourceParseError::UnknownKind(kind.to_string())),
}
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum ResourceParseError {
#[error("missing 'kind' field")]
MissingKind,
#[error("unknown resource kind: {0}")]
UnknownKind(String),
#[error("deserialization error: {0}")]
DeserializationError(String),
}