Skip to main content

cadvm_core/
model.rs

1//! Core data types: commits, manifests and file entries.
2
3use std::collections::BTreeMap;
4use std::path::PathBuf;
5
6use cadvm_store::{BlobRef, ObjectId};
7use serde::{Deserialize, Serialize};
8
9use crate::format::CadFormat;
10use crate::mesh::MeshMetadata;
11use crate::step::StepMetadata;
12
13/// Current manifest schema version.
14pub const MANIFEST_VERSION: u32 = 1;
15
16/// The author of a commit (name + optional email).
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub struct Author {
19    pub name: String,
20    pub email: String,
21}
22
23impl Author {
24    /// Human-friendly `Name <email>` form (drops the brackets if no email).
25    pub fn display(&self) -> String {
26        if self.email.is_empty() {
27            self.name.clone()
28        } else {
29            format!("{} <{}>", self.name, self.email)
30        }
31    }
32}
33
34/// A single tracked file inside a [`Manifest`].
35///
36/// (Not `Eq`: mesh metadata carries floating-point bounds.)
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
38pub struct FileEntry {
39    /// Path relative to the repository root.
40    pub path: PathBuf,
41    pub format: CadFormat,
42    /// Hash of the full file content (level-1 dedup key); mirrors `blob_ref.raw_hash`.
43    pub raw_hash: ObjectId,
44    /// Storage layout of the file (raw blob + chunks).
45    pub blob_ref: BlobRef,
46    pub size_bytes: u64,
47    pub line_count: Option<u64>,
48    /// B-Rep (STEP) metadata, when applicable.
49    #[serde(default)]
50    pub step_metadata: Option<StepMetadata>,
51    /// Mesh (STL/OBJ) metadata, when applicable.
52    #[serde(default)]
53    pub mesh_metadata: Option<MeshMetadata>,
54}
55
56/// A point-in-time snapshot of every tracked file, keyed by relative path.
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct Manifest {
59    pub version: u32,
60    pub files: BTreeMap<PathBuf, FileEntry>,
61}
62
63impl Manifest {
64    /// Create an empty manifest at the current schema version.
65    pub fn empty() -> Self {
66        Manifest {
67            version: MANIFEST_VERSION,
68            files: BTreeMap::new(),
69        }
70    }
71
72    /// Number of tracked files.
73    pub fn file_count(&self) -> usize {
74        self.files.len()
75    }
76}
77
78/// A commit: an immutable snapshot pointer plus history metadata.
79///
80/// `id` is the content hash of the serialized commit body (everything *except*
81/// the id itself) and is therefore not persisted inside the commit object — it
82/// is recovered from the storage key on read.
83#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct Commit {
85    pub id: ObjectId,
86    pub parents: Vec<ObjectId>,
87    pub manifest: ObjectId,
88    pub message: String,
89    pub timestamp_unix: i64,
90    /// Commit author. `None` for legacy commits written before authors existed.
91    pub author: Option<Author>,
92}
93
94/// The on-disk, serialized form of a commit (without its self-referential id).
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct CommitBody {
97    pub parents: Vec<ObjectId>,
98    pub manifest: ObjectId,
99    pub message: String,
100    pub timestamp_unix: i64,
101    /// Author; `#[serde(default)]` keeps old author-less commits readable.
102    #[serde(default)]
103    pub author: Option<Author>,
104}
105
106impl Commit {
107    /// Split a commit into its serializable body.
108    pub fn body(&self) -> CommitBody {
109        CommitBody {
110            parents: self.parents.clone(),
111            manifest: self.manifest.clone(),
112            message: self.message.clone(),
113            timestamp_unix: self.timestamp_unix,
114            author: self.author.clone(),
115        }
116    }
117
118    /// Reassemble a full commit from a stored body and its content id.
119    pub fn from_body(id: ObjectId, body: CommitBody) -> Self {
120        Commit {
121            id,
122            parents: body.parents,
123            manifest: body.manifest,
124            message: body.message,
125            timestamp_unix: body.timestamp_unix,
126            author: body.author,
127        }
128    }
129}