golem_scalajs_wit_bindgen/codegen/
record.rs1use std::fmt::Display;
16
17use color_eyre::Result;
18use convert_case::{Case, Casing};
19use wit_parser::{Field as WitField, Record as WitRecord};
20
21use super::Render;
22use crate::types::{ConcreteName, Type, TypeMap, TypeName};
23
24struct FieldName(String);
26
27impl Display for FieldName {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 write!(f, "{}", self.0)
30 }
31}
32
33impl From<String> for FieldName {
34 fn from(name: String) -> Self {
35 Self(name.to_case(Case::Camel))
36 }
37}
38
39struct Field {
41 name: FieldName,
43
44 ty: Type,
46}
47
48impl Field {
49 pub fn from_wit(field: WitField, type_map: &TypeMap) -> Result<Self> {
51 Ok(Self {
52 name: FieldName::from(field.name),
53 ty: Type::from_wit(field.ty, type_map)?,
54 })
55 }
56}
57
58pub struct Record {
60 name: TypeName,
62
63 fields: Vec<Field>,
65}
66
67impl Record {
68 pub fn from_wit(name: &str, record: &WitRecord, type_map: &TypeMap) -> Result<Self> {
70 let fields: Result<Vec<Field>> = record
71 .clone()
72 .fields
73 .into_iter()
74 .map(|field| Field::from_wit(field, type_map))
75 .collect();
76
77 Ok(Self {
78 name: TypeName::Concrete(ConcreteName::from(name.to_owned())),
79 fields: fields?,
80 })
81 }
82}
83
84impl Render for Record {
85 fn render(self) -> Result<String> {
86 fn render<F>(fields: &[Field], sep: &str, formatter: F) -> String
87 where
88 F: FnMut(&Field) -> String,
89 {
90 fields.iter().map(formatter).collect::<Vec<_>>().join(sep)
91 }
92
93 let fields = render(&self.fields, "\n", |Field { name, ty }| {
94 format!("val {name}: {ty}")
95 });
96
97 let apply_params = render(&self.fields, ", ", |Field { name, ty }| {
98 format!("{name}: {ty}")
99 });
100
101 let apply_temp_vars = render(&self.fields, "\n", |Field { name, ty }| {
102 format!("val {name}0: {ty} = {name}")
103 });
104
105 let new_vars = render(&self.fields, "\n", |Field { name, ty }| {
106 format!("val {name}: {ty} = {name}0")
107 });
108
109 let name = self.name;
110
111 Ok(format!(
112 "
113 sealed trait {name} extends js.Object {{
114 {fields}
115 }}
116 object {name} {{
117 def apply({apply_params}): {name} = {{
118 {apply_temp_vars}
119
120 new {name} {{
121 {new_vars}
122 }}
123 }}
124 }}
125 "
126 ))
127 }
128}