1use crate::default_common::{discriminator_default_value, resolve_alias};
26use crate::encode::EncodeError;
27use crate::fixed_literal::fixed_text;
28use zerodds_ast::{
29 Ast, ConstExpr, Literal as AstLiteral, MemberNode, PrimitiveKind, TypeKind, TypeNode,
30};
31use zerodds_ast_core::Id;
32use zerodds_lang_cst::common::{Ident, Literal, Path};
33use zerodds_lang_cst::rust;
34
35const MAX_DEPTH: usize = 64;
37
38pub fn member_default(
51 ast: &Ast,
52 from: Id<zerodds_ast::ModuleNode>,
53 node: &MemberNode,
54 type_: Id<TypeNode>,
55) -> Result<rust::Expr, EncodeError> {
56 if node.facets.is_optional() {
62 return Ok(rust::Expr::Path(Path::single("None")));
63 }
64 let value = member_value_default(ast, from, node, type_)?;
65 Ok(crate::adapter::cst::external_value(ast, node, value))
66}
67
68pub(crate) fn member_value_default(
71 ast: &Ast,
72 from: Id<zerodds_ast::ModuleNode>,
73 node: &MemberNode,
74 type_: Id<TypeNode>,
75) -> Result<rust::Expr, EncodeError> {
76 match node.facets.xtypes.as_ref().and_then(|x| x.default_value) {
77 Some(expr) => explicit(ast, expr, type_, &node.name),
78 None => default_of(ast, from, type_, &node.name),
79 }
80}
81
82pub fn default_of(
87 ast: &Ast,
88 from: Id<zerodds_ast::ModuleNode>,
89 type_: Id<TypeNode>,
90 at: &str,
91) -> Result<rust::Expr, EncodeError> {
92 at_depth(ast, from, type_, at, 0)
93}
94
95#[allow(clippy::too_many_lines)]
99fn at_depth(
100 ast: &Ast,
101 from: Id<zerodds_ast::ModuleNode>,
102 type_: Id<TypeNode>,
103 at: &str,
104 depth: usize,
105) -> Result<rust::Expr, EncodeError> {
106 let refuse = |kind: &'static str| EncodeError::NoWriter {
107 member: at.to_string(),
108 kind,
109 };
110 if depth > MAX_DEPTH {
111 return Err(refuse(
112 "type whose default nests deeper than an acyclic model can",
113 ));
114 }
115 let node = ast.type_(type_).map_err(|error| EncodeError::NoLayout {
116 detail: format!("{error}"),
117 })?;
118 Ok(match &node.kind {
119 TypeKind::Primitive(kind) => primitive_default(*kind),
120 TypeKind::String { .. } => call_path(&["String", "new"]),
122 TypeKind::Fixed { scale, .. } => {
126 let text = if *scale == 0 {
127 String::from("0")
128 } else {
129 format!("0.{}", "0".repeat(usize::from(*scale)))
130 };
131 rust::Expr::MethodCall {
132 receiver: Box::new(rust::Expr::Literal(Literal::string(&text))),
133 method: Ident::new("to_string"),
134 args: Vec::new(),
135 }
136 }
137 TypeKind::Alias { aliased } => {
138 let target = aliased
139 .resolved()
140 .ok_or_else(|| refuse("unresolved typedef"))?;
141 at_depth(ast, from, target, at, depth + 1)?
142 }
143 TypeKind::Enumeration { .. } => {
146 let variant = default_enumerator(ast, type_)
147 .ok_or_else(|| refuse("enumeration with no enumerator to take as its default"))?;
148 let path = crate::adapter::cst::relative_path(ast, from, node)
151 .map_err(|_| refuse("an enumeration the model has no module for"))?;
152 let mut segments: Vec<String> = path
153 .segments()
154 .iter()
155 .map(|s| s.as_str().to_string())
156 .collect();
157 segments.push(variant.clone());
158 let borrowed: Vec<&str> = segments.iter().map(String::as_str).collect();
159 rust::Expr::Path(Path::new(&borrowed))
160 }
161 TypeKind::Bitmask { .. } => rust::Expr::Literal(Literal::int(0)),
164 TypeKind::Bitset { .. } => {
174 let mut fields = Vec::new();
175 for field in &ast.all_bitfields_of(type_) {
176 let field_node = ast
180 .bitfield(*field)
181 .map_err(|_| refuse("bitset with a stale bitfield handle"))?;
182 let Some(field_name) = field_node.name.as_ref() else {
186 continue;
187 };
188 fields.push((
189 Ident::new(&rust::escape_keyword(field_name)),
190 rust::Expr::Literal(Literal::int(0)),
191 ));
192 }
193 rust::Expr::StructLit {
194 path: crate::adapter::cst::relative_path(ast, from, node)
195 .map_err(|_| refuse("a bitset the model has no module for"))?,
196 fields,
197 base: None,
198 }
199 }
200 TypeKind::Sequence { .. } => call_path(&["Vec", "new"]),
202 TypeKind::Map { .. } => match crate::adapter::cst::rust_map_form() {
209 crate::adapter::cst::RustMapForm::BTreeMap => call_path(&["BTreeMap", "new"]),
210 crate::adapter::cst::RustMapForm::Entries => call_path(&["Vec", "new"]),
211 },
212 TypeKind::Array { element, dims } => {
215 let element = element
216 .resolved()
217 .ok_or_else(|| refuse("unresolved array element"))?;
218 let mut expression = at_depth(ast, from, element, at, depth + 1)?;
219 let copyable = matches!(
228 ast.type_(element).ok().map(|node| &node.kind),
229 Some(TypeKind::Primitive(_))
230 );
231 for dim in dims.iter().rev() {
232 let count = ast
233 .eval_integral(*dim)
234 .map_err(|_| refuse("array whose length does not evaluate"))?;
235 expression = if copyable {
236 rust::Expr::Repeat {
237 value: Box::new(expression),
238 count: Box::new(rust::Expr::Literal(Literal::int(count))),
239 }
240 } else {
241 let count = usize::try_from(count)
242 .map_err(|_| refuse("array whose length does not fit a usize"))?;
243 rust::Expr::Array(vec![expression.clone(); count])
244 };
245 }
246 expression
247 }
248 TypeKind::Structure { .. } | TypeKind::Valuetype { .. } => {
249 let mut fields = Vec::new();
250 if let Some(base) = crate::adapter::c::struct_base(ast, type_) {
252 fields.push((
253 Ident::new(crate::adapter::cst::PARENT),
254 at_depth(ast, from, base, crate::adapter::cst::PARENT, depth + 1)?,
255 ));
256 }
257 for member in ast.members_of(type_) {
258 let Ok(member_node) = ast.member(*member) else {
259 continue;
260 };
261 let member_type = member_node
262 .type_
263 .resolved()
264 .ok_or_else(|| refuse("member with an unresolved type"))?;
265 let value = if member_node.facets.is_optional() {
272 rust::Expr::Path(Path::single("None"))
273 } else {
274 let value = match member_node
275 .facets
276 .xtypes
277 .as_ref()
278 .and_then(|x| x.default_value)
279 {
280 Some(expr) => explicit(ast, expr, member_type, &member_node.name)?,
281 None => at_depth(ast, from, member_type, &member_node.name, depth + 1)?,
282 };
283 crate::adapter::cst::external_value(ast, member_node, value)
284 };
285 fields.push((Ident::new(&rust::escape_keyword(&member_node.name)), value));
286 }
287 rust::Expr::StructLit {
288 path: crate::adapter::cst::relative_path(ast, from, node)
289 .map_err(|_| refuse("a struct the model has no module for"))?,
290 fields,
291 base: None,
292 }
293 }
294 TypeKind::Union { .. } => {
304 let shape = crate::rust_union::shape(ast, type_).map_err(refuse)?;
305 let selector = discriminator_default_value(ast, shape.discriminator)
306 .ok_or_else(|| refuse("union whose discriminator has no default value"))?;
307 let discriminator_value =
308 crate::rust_union::label_literal(ast, from, shape.kind, selector)
309 .map_err(refuse)?
310 .expr();
311 let path = crate::adapter::cst::relative_path(ast, from, node)
312 .map_err(|_| refuse("a union the model has no module for"))?;
313 let mut segments: Vec<String> = path
314 .segments()
315 .iter()
316 .map(|s| s.as_str().to_string())
317 .collect();
318 let selected = shape
319 .cases
320 .iter()
321 .find(|case| case.labels.contains(&selector))
322 .or_else(|| shape.cases.iter().find(|case| case.is_default));
323 let args = match selected {
324 Some(case) => {
325 let member = case.member;
326 let member_type = member
327 .type_
328 .resolved()
329 .ok_or_else(|| refuse("union case with an unresolved type"))?;
330 segments.push(case.variant.clone());
331 let mut args = Vec::new();
332 if case.carries_discriminator() {
333 args.push(discriminator_value);
334 }
335 args.push(crate::adapter::cst::external_value(
336 ast,
337 member,
338 at_depth(ast, from, member_type, &member.name, depth + 1)?,
339 ));
340 args
341 }
342 None => {
343 segments.push(crate::rust_union::NO_MEMBER.to_string());
344 vec![discriminator_value]
345 }
346 };
347 let borrowed: Vec<&str> = segments.iter().map(String::as_str).collect();
348 rust::Expr::Call {
349 callee: Box::new(rust::Expr::Path(Path::new(&borrowed))),
350 args,
351 }
352 }
353 other => {
354 let _ = other;
355 return Err(refuse("type with no default value in this column"));
356 }
357 })
358}
359
360fn primitive_default(kind: PrimitiveKind) -> rust::Expr {
362 match kind {
363 PrimitiveKind::Boolean => rust::Expr::Literal(Literal::Bool(false)),
364 PrimitiveKind::Char | PrimitiveKind::WChar => rust::Expr::Literal(Literal::Char('\0')),
366 PrimitiveKind::Float32 => rust::Expr::Literal(Literal::Float(String::from("0.0f32"))),
367 PrimitiveKind::Float64 => rust::Expr::Literal(Literal::Float(String::from("0.0f64"))),
368 PrimitiveKind::Float128 => rust::Expr::Path(Path::new(&["Float128", "ZERO"])),
369 PrimitiveKind::Octet
370 | PrimitiveKind::UInt8
371 | PrimitiveKind::Int8
372 | PrimitiveKind::Int16
373 | PrimitiveKind::UInt16
374 | PrimitiveKind::Int32
375 | PrimitiveKind::UInt32
376 | PrimitiveKind::Int64
377 | PrimitiveKind::UInt64 => rust::Expr::Literal(Literal::int(0)),
378 }
379}
380
381fn default_enumerator(ast: &Ast, type_: Id<TypeNode>) -> Option<String> {
383 let mut first = None;
384 for enumerator in ast.enumerators_of(type_) {
385 let Ok(node) = ast.enumerator(*enumerator) else {
386 continue;
387 };
388 let variant = rust::escape_keyword(&node.name);
389 if node
390 .facets
391 .xtypes
392 .as_ref()
393 .is_some_and(|x| x.is_default_literal)
394 {
395 return Some(variant);
396 }
397 if first.is_none() {
398 first = Some(variant);
399 }
400 }
401 first
402}
403
404fn explicit(
406 ast: &Ast,
407 expr: Id<zerodds_ast::ConstExprNode>,
408 type_: Id<TypeNode>,
409 member_name: &str,
410) -> Result<rust::Expr, EncodeError> {
411 let refuse = |kind: &'static str| EncodeError::NoWriter {
412 member: member_name.to_string(),
413 kind,
414 };
415 let node = ast
416 .expr(expr)
417 .map_err(|_| refuse("a `@default` this frontend cannot follow"))?;
418 let resolved = resolve_alias(ast, type_);
419 Ok(match &node.expr {
420 ConstExpr::Literal(AstLiteral::Boolean(flag)) => rust::Expr::Literal(Literal::Bool(*flag)),
421 ConstExpr::Literal(AstLiteral::Char(ch)) => rust::Expr::Literal(Literal::Char(*ch)),
422 ConstExpr::Literal(AstLiteral::WChar(code)) => {
423 let ch = char::from_u32(*code)
424 .ok_or_else(|| refuse("a `@default` wide character that is not a code point"))?;
425 rust::Expr::Literal(Literal::Char(ch))
426 }
427 ConstExpr::Literal(AstLiteral::String(text)) => rust::Expr::MethodCall {
428 receiver: Box::new(rust::Expr::Literal(Literal::string(text))),
429 method: Ident::new("to_string"),
430 args: Vec::new(),
431 },
432 ConstExpr::Literal(AstLiteral::WString(codes)) => {
433 let mut text = String::new();
434 for code in codes {
435 let ch = char::from_u32(*code)
436 .ok_or_else(|| refuse("a `@default` wide string that is not code points"))?;
437 text.push(ch);
438 }
439 rust::Expr::MethodCall {
440 receiver: Box::new(rust::Expr::Literal(Literal::string(&text))),
441 method: Ident::new("to_string"),
442 args: Vec::new(),
443 }
444 }
445 ConstExpr::Literal(AstLiteral::Float {
446 mantissa,
447 exponent: None,
448 }) => rust::Expr::Literal(Literal::Float(mantissa.clone())),
449 ConstExpr::Literal(AstLiteral::Float {
450 mantissa,
451 exponent: Some(exponent),
452 }) => rust::Expr::Literal(Literal::Float(format!("{mantissa}e{exponent}"))),
453 ConstExpr::Literal(AstLiteral::Fixed { digits, scale }) => rust::Expr::MethodCall {
454 receiver: Box::new(rust::Expr::Literal(Literal::string(&fixed_text(
455 digits, *scale,
456 )))),
457 method: Ident::new("to_string"),
458 args: Vec::new(),
459 },
460 ConstExpr::Literal(AstLiteral::Enumerator(reference)) => {
461 let target = reference
462 .resolved()
463 .ok_or_else(|| refuse("a `@default` enumerator that is unresolved"))?;
464 let enumerator = ast
465 .enumerator(target)
466 .map_err(|_| refuse("a `@default` enumerator this frontend cannot follow"))?;
467 let owner = ast
468 .type_(resolved)
469 .map_err(|_| refuse("a `@default` whose member type is stale"))?;
470 rust::Expr::Path(Path::new(&[
471 &owner.name,
472 &rust::escape_keyword(&enumerator.name),
473 ]))
474 }
475 _ => {
478 let value = ast
479 .eval_integral(expr)
480 .map_err(|_| refuse("a `@default` this frontend cannot evaluate"))?;
481 rust::Expr::Literal(Literal::int(value))
482 }
483 })
484}
485
486fn call_path(segments: &[&str]) -> rust::Expr {
487 rust::Expr::Call {
488 callee: Box::new(rust::Expr::Path(Path::new(segments))),
489 args: Vec::new(),
490 }
491}