From 2348c27d8be6b35ae95b1b2421537f94df34ea88 Mon Sep 17 00:00:00 2001 From: kjuulh Date: Tue, 6 Jan 2026 12:38:25 +0100 Subject: [PATCH] feat: add serialize and deserialize for manifest --- .../examples/kubernetes-like/main.rs | 12 +++++- crates/nocontrol/src/control_plane.rs | 2 - .../src/control_plane/backing_store.rs | 12 +++--- crates/nocontrol/src/lib.rs | 10 +++-- crates/nocontrol/src/manifests.rs | 40 ++++++------------- crates/nocontrol/tests/mod.rs | 12 +++++- 6 files changed, 47 insertions(+), 41 deletions(-) diff --git a/crates/nocontrol/examples/kubernetes-like/main.rs b/crates/nocontrol/examples/kubernetes-like/main.rs index 8441850..5f8a999 100644 --- a/crates/nocontrol/examples/kubernetes-like/main.rs +++ b/crates/nocontrol/examples/kubernetes-like/main.rs @@ -3,7 +3,7 @@ use std::io::{BufRead, Write}; use async_trait::async_trait; use nocontrol::{ manifests::{Manifest, ManifestMetadata, ManifestState}, - Operator, + Operator, Specification, }; use serde::{Deserialize, Serialize}; use tracing_subscriber::EnvFilter; @@ -163,11 +163,19 @@ impl Operator for MyOperator { } } -#[derive(Clone, Serialize)] +#[derive(Clone, Serialize, Deserialize)] pub enum Specifications { Deployment(DeploymentControllerManifest), } +impl Specification for Specifications { + fn kind(&self) -> &'static str { + match self { + Specifications::Deployment(_) => "deployment", + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeploymentControllerManifest { name: String, diff --git a/crates/nocontrol/src/control_plane.rs b/crates/nocontrol/src/control_plane.rs index f620855..aa3f448 100644 --- a/crates/nocontrol/src/control_plane.rs +++ b/crates/nocontrol/src/control_plane.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use tokio_util::sync::CancellationToken; use crate::{ diff --git a/crates/nocontrol/src/control_plane/backing_store.rs b/crates/nocontrol/src/control_plane/backing_store.rs index f7c28c4..48dcdbe 100644 --- a/crates/nocontrol/src/control_plane/backing_store.rs +++ b/crates/nocontrol/src/control_plane/backing_store.rs @@ -1,20 +1,22 @@ use std::sync::Arc; use jiff::ToSpan; -use serde::Serialize; use sha2::{Digest, Sha256}; use tokio::sync::RwLock; -use crate::manifests::{ - Manifest, ManifestLease, ManifestState, ManifestStatus, ManifestStatusState, WorkerId, +use crate::{ + manifests::{ + Manifest, ManifestLease, ManifestState, ManifestStatus, ManifestStatusState, WorkerId, + }, + Specification, }; #[derive(Clone)] -pub struct BackingStore { +pub struct BackingStore { manifests: Arc>>>, } -impl BackingStore { +impl BackingStore { pub fn new() -> Self { Self { manifests: Arc::new(RwLock::new(Vec::new())), diff --git a/crates/nocontrol/src/lib.rs b/crates/nocontrol/src/lib.rs index d61fa44..4b0a47f 100644 --- a/crates/nocontrol/src/lib.rs +++ b/crates/nocontrol/src/lib.rs @@ -2,13 +2,17 @@ mod control_plane; pub mod manifests; pub use control_plane::ControlPlane; -use serde::Serialize; +use serde::{de::DeserializeOwned, Serialize}; -use crate::manifests::{Manifest, ManifestState}; +use crate::manifests::ManifestState; + +pub trait Specification: Clone + Serialize + DeserializeOwned { + fn kind(&self) -> &'static str; +} #[async_trait::async_trait] pub trait Operator { - type Specifications: Clone + Serialize; + type Specifications: Specification; async fn reconcile( &self, diff --git a/crates/nocontrol/src/manifests.rs b/crates/nocontrol/src/manifests.rs index d946ea1..a7af398 100644 --- a/crates/nocontrol/src/manifests.rs +++ b/crates/nocontrol/src/manifests.rs @@ -1,7 +1,13 @@ -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +use crate::Specification; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ManifestState { +#[serde(bound(serialize = "T: Serialize", deserialize = "T: DeserializeOwned"))] +pub struct ManifestState +where + T: Specification, +{ pub manifest: Manifest, pub manifest_hash: Vec, pub generation: u64, @@ -22,7 +28,11 @@ pub struct ManifestLease { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Manifest { +#[serde(bound(serialize = "T: Serialize", deserialize = "T: DeserializeOwned"))] +pub struct Manifest +where + T: Specification, +{ pub name: String, pub metadata: ManifestMetadata, pub spec: T, @@ -53,27 +63,3 @@ pub struct ManifestEvent { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ManifestMetadata {} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "@type")] -pub enum ManifestSpecification { - SchemaApplication {}, -} - -#[cfg(test)] -mod test { - use crate::manifests::*; - - #[test] - fn manifest() -> anyhow::Result<()> { - let manifest = Manifest { - name: "ingest".into(), - metadata: ManifestMetadata {}, - spec: ManifestSpecification::SchemaApplication {}, - }; - - insta::assert_debug_snapshot!(manifest); - - Ok(()) - } -} diff --git a/crates/nocontrol/tests/mod.rs b/crates/nocontrol/tests/mod.rs index 8dea42b..7cd18dc 100644 --- a/crates/nocontrol/tests/mod.rs +++ b/crates/nocontrol/tests/mod.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use nocontrol::{ manifests::{Manifest, ManifestMetadata, ManifestState}, - Operator, + Operator, Specification, }; use serde::{Deserialize, Serialize}; use tracing_test::traced_test; @@ -80,11 +80,19 @@ impl Operator for MyOperator { } } -#[derive(Clone, Serialize)] +#[derive(Clone, Serialize, Deserialize)] pub enum Specifications { Deployment(DeploymentControllerManifest), } +impl Specification for Specifications { + fn kind(&self) -> &'static str { + match self { + Specifications::Deployment(_) => "deployment", + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeploymentControllerManifest { name: String,