1#![allow(async_fn_in_trait)]
4
5use kcl_error::SourceRange;
6use serde::{Deserialize, Serialize};
7
8pub mod sketch;
9
10pub trait LifecycleApi {
11 async fn open_project(&self, project: ProjectId, files: Vec<File>, open_file: FileId) -> Result<()>;
12 async fn add_file(&self, project: ProjectId, file: File) -> Result<()>;
13 async fn remove_file(&self, project: ProjectId, file: FileId) -> Result<()>;
14 async fn update_file(&self, project: ProjectId, file: FileId, text: String) -> Result<()>;
16 async fn switch_file(&self, project: ProjectId, file: FileId) -> Result<()>;
17 async fn refresh(&self, project: ProjectId) -> Result<()>;
18}
19
20#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
21#[ts(export)]
22pub struct SceneGraph {
23 pub project: ProjectId,
24 pub file: FileId,
25 pub version: Version,
26
27 pub objects: Vec<Object>,
28 pub settings: Settings,
29 pub sketch_mode: Option<ObjectId>,
30}
31
32impl SceneGraph {
33 pub fn empty(project: ProjectId, file: FileId, version: Version) -> Self {
34 SceneGraph {
35 project,
36 file,
37 version,
38 objects: Vec::new(),
39 settings: Settings {},
40 sketch_mode: None,
41 }
42 }
43}
44
45#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
46#[ts(export)]
47pub struct SceneGraphDelta {
48 pub new_graph: SceneGraph,
49 pub invalidates_ids: bool,
50}
51
52impl SceneGraphDelta {
53 pub fn new(new_graph: SceneGraph, invalidates_ids: bool) -> Self {
54 SceneGraphDelta {
55 new_graph,
56 invalidates_ids,
57 }
58 }
59}
60
61#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
62#[ts(export)]
63pub struct SourceDelta {}
64
65#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Deserialize, Serialize, ts_rs::TS)]
66#[ts(export, rename = "ApiObjectId")]
67pub struct ObjectId(pub usize);
68
69#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ts_rs::TS)]
70#[ts(export, rename = "ApiVersion")]
71pub struct Version(pub usize);
72
73#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Deserialize, Serialize, ts_rs::TS)]
74#[ts(export, rename = "ApiProjectId")]
75pub struct ProjectId(pub usize);
76
77#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Deserialize, Serialize, ts_rs::TS)]
78#[ts(export, rename = "ApiFileId")]
79pub struct FileId(pub usize);
80
81#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
82#[ts(export, rename = "ApiFile")]
83pub struct File {
84 pub id: FileId,
85 pub path: String,
86 pub text: String,
87}
88
89#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
90#[ts(export, rename = "ApiSettings")]
91pub struct Settings {}
92
93#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
94pub struct Object {
95 pub kind: ObjectKind,
96 pub artifact_id: usize,
97 pub source: SourceRef,
98}
99
100#[allow(clippy::large_enum_variant)]
101#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
102pub enum ObjectKind {
103 Sketch(crate::sketch::Sketch),
104 Segment(crate::sketch::Segment),
105 Constraint,
106 Sweep,
107}
108
109#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
110pub enum Plane {
111 Object(ObjectId),
112 Default,
113}
114
115#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
116pub enum SourceRef {
117 Simple(SourceRange),
118 BackTrace(Vec<SourceRange>),
119}
120
121pub trait Kind: std::fmt::Debug + Clone + ts_rs::TS {}
122
123#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
124#[ts(export)]
125pub struct Number {
126 value: f64,
127 units: NumericSuffix,
128}
129
130impl Kind for Number {}
131
132#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
133#[ts(export)]
134pub enum Expr {
135 Number(Number),
136 Var(Number),
137 Variable(String),
138}
139
140impl Kind for Expr {}
141
142#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
144#[repr(u32)]
145#[ts(export)]
146pub enum NumericSuffix {
147 None,
148 Count,
149 Length,
150 Angle,
151 Mm,
152 Cm,
153 M,
154 Inch,
155 Ft,
156 Yd,
157 Deg,
158 Rad,
159 Unknown,
160}
161
162#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
163#[ts(export)]
164pub struct Error {
165 pub msg: String,
166}
167
168impl Error {
169 pub fn file_id_in_use(id: FileId, path: &str) -> Self {
170 Error {
171 msg: format!("File ID already in use: {id:?}, currently used for `{path}`"),
172 }
173 }
174
175 pub fn bad_project(found: ProjectId, expected: Option<ProjectId>) -> Self {
176 let msg = match expected {
177 Some(expected) => format!("Project ID mismatch found: {found:?}, expected: {expected:?}"),
178 None => format!("No open project, found: {found:?}"),
179 };
180 Error { msg }
181 }
182
183 pub fn bad_version(found: Version, expected: Version) -> Self {
184 Error {
185 msg: format!("Version mismatch found: {found:?}, expected: {expected:?}"),
186 }
187 }
188
189 pub fn bad_file(found: FileId, expected: Option<FileId>) -> Self {
190 let msg = match expected {
191 Some(expected) => format!("File ID mismatch found: {found:?}, expected: {expected:?}"),
192 None => format!("File ID not found: {found:?}"),
193 };
194 Error { msg }
195 }
196
197 pub fn serialize(e: impl serde::ser::Error) -> Self {
198 Error {
199 msg: format!(
200 "Could not serialize successful KCL result. This is a bug in KCL and not in your code, please report this to Zoo. Details: {e}"
201 ),
202 }
203 }
204
205 pub fn deserialize(name: &str, e: impl serde::de::Error) -> Self {
206 Error {
207 msg: format!(
208 "Could not deserialize argument `{name}`. This is a bug in KCL and not in your code, please report this to Zoo. Details: {e}"
209 ),
210 }
211 }
212}
213
214pub type Result<T> = std::result::Result<T, Error>;