1use kcl_error::SourceRange;
2use schemars::JsonSchema;
3use serde::Deserialize;
4use serde::Serialize;
5
6use crate::ArtifactId;
7use crate::NodePath;
8use crate::NumericSuffix;
9use crate::UnitLength;
10use crate::artifact::PlaneName;
11
12mod sketch;
13pub use sketch::*;
14
15#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize, JsonSchema, ts_rs::TS)]
16#[ts(export, export_to = "FrontendApi.ts", rename = "ApiObjectId")]
17pub struct ObjectId(pub usize);
18
19impl ObjectId {
20 pub fn predecessor(self) -> Option<Self> {
21 self.0.checked_sub(1).map(ObjectId)
22 }
23}
24
25#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
26#[ts(export, export_to = "FrontendApi.ts", rename = "ApiObject")]
27pub struct Object {
28 pub id: ObjectId,
29 pub kind: ObjectKind,
30 pub label: String,
31 pub comments: String,
32 pub artifact_id: ArtifactId,
33 pub source: SourceRef,
34}
35
36impl Object {
37 pub fn placeholder(id: ObjectId, range: SourceRange, node_path: Option<NodePath>) -> Self {
38 Object {
39 id,
40 kind: ObjectKind::Nil,
41 label: Default::default(),
42 comments: Default::default(),
43 artifact_id: ArtifactId::placeholder(),
44 source: SourceRef::new(range, node_path),
45 }
46 }
47}
48
49#[allow(clippy::large_enum_variant)]
50#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
51#[ts(export, export_to = "FrontendApi.ts", rename = "ApiObjectKind")]
52#[serde(tag = "type")]
53pub enum ObjectKind {
54 Nil,
56 Plane(Plane),
57 Face(Face),
58 Wall(Wall),
59 Cap(Cap),
60 Sketch(crate::front::sketch::Sketch),
61 Segment {
64 segment: sketch::Segment,
65 },
66 Constraint {
67 constraint: sketch::Constraint,
68 },
69}
70
71#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
72#[ts(export, export_to = "FrontendApi.ts", rename = "ApiCap")]
73#[serde(rename_all = "camelCase")]
74pub struct Cap {
75 pub id: ObjectId,
76 pub kind: CapKind,
77 #[serde(skip_deserializing)]
78 pub source: CapSource,
79 #[serde(default, skip_serializing_if = "Option::is_none")]
80 #[ts(optional)]
81 pub solid_output_index: Option<usize>,
82}
83
84#[derive(Debug, Clone, Default, PartialEq, Serialize, ts_rs::TS, JsonSchema)]
85#[ts(export, export_to = "FrontendApi.ts", rename = "ApiCapSource")]
86#[serde(rename_all = "camelCase")]
87pub struct CapSource {
88 pub solid: SourceRefRange,
89 pub sweep: SourceRefRange,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
93#[ts(export, export_to = "FrontendApi.ts", rename = "ApiCapKind")]
94#[serde(rename_all = "camelCase")]
95pub enum CapKind {
96 Start,
97 End,
98}
99
100#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
101#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSourceRef")]
102#[serde(tag = "type")]
103pub enum SourceRef {
104 Simple {
105 range: SourceRange,
106 node_path: Option<NodePath>,
107 },
108 BackTrace {
109 ranges: Vec<(SourceRange, Option<NodePath>)>,
110 },
111}
112
113impl SourceRef {
114 pub fn new(range: SourceRange, node_path: Option<NodePath>) -> Self {
115 Self::Simple { range, node_path }
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
120#[ts(export, export_to = "FrontendApi.ts", rename = "ApiPlane")]
121#[serde(rename_all = "camelCase")]
122pub enum Plane {
123 Object(ObjectId),
124 Default(PlaneName),
125 PrimitiveFace(PrimitiveFacePlane),
126}
127
128#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
131#[ts(export, export_to = "FrontendApi.ts")]
132#[serde(rename_all = "camelCase")]
133pub struct PrimitiveFacePlane {
134 pub solid_id: uuid::Uuid,
136 pub index: usize,
137}
138
139#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
140#[ts(export, export_to = "FrontendApi.ts", rename = "ApiFace")]
141#[serde(rename_all = "camelCase")]
142pub struct Face {
143 pub id: ObjectId,
144}
145
146#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
147#[ts(export, export_to = "FrontendApi.ts", rename = "ApiWall")]
148#[serde(rename_all = "camelCase")]
149pub struct Wall {
150 pub id: ObjectId,
151 #[serde(skip_deserializing)]
152 pub source: WallSource,
153 #[serde(default, skip_serializing_if = "Option::is_none")]
154 #[ts(optional)]
155 pub solid_output_index: Option<usize>,
156}
157
158#[derive(Debug, Clone, Default, PartialEq, Serialize, ts_rs::TS, JsonSchema)]
159#[ts(export, export_to = "FrontendApi.ts", rename = "ApiWallSource")]
160#[serde(rename_all = "camelCase")]
161pub struct WallSource {
162 pub solid: SourceRefRange,
163 pub sweep: SourceRefRange,
164 #[serde(default, skip_serializing_if = "Option::is_none")]
165 #[ts(optional)]
166 pub path: Option<SourceRefRange>,
167 pub segment: SourceRefRange,
168}
169
170#[derive(Debug, Clone, Default, PartialEq, Serialize, ts_rs::TS, JsonSchema)]
171#[ts(export, export_to = "FrontendApi.ts", rename = "ApiSourceRefRange")]
172#[serde(rename_all = "camelCase")]
173pub struct SourceRefRange {
174 pub range: SourceRange,
175 pub node_path: Option<NodePath>,
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
179#[ts(export, export_to = "FrontendApi.ts")]
180pub struct Number {
181 pub value: f64,
182 pub units: NumericSuffix,
183}
184
185#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
186#[ts(export, export_to = "FrontendApi.ts")]
187#[serde(tag = "type")]
188pub enum Expr {
189 Number(Number),
190 Var(Number),
191 Variable(String),
192}
193
194impl From<SourceRange> for SourceRef {
195 fn from(value: SourceRange) -> Self {
196 Self::Simple {
197 range: value,
198 node_path: None,
199 }
200 }
201}
202
203impl From<(f64, UnitLength)> for Number {
204 fn from((value, units): (f64, UnitLength)) -> Self {
205 let units_suffix = NumericSuffix::from(units);
207 Number {
208 value,
209 units: units_suffix,
210 }
211 }
212}