1use std::fmt::{self, Display};
2
3use crate::{
4 Docs, Enum, EnumCase, Field, Flag, Flags, Record, Render, RenderOpts, Resource, ResourceFunc,
5 Result_, Tuple, Variant, ident::Ident,
6};
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
11pub enum Type {
12 Bool,
13 U8,
14 U16,
15 U32,
16 U64,
17 S8,
18 S16,
19 S32,
20 S64,
21 F32,
22 F64,
23 Char,
24 String,
25 Borrow(Ident),
26 Option(Box<Type>),
27 Result(Box<Result_>),
28 List(Box<Type>),
29 FixedSizeList(Box<Type>, u32),
30 Tuple(Tuple),
31 Future(Option<Box<Type>>),
32 Stream(Option<Box<Type>>),
33 ErrorContext,
34 Named(Ident),
35}
36
37impl Type {
38 pub fn borrow(name: impl Into<Ident>) -> Self {
39 Type::Borrow(name.into())
40 }
41 pub fn option(type_: Type) -> Self {
42 Type::Option(Box::new(type_))
43 }
44 pub fn result(result: Result_) -> Self {
45 Type::Result(Box::new(result))
46 }
47 pub fn result_ok(type_: Type) -> Self {
48 Type::Result(Box::new(Result_::ok(type_)))
49 }
50 pub fn result_err(type_: Type) -> Self {
51 Type::Result(Box::new(Result_::err(type_)))
52 }
53 pub fn result_both(ok: Type, err: Type) -> Self {
54 Type::Result(Box::new(Result_::both(ok, err)))
55 }
56 pub fn result_empty() -> Self {
57 Type::Result(Box::new(Result_::empty()))
58 }
59 pub fn list(type_: Type) -> Self {
60 Type::List(Box::new(type_))
61 }
62 pub fn fixed_size_list(type_: Type, size: u32) -> Self {
63 Type::FixedSizeList(Box::new(type_), size)
64 }
65 pub fn tuple(types: impl IntoIterator<Item = Type>) -> Self {
66 Type::Tuple(Tuple {
67 types: types.into_iter().collect(),
68 })
69 }
70 pub fn future(type_: Option<Type>) -> Self {
71 Type::Future(type_.map(Box::new))
72 }
73 pub fn stream(type_: Option<Type>) -> Self {
74 Type::Stream(type_.map(Box::new))
75 }
76 pub fn named(name: impl Into<Ident>) -> Self {
77 Type::Named(name.into())
78 }
79}
80impl From<Result_> for Type {
81 fn from(value: Result_) -> Self {
82 Self::result(value)
83 }
84}
85impl From<Tuple> for Type {
86 fn from(value: Tuple) -> Self {
87 Type::Tuple(value)
88 }
89}
90impl From<Ident> for Type {
91 fn from(value: Ident) -> Self {
92 Self::named(value)
93 }
94}
95
96impl Display for Type {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 match self {
99 Type::Bool => write!(f, "bool"),
100 Type::U8 => write!(f, "u8"),
101 Type::U16 => write!(f, "u16"),
102 Type::U32 => write!(f, "u32"),
103 Type::U64 => write!(f, "u64"),
104 Type::S8 => write!(f, "s8"),
105 Type::S16 => write!(f, "s16"),
106 Type::S32 => write!(f, "s32"),
107 Type::S64 => write!(f, "s64"),
108 Type::F32 => write!(f, "f32"),
109 Type::F64 => write!(f, "f64"),
110 Type::Char => write!(f, "char"),
111 Type::String => write!(f, "string"),
112 Type::Named(name) => write!(f, "{name}"),
113 Type::Borrow(type_) => {
114 write!(f, "borrow<{type_}>")
115 }
116 Type::Option(type_) => {
117 write!(f, "option<{type_}>")
118 }
119 Type::Result(result) => result.fmt(f),
120 Type::List(type_) => {
121 write!(f, "list<{type_}>")
122 }
123 Type::FixedSizeList(type_, size) => {
124 write!(f, "list<{type_}, {size}>")
125 }
126 Type::Tuple(tuple) => tuple.fmt(f),
127 Type::Future(None) => {
128 write!(f, "future")
129 }
130 Type::Future(Some(type_)) => {
131 write!(f, "future<{type_}>")
132 }
133 Type::Stream(None) => {
134 write!(f, "stream")
135 }
136 Type::Stream(Some(type_)) => {
137 write!(f, "stream<{type_}>")
138 }
139 Type::ErrorContext => write!(f, "error-context"),
140 }
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
147pub struct VariantCase {
148 name: Ident,
149 #[cfg_attr(feature = "serde", serde(rename = "type"))]
150 type_: Option<Type>,
151 docs: Option<Docs>,
152}
153
154impl VariantCase {
155 pub fn empty(name: impl Into<Ident>) -> Self {
156 Self {
157 name: name.into(),
158 type_: None,
159 docs: None,
160 }
161 }
162
163 pub fn value(name: impl Into<Ident>, ty: Type) -> Self {
164 Self {
165 name: name.into(),
166 type_: Some(ty),
167 docs: None,
168 }
169 }
170
171 pub fn set_name(&mut self, name: impl Into<Ident>) {
172 self.name = name.into();
173 }
174
175 pub fn name(&self) -> &Ident {
176 &self.name
177 }
178
179 pub fn name_mut(&mut self) -> &mut Ident {
180 &mut self.name
181 }
182
183 pub fn type_(&self) -> Option<&Type> {
184 self.type_.as_ref()
185 }
186
187 pub fn type_mut(&mut self) -> &mut Option<Type> {
188 &mut self.type_
189 }
190
191 pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
192 self.docs = docs.map(|d| d.into());
193 }
194
195 pub fn docs(&self) -> &Option<Docs> {
196 &self.docs
197 }
198}
199
200impl<N> Into<VariantCase> for (N,)
201where
202 N: Into<Ident>,
203{
204 fn into(self) -> VariantCase {
205 VariantCase::empty(self.0)
206 }
207}
208
209impl<N> Into<VariantCase> for (N, Type)
210where
211 N: Into<Ident>,
212{
213 fn into(self) -> VariantCase {
214 VariantCase::value(self.0, self.1)
215 }
216}
217
218impl<N, D> Into<VariantCase> for (N, Type, D)
219where
220 N: Into<Ident>,
221 D: Into<Docs>,
222{
223 fn into(self) -> VariantCase {
224 let mut field = VariantCase::value(self.0, self.1);
225 field.set_docs(Some(self.2.into()));
226 field
227 }
228}
229
230#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
231#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
232#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
233pub struct TypeDef {
234 name: Ident,
235 kind: TypeDefKind,
236 docs: Option<Docs>,
237}
238
239impl TypeDef {
240 pub fn new(name: impl Into<Ident>, kind: TypeDefKind) -> Self {
241 TypeDef {
242 name: name.into(),
243 kind,
244 docs: None,
245 }
246 }
247
248 pub fn record(
249 name: impl Into<Ident>,
250 fields: impl IntoIterator<Item = impl Into<Field>>,
251 ) -> Self {
252 TypeDef {
253 name: name.into(),
254 kind: TypeDefKind::record(fields),
255 docs: None,
256 }
257 }
258
259 pub fn resource(
260 name: impl Into<Ident>,
261 funcs: impl IntoIterator<Item = impl Into<ResourceFunc>>,
262 ) -> Self {
263 TypeDef {
264 name: name.into(),
265 kind: TypeDefKind::resource(funcs),
266 docs: None,
267 }
268 }
269
270 pub fn flags(name: impl Into<Ident>, flags: impl IntoIterator<Item = impl Into<Flag>>) -> Self {
271 TypeDef {
272 name: name.into(),
273 kind: TypeDefKind::flags(flags),
274 docs: None,
275 }
276 }
277
278 pub fn variant(
279 name: impl Into<Ident>,
280 cases: impl IntoIterator<Item = impl Into<VariantCase>>,
281 ) -> Self {
282 TypeDef {
283 name: name.into(),
284 kind: TypeDefKind::variant(cases),
285 docs: None,
286 }
287 }
288
289 pub fn enum_(
290 name: impl Into<Ident>,
291 cases: impl IntoIterator<Item = impl Into<EnumCase>>,
292 ) -> Self {
293 TypeDef {
294 name: name.into(),
295 kind: TypeDefKind::enum_(cases),
296 docs: None,
297 }
298 }
299
300 pub fn type_(name: impl Into<Ident>, type_: Type) -> Self {
301 TypeDef {
302 name: name.into(),
303 kind: TypeDefKind::type_(type_),
304 docs: None,
305 }
306 }
307
308 pub fn name(&self) -> &Ident {
309 &self.name
310 }
311
312 pub fn name_mut(&mut self) -> &mut Ident {
313 &mut self.name
314 }
315
316 pub fn kind(&self) -> &TypeDefKind {
317 &self.kind
318 }
319
320 pub fn kind_mut(&mut self) -> &mut TypeDefKind {
321 &mut self.kind
322 }
323
324 pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
325 self.docs = docs.map(|d| d.into());
326 }
327
328 pub fn docs(&self) -> &Option<Docs> {
329 &self.docs
330 }
331}
332
333#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
334#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
335#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
336pub enum TypeDefKind {
337 Record(Record),
338 Resource(Resource),
339 Flags(Flags),
340 Variant(Variant),
341 Enum(Enum),
342 Type(Type),
343}
344
345impl TypeDefKind {
346 pub fn record(fields: impl IntoIterator<Item = impl Into<Field>>) -> Self {
347 Self::Record(Record {
348 fields: fields.into_iter().map(|c| c.into()).collect(),
349 })
350 }
351
352 pub fn resource(funcs: impl IntoIterator<Item = impl Into<ResourceFunc>>) -> Self {
353 Self::Resource(Resource {
354 funcs: funcs.into_iter().map(|f| f.into()).collect(),
355 })
356 }
357
358 pub fn flags(flags: impl IntoIterator<Item = impl Into<Flag>>) -> Self {
359 Self::Flags(Flags {
360 flags: flags.into_iter().map(|f| f.into()).collect(),
361 })
362 }
363
364 pub fn variant(cases: impl IntoIterator<Item = impl Into<VariantCase>>) -> Self {
365 Self::Variant(Variant {
366 cases: cases.into_iter().map(|c| c.into()).collect(),
367 })
368 }
369
370 pub fn enum_(cases: impl IntoIterator<Item = impl Into<EnumCase>>) -> Self {
371 Self::Enum(Enum {
372 cases: cases.into_iter().map(|c| c.into()).collect(),
373 })
374 }
375
376 pub fn type_(type_: Type) -> Self {
377 Self::Type(type_)
378 }
379}
380
381impl Render for TypeDef {
382 fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
383 match &self.kind {
384 TypeDefKind::Record(record) => {
385 if let Some(docs) = &self.docs {
386 docs.render(f, opts)?;
387 }
388 write!(f, "{}record {} {{", opts.spaces(), self.name)?;
389 for (index, field) in record.fields.iter().enumerate() {
390 if index == 0 {
391 write!(f, "\n")?;
392 }
393 let opts = opts.indent();
394 if let Some(docs) = &field.docs {
395 docs.render(f, &opts)?;
396 }
397 write!(f, "{}{}: {},\n", opts.spaces(), field.name, field.type_)?;
398 }
399 write!(f, "{}}}\n", opts.spaces())?;
400 }
401 TypeDefKind::Resource(resource) => {
402 if let Some(docs) = &self.docs {
403 docs.render(f, opts)?;
404 }
405 write!(f, "{}resource {} {{\n", opts.spaces(), self.name)?;
406 for func in &resource.funcs {
407 let opts = opts.indent();
408 if let Some(docs) = &func.docs {
409 docs.render(f, &opts)?;
410 }
411 match &func.kind {
412 crate::ResourceFuncKind::Method(name, async_, result) => {
413 let opt_async = if *async_ { "async " } else { "" };
414 write!(
415 f,
416 "{}{name}: {opt_async}func({})",
417 opts.spaces(),
418 func.params
419 )?;
420 if let Some(ty) = result {
421 write!(f, " -> {ty}")?;
422 }
423 write!(f, ";\n")?;
424 }
425 crate::ResourceFuncKind::Static(name, async_, result) => {
426 let opt_async = if *async_ { "async " } else { "" };
427 write!(
428 f,
429 "{}{name}: static {opt_async}func({})",
430 opts.spaces(),
431 func.params
432 )?;
433 if let Some(ty) = result {
434 write!(f, " -> {ty}")?;
435 }
436 write!(f, ";\n")?;
437 }
438 crate::ResourceFuncKind::Constructor => {
439 write!(f, "{}constructor({});\n", opts.spaces(), func.params)?;
440 }
441 }
442 }
443 write!(f, "{}}}\n", opts.spaces())?;
444 }
445 TypeDefKind::Flags(flags) => {
446 if let Some(docs) = &self.docs {
447 docs.render(f, opts)?;
448 }
449 write!(f, "{}flags {} {{\n", opts.spaces(), self.name)?;
450 for flag in &flags.flags {
451 let opts = opts.indent();
452 if let Some(docs) = &flag.docs {
453 docs.render(f, &opts)?;
454 }
455 write!(f, "{}{},\n", opts.spaces(), flag.name)?;
456 }
457 write!(f, "{}}}\n", opts.spaces())?;
458 }
459 TypeDefKind::Variant(variant) => {
460 if let Some(docs) = &self.docs {
461 docs.render(f, opts)?;
462 }
463 write!(f, "{}variant {} {{\n", opts.spaces(), self.name)?;
464 for case in &variant.cases {
465 let opts = opts.indent();
466 if let Some(docs) = &case.docs {
467 docs.render(f, &opts)?;
468 }
469 match &case.type_ {
470 Some(type_) => {
471 write!(f, "{}{}({}),\n", opts.spaces(), case.name, type_)?;
472 }
473 None => {
474 write!(f, "{}{},\n", opts.spaces(), case.name)?;
475 }
476 }
477 }
478 write!(f, "{}}}\n", opts.spaces())?;
479 }
480 TypeDefKind::Enum(enum_) => {
481 if let Some(docs) = &self.docs {
482 docs.render(f, opts)?;
483 }
484 write!(f, "{}enum {} {{\n", opts.spaces(), self.name)?;
485 for case in &enum_.cases {
486 let opts = opts.indent();
487 if let Some(docs) = &case.docs {
488 docs.render(f, &opts)?;
489 }
490 write!(f, "{}{},\n", opts.spaces(), case.name)?;
491 }
492 write!(f, "{}}}\n", opts.spaces())?;
493 }
494 TypeDefKind::Type(type_) => {
495 if let Some(docs) = &self.docs {
496 docs.render(f, opts)?;
497 }
498 write!(f, "{}type {} = {};\n", opts.spaces(), self.name, type_)?;
499 }
500 }
501 Ok(())
502 }
503}