1use crate::debugger::debugee::dwarf::r#type::{
2 ArrayType, ComplexType, MemberLocation, StructureMember, TypeDeclaration, TypeId,
3};
4use crate::debugger::variable::value::Value;
5use indexmap::IndexMap;
6use serde_json::Value as JsonValue;
7
8#[derive(Debug, thiserror::Error)]
9pub enum SerializeError {
10 #[error("unsupported input: {0}")]
11 UnsupportedInput(String),
12 #[error("missing required field: {0}")]
13 MissingField(String),
14 #[error("unexpected input for type: {0}")]
15 UnexpectedInput(String),
16 #[error("unknown type id")]
17 UnknownType,
18 #[error("unknown type size for type id {0:?}")]
19 UnknownTypeSize(TypeId),
20 #[error("enum variant '{0}' not found")]
21 EnumVariantNotFound(String),
22 #[error("enum discriminant type missing")]
23 EnumDiscriminantMissing,
24 #[error("member offset for '{0}' not available")]
25 MemberOffsetMissing(String),
26 #[error("array element type missing")]
27 ArrayElementTypeMissing,
28 #[error("array length mismatch: expected {expected}, got {actual}")]
29 ArrayLengthMismatch { expected: usize, actual: usize },
30 #[error("value size mismatch: expected {expected}, got {actual}")]
31 SizeMismatch { expected: usize, actual: usize },
32 #[error("scalar parse failed: {0}")]
33 ScalarParse(String),
34}
35
36#[derive(Clone, Debug)]
37pub struct WriteOffset {
38 pub path: String,
39 pub offset: usize,
40 pub size: usize,
41}
42
43#[derive(Clone, Debug)]
44pub struct SerializedValue {
45 pub bytes: Vec<u8>,
46 pub size: usize,
47 pub offsets: Vec<WriteOffset>,
48}
49
50#[derive(Clone, Debug)]
51enum InputValue {
52 Scalar(String),
53 Array(Vec<InputValue>),
54 Object(IndexMap<String, InputValue>),
55 EnumVariant {
56 name: String,
57 payload: Option<Box<InputValue>>,
58 },
59}
60
61pub fn serialize_dap_value(
62 input: &str,
63 type_graph: &ComplexType,
64 type_id: TypeId,
65 runtime_value: Option<&Value>,
66) -> Result<SerializedValue, SerializeError> {
67 let input = parse_input_value(input)?;
68 let mut offsets = Vec::new();
69 let bytes =
70 serialize_value_inner(&input, type_graph, type_id, runtime_value, "", &mut offsets)?;
71 let size = bytes.len();
72 Ok(SerializedValue {
73 bytes,
74 size,
75 offsets,
76 })
77}
78
79fn parse_input_value(input: &str) -> Result<InputValue, SerializeError> {
80 let trimmed = input.trim();
81 if trimmed.is_empty() {
82 return Err(SerializeError::UnsupportedInput("empty input".to_string()));
83 }
84
85 if let Ok(json) = serde_json::from_str::<JsonValue>(trimmed) {
86 return Ok(input_from_json(&json));
87 }
88
89 if let Some(enum_value) = parse_enum_syntax(trimmed)? {
90 return Ok(enum_value);
91 }
92
93 if let Some(tuple) = parse_tuple_syntax(trimmed)? {
94 return Ok(tuple);
95 }
96
97 if let Some(obj) = parse_object_syntax(trimmed)? {
98 return Ok(obj);
99 }
100
101 Ok(InputValue::Scalar(trimmed.to_string()))
102}
103
104fn parse_enum_syntax(input: &str) -> Result<Option<InputValue>, SerializeError> {
105 let mut chars = input.chars();
106 let first = chars.next();
107 let Some(first) = first else {
108 return Ok(None);
109 };
110 if !first.is_ascii_alphabetic() && first != '_' {
111 return Ok(None);
112 }
113
114 let mut ident = String::new();
115 ident.push(first);
116 let mut rest_start = first.len_utf8();
117 for ch in input[rest_start..].chars() {
118 if ch.is_ascii_alphanumeric() || ch == '_' {
119 ident.push(ch);
120 rest_start += ch.len_utf8();
121 } else {
122 break;
123 }
124 }
125
126 let rest = input[rest_start..].trim_start();
127 if rest.is_empty() {
128 return Ok(None);
129 }
130
131 let payload = if rest.starts_with('(') && rest.ends_with(')') {
132 let inner = &rest[1..rest.len() - 1];
133 Some(Box::new(parse_input_value(inner)?))
134 } else if rest.starts_with('{') && rest.ends_with('}') {
135 let inner = &rest[1..rest.len() - 1];
136 Some(Box::new(parse_object_body(inner)?))
137 } else {
138 return Ok(None);
139 };
140
141 Ok(Some(InputValue::EnumVariant {
142 name: ident,
143 payload,
144 }))
145}
146
147fn parse_tuple_syntax(input: &str) -> Result<Option<InputValue>, SerializeError> {
148 let trimmed = input.trim();
149 if !(trimmed.starts_with('(') && trimmed.ends_with(')')) {
150 return Ok(None);
151 }
152 let inner = &trimmed[1..trimmed.len() - 1];
153 let items = split_top_level(inner)
154 .into_iter()
155 .filter(|part| !part.trim().is_empty())
156 .map(|part| parse_input_value(part.trim()))
157 .collect::<Result<Vec<_>, _>>()?;
158 Ok(Some(InputValue::Array(items)))
159}
160
161fn parse_object_syntax(input: &str) -> Result<Option<InputValue>, SerializeError> {
162 let trimmed = input.trim();
163 if !(trimmed.starts_with('{') && trimmed.ends_with('}')) {
164 return Ok(None);
165 }
166 let inner = &trimmed[1..trimmed.len() - 1];
167 Ok(Some(parse_object_body(inner)?))
168}
169
170fn parse_object_body(body: &str) -> Result<InputValue, SerializeError> {
171 let mut out = IndexMap::new();
172 for part in split_top_level(body) {
173 let part = part.trim();
174 if part.is_empty() {
175 continue;
176 }
177 let (key, value) = split_key_value(part)?;
178 let key = key.trim().trim_matches('"').trim_matches('\'');
179 let value = parse_input_value(value.trim())?;
180 out.insert(key.to_string(), value);
181 }
182 Ok(InputValue::Object(out))
183}
184
185fn split_key_value(input: &str) -> Result<(&str, &str), SerializeError> {
186 let mut depth = 0usize;
187 let mut in_str = None;
188 for (idx, ch) in input.char_indices() {
189 match ch {
190 '"' | '\'' => {
191 if in_str == Some(ch) {
192 in_str = None;
193 } else if in_str.is_none() {
194 in_str = Some(ch);
195 }
196 }
197 '{' | '[' | '(' if in_str.is_none() => depth += 1,
198 '}' | ']' | ')' if in_str.is_none() => depth = depth.saturating_sub(1),
199 ':' if in_str.is_none() && depth == 0 => {
200 let (k, v) = input.split_at(idx);
201 return Ok((k, &v[1..]));
202 }
203 _ => {}
204 }
205 }
206 Err(SerializeError::UnsupportedInput(format!(
207 "expected key:value in '{input}'"
208 )))
209}
210
211fn split_top_level(input: &str) -> Vec<&str> {
212 let mut parts = Vec::new();
213 let mut depth = 0usize;
214 let mut in_str: Option<char> = None;
215 let mut start = 0usize;
216 let mut prev_char = '\0';
217
218 for (idx, ch) in input.char_indices() {
219 if let Some(quote) = in_str {
220 if ch == quote && prev_char != '\\' {
221 in_str = None;
222 }
223 prev_char = ch;
224 continue;
225 }
226
227 match ch {
228 '\'' | '"' => in_str = Some(ch),
229 '{' | '[' | '(' => depth += 1,
230 '}' | ']' | ')' => depth = depth.saturating_sub(1),
231 ',' if depth == 0 => {
232 parts.push(&input[start..idx]);
233 start = idx + ch.len_utf8();
234 }
235 _ => {}
236 }
237 prev_char = ch;
238 }
239
240 if start <= input.len() {
241 parts.push(&input[start..]);
242 }
243
244 parts
245}
246
247fn input_from_json(value: &JsonValue) -> InputValue {
248 match value {
249 JsonValue::Null => InputValue::Scalar("null".to_string()),
250 JsonValue::Bool(b) => InputValue::Scalar(b.to_string()),
251 JsonValue::Number(num) => InputValue::Scalar(num.to_string()),
252 JsonValue::String(s) => InputValue::Scalar(s.clone()),
253 JsonValue::Array(items) => InputValue::Array(items.iter().map(input_from_json).collect()),
254 JsonValue::Object(map) => InputValue::Object(
255 map.iter()
256 .map(|(k, v)| (k.clone(), input_from_json(v)))
257 .collect(),
258 ),
259 }
260}
261
262fn serialize_value_inner(
263 input: &InputValue,
264 type_graph: &ComplexType,
265 type_id: TypeId,
266 runtime_value: Option<&Value>,
267 path: &str,
268 offsets: &mut Vec<WriteOffset>,
269) -> Result<Vec<u8>, SerializeError> {
270 let mut ctx = SerializeContext {
271 input,
272 type_graph,
273 type_id,
274 runtime_value,
275 path,
276 offsets,
277 };
278 let decl = type_graph
279 .types
280 .get(&type_id)
281 .ok_or(SerializeError::UnknownType)?;
282 match decl {
283 TypeDeclaration::Scalar(scalar) => serialize_scalar_value(input, scalar),
284 TypeDeclaration::Pointer { .. } => serialize_pointer_value(input),
285 TypeDeclaration::Array(array) => serialize_array_value(&mut ctx, array),
286 TypeDeclaration::Structure {
287 byte_size, members, ..
288 } => serialize_struct_value(&mut ctx, *byte_size, members),
289 TypeDeclaration::Union {
290 byte_size, members, ..
291 } => serialize_union_value(&mut ctx, *byte_size, members),
292 TypeDeclaration::CStyleEnum {
293 byte_size,
294 discr_type,
295 enumerators,
296 ..
297 } => serialize_c_enum_value(input, type_graph, *byte_size, *discr_type, enumerators),
298 TypeDeclaration::RustEnum {
299 byte_size,
300 discr_type,
301 enumerators,
302 ..
303 } => serialize_rust_enum_value(&mut ctx, *byte_size, discr_type.as_deref(), enumerators),
304 TypeDeclaration::Subroutine { .. } => serialize_pointer_value(input),
305 TypeDeclaration::ModifiedType { inner, .. } => {
306 let inner = inner.ok_or(SerializeError::UnknownType)?;
307 serialize_value_inner(input, type_graph, inner, runtime_value, path, offsets)
308 }
309 }
310}
311
312struct SerializeContext<'a> {
313 input: &'a InputValue,
314 type_graph: &'a ComplexType,
315 type_id: TypeId,
316 runtime_value: Option<&'a Value>,
317 path: &'a str,
318 offsets: &'a mut Vec<WriteOffset>,
319}
320
321fn serialize_scalar_value(
322 input: &InputValue,
323 scalar: &crate::debugger::debugee::dwarf::r#type::ScalarType,
324) -> Result<Vec<u8>, SerializeError> {
325 let input = match input {
326 InputValue::Scalar(s) => s.as_str(),
327 _ => {
328 return Err(SerializeError::UnexpectedInput(
329 "expected scalar".to_string(),
330 ));
331 }
332 };
333 let byte_size = scalar.byte_size.unwrap_or(0) as usize;
334 let encoding = scalar.encoding;
335
336 fn parse_i128(input: &str) -> Result<i128, SerializeError> {
337 if let Some(hex) = input
338 .strip_prefix("0x")
339 .or_else(|| input.strip_prefix("0X"))
340 {
341 i128::from_str_radix(hex, 16).map_err(|e| SerializeError::ScalarParse(e.to_string()))
342 } else {
343 input
344 .parse::<i128>()
345 .map_err(|e| SerializeError::ScalarParse(e.to_string()))
346 }
347 }
348
349 fn parse_u128(input: &str) -> Result<u128, SerializeError> {
350 if let Some(hex) = input
351 .strip_prefix("0x")
352 .or_else(|| input.strip_prefix("0X"))
353 {
354 u128::from_str_radix(hex, 16).map_err(|e| SerializeError::ScalarParse(e.to_string()))
355 } else {
356 input
357 .parse::<u128>()
358 .map_err(|e| SerializeError::ScalarParse(e.to_string()))
359 }
360 }
361
362 let bytes = match encoding {
363 Some(gimli::DW_ATE_float) => match byte_size {
364 4 => Ok(input
365 .parse::<f32>()
366 .map_err(|e| SerializeError::ScalarParse(e.to_string()))?
367 .to_le_bytes()
368 .to_vec()),
369 8 => Ok(input
370 .parse::<f64>()
371 .map_err(|e| SerializeError::ScalarParse(e.to_string()))?
372 .to_le_bytes()
373 .to_vec()),
374 _ => Err(SerializeError::ScalarParse(format!(
375 "unsupported float size {byte_size}"
376 ))),
377 },
378 Some(gimli::DW_ATE_boolean) => {
379 let value = match input {
380 "true" | "True" | "TRUE" | "1" => true,
381 "false" | "False" | "FALSE" | "0" => false,
382 _ => {
383 return Err(SerializeError::ScalarParse(format!(
384 "expected bool, got '{input}'"
385 )));
386 }
387 };
388 Ok(vec![if value { 1 } else { 0 }])
389 }
390 Some(gimli::DW_ATE_UTF) | Some(gimli::DW_ATE_ASCII) => {
391 let ch =
392 if let Some(stripped) = input.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
393 {
394 stripped.chars().next().ok_or_else(|| {
395 SerializeError::ScalarParse("empty char literal".to_string())
396 })?
397 } else if input.chars().count() == 1 {
398 input.chars().next().unwrap()
399 } else {
400 return Err(SerializeError::ScalarParse(
401 "expected char literal".to_string(),
402 ));
403 };
404 Ok((ch as u32).to_le_bytes().to_vec())
405 }
406 Some(gimli::DW_ATE_signed) | Some(gimli::DW_ATE_signed_char) => {
407 let value = parse_i128(input)?;
408 int_to_bytes(value as i128, byte_size)
409 }
410 Some(gimli::DW_ATE_unsigned)
411 | Some(gimli::DW_ATE_unsigned_char)
412 | Some(gimli::DW_ATE_address) => {
413 let value = parse_u128(input)?;
414 uint_to_bytes(value, byte_size)
415 }
416 _ => {
417 let value = parse_i128(input)?;
418 int_to_bytes(value, byte_size)
419 }
420 }?;
421
422 Ok(bytes)
423}
424
425fn serialize_pointer_value(input: &InputValue) -> Result<Vec<u8>, SerializeError> {
426 let input = match input {
427 InputValue::Scalar(s) => s.as_str(),
428 _ => {
429 return Err(SerializeError::UnexpectedInput(
430 "expected pointer scalar".to_string(),
431 ));
432 }
433 };
434 let addr = if let Some(hex) = input
435 .strip_prefix("0x")
436 .or_else(|| input.strip_prefix("0X"))
437 {
438 usize::from_str_radix(hex, 16).map_err(|e| SerializeError::ScalarParse(e.to_string()))?
439 } else {
440 input
441 .parse::<usize>()
442 .map_err(|e| SerializeError::ScalarParse(e.to_string()))?
443 };
444 Ok(addr.to_le_bytes().to_vec())
445}
446
447fn serialize_struct_value(
448 ctx: &mut SerializeContext<'_>,
449 byte_size: Option<u64>,
450 members: &[StructureMember],
451) -> Result<Vec<u8>, SerializeError> {
452 let size = byte_size.ok_or(SerializeError::UnknownTypeSize(ctx.type_id))?;
453 let mut buffer = vec![0u8; size as usize];
454
455 let input_map = match ctx.input {
456 InputValue::Object(map) => Some(map),
457 _ => None,
458 };
459 let input_array = match ctx.input {
460 InputValue::Array(items) => Some(items),
461 _ => None,
462 };
463
464 for (index, member) in members.iter().enumerate() {
465 let member_input = if let Some(name) = member.name.as_deref() {
466 input_map
467 .and_then(|map| map.get(name))
468 .ok_or_else(|| SerializeError::MissingField(name.to_string()))?
469 } else {
470 input_array
471 .and_then(|items| items.get(index))
472 .ok_or_else(|| SerializeError::MissingField(format!("[{index}]")))?
473 };
474
475 let member_type = member.type_ref.ok_or(SerializeError::UnknownType)?;
476 let member_runtime = runtime_member(ctx.runtime_value, member.name.as_deref(), index);
477 let member_bytes = serialize_value_inner(
478 member_input,
479 ctx.type_graph,
480 member_type,
481 member_runtime,
482 &format!("{}{}", ctx.path, member_path_suffix(member, index)),
483 ctx.offsets,
484 )?;
485 let offset = member_offset(member, ctx.runtime_value, index)
486 .ok_or_else(|| SerializeError::MemberOffsetMissing(member_name(member, index)))?;
487 let end = offset + member_bytes.len();
488 if end > buffer.len() {
489 return Err(SerializeError::SizeMismatch {
490 expected: buffer.len(),
491 actual: end,
492 });
493 }
494 buffer[offset..end].copy_from_slice(&member_bytes);
495 ctx.offsets.push(WriteOffset {
496 path: format!("{}{}", ctx.path, member_path_suffix(member, index)),
497 offset,
498 size: member_bytes.len(),
499 });
500 }
501
502 Ok(buffer)
503}
504
505fn serialize_union_value(
506 ctx: &mut SerializeContext<'_>,
507 byte_size: Option<u64>,
508 members: &[StructureMember],
509) -> Result<Vec<u8>, SerializeError> {
510 let size = byte_size.ok_or(SerializeError::UnknownTypeSize(ctx.type_id))?;
511 let mut buffer = vec![0u8; size as usize];
512 let (member_idx, member_input) = match ctx.input {
513 InputValue::Object(map) => {
514 let (name, value) = map
515 .iter()
516 .next()
517 .ok_or_else(|| SerializeError::UnsupportedInput("empty union".to_string()))?;
518 let idx = members
519 .iter()
520 .position(|m| m.name.as_deref() == Some(name))
521 .ok_or_else(|| SerializeError::MissingField(name.to_string()))?;
522 (idx, value)
523 }
524 InputValue::Array(items) => {
525 let value = items
526 .first()
527 .ok_or_else(|| SerializeError::UnsupportedInput("empty union".to_string()))?;
528 (0, value)
529 }
530 _ => {
531 return Err(SerializeError::UnexpectedInput(
532 "union expects object with single field".to_string(),
533 ));
534 }
535 };
536 let member = &members[member_idx];
537 let member_type = member.type_ref.ok_or(SerializeError::UnknownType)?;
538 let member_runtime = runtime_member(ctx.runtime_value, member.name.as_deref(), member_idx);
539 let member_bytes = serialize_value_inner(
540 member_input,
541 ctx.type_graph,
542 member_type,
543 member_runtime,
544 &format!("{}{}", ctx.path, member_path_suffix(member, member_idx)),
545 ctx.offsets,
546 )?;
547 let offset = member_offset(member, ctx.runtime_value, member_idx)
548 .ok_or_else(|| SerializeError::MemberOffsetMissing(member_name(member, member_idx)))?;
549 let end = offset + member_bytes.len();
550 if end > buffer.len() {
551 return Err(SerializeError::SizeMismatch {
552 expected: buffer.len(),
553 actual: end,
554 });
555 }
556 buffer[offset..end].copy_from_slice(&member_bytes);
557 ctx.offsets.push(WriteOffset {
558 path: format!("{}{}", ctx.path, member_path_suffix(member, member_idx)),
559 offset,
560 size: member_bytes.len(),
561 });
562 Ok(buffer)
563}
564
565fn serialize_array_value(
566 ctx: &mut SerializeContext<'_>,
567 array: &ArrayType,
568) -> Result<Vec<u8>, SerializeError> {
569 let items = match ctx.input {
570 InputValue::Array(items) => items,
571 _ => {
572 return Err(SerializeError::UnexpectedInput(
573 "array expects list".to_string(),
574 ));
575 }
576 };
577 let element_type = array
578 .element_type()
579 .ok_or(SerializeError::ArrayElementTypeMissing)?;
580 let mut buf = Vec::new();
581 let mut element_size = None;
582 for (idx, item) in items.iter().enumerate() {
583 let runtime_item = runtime_array_item(ctx.runtime_value, idx);
584 let bytes = serialize_value_inner(
585 item,
586 ctx.type_graph,
587 element_type,
588 runtime_item,
589 &format!("{}[{idx}]", ctx.path),
590 ctx.offsets,
591 )?;
592 let size = bytes.len();
593 if let Some(existing) = element_size {
594 if existing != size {
595 return Err(SerializeError::SizeMismatch {
596 expected: existing,
597 actual: size,
598 });
599 }
600 } else {
601 element_size = Some(size);
602 }
603 buf.extend_from_slice(&bytes);
604 ctx.offsets.push(WriteOffset {
605 path: format!("{}[{idx}]", ctx.path),
606 offset: idx * size,
607 size,
608 });
609 }
610 if let Some(expected_size) = array.byte_size_hint() {
611 let expected_size = expected_size as usize;
612 if expected_size != buf.len() {
613 let element_size = element_size.unwrap_or(0);
614 let expected_len = if element_size > 0 {
615 expected_size / element_size
616 } else {
617 0
618 };
619 return Err(SerializeError::ArrayLengthMismatch {
620 expected: expected_len,
621 actual: items.len(),
622 });
623 }
624 }
625 Ok(buf)
626}
627
628fn serialize_c_enum_value(
629 input: &InputValue,
630 type_graph: &ComplexType,
631 byte_size: Option<u64>,
632 discr_type: Option<TypeId>,
633 enumerators: &std::collections::HashMap<i64, String>,
634) -> Result<Vec<u8>, SerializeError> {
635 let name_or_value = match input {
636 InputValue::Scalar(s) => s.clone(),
637 InputValue::EnumVariant { name, .. } => name.clone(),
638 _ => {
639 return Err(SerializeError::UnexpectedInput(
640 "enum expects scalar".to_string(),
641 ));
642 }
643 };
644
645 let discr_value = if let Ok(num) = name_or_value.parse::<i64>() {
646 num
647 } else {
648 let (value, _) = enumerators
649 .iter()
650 .find(|(_, name)| *name == &name_or_value)
651 .ok_or_else(|| SerializeError::EnumVariantNotFound(name_or_value.clone()))?;
652 *value
653 };
654
655 if let Some(type_id) = discr_type {
656 let input = InputValue::Scalar(discr_value.to_string());
657 let mut offsets = Vec::new();
658 let bytes = serialize_value_inner(&input, type_graph, type_id, None, "", &mut offsets)?;
659 if let Some(byte_size) = byte_size {
660 let expected = byte_size as usize;
661 if bytes.len() != expected {
662 return Err(SerializeError::SizeMismatch {
663 expected,
664 actual: bytes.len(),
665 });
666 }
667 }
668 return Ok(bytes);
669 }
670
671 let size = byte_size.unwrap_or(0) as usize;
672 if size == 0 {
673 return Err(SerializeError::EnumDiscriminantMissing);
674 }
675 int_to_bytes(discr_value as i128, size)
676}
677
678fn serialize_rust_enum_value(
679 ctx: &mut SerializeContext<'_>,
680 byte_size: Option<u64>,
681 discr_member: Option<&StructureMember>,
682 enumerators: &std::collections::HashMap<Option<i64>, StructureMember>,
683) -> Result<Vec<u8>, SerializeError> {
684 let size = byte_size.ok_or(SerializeError::UnknownTypeSize(ctx.type_id))?;
685 let mut buffer = vec![0u8; size as usize];
686
687 let (variant_name, payload) = match ctx.input {
688 InputValue::EnumVariant { name, payload } => (name.clone(), payload.as_deref()),
689 InputValue::Scalar(name) => (name.clone(), None),
690 _ => {
691 return Err(SerializeError::UnexpectedInput(
692 "enum expects variant".to_string(),
693 ));
694 }
695 };
696
697 let (discr_value, variant_member) = enumerators
698 .iter()
699 .find(|(_, member)| member.name.as_deref() == Some(variant_name.as_str()))
700 .map(|(discr, member)| (discr.unwrap_or_default(), member))
701 .ok_or_else(|| SerializeError::EnumVariantNotFound(variant_name.clone()))?;
702
703 if let Some(discr_member) = discr_member {
704 let discr_type = discr_member
705 .type_ref
706 .ok_or(SerializeError::EnumDiscriminantMissing)?;
707 let discr_bytes = serialize_value_inner(
708 &InputValue::Scalar(discr_value.to_string()),
709 ctx.type_graph,
710 discr_type,
711 None,
712 ctx.path,
713 ctx.offsets,
714 )?;
715 let offset = member_offset(discr_member, ctx.runtime_value, 0)
716 .ok_or_else(|| SerializeError::MemberOffsetMissing("discriminant".to_string()))?;
717 let end = offset + discr_bytes.len();
718 if end > buffer.len() {
719 return Err(SerializeError::SizeMismatch {
720 expected: buffer.len(),
721 actual: end,
722 });
723 }
724 buffer[offset..end].copy_from_slice(&discr_bytes);
725 ctx.offsets.push(WriteOffset {
726 path: format!("{}.discriminant", ctx.path),
727 offset,
728 size: discr_bytes.len(),
729 });
730 }
731
732 if let Some(variant_type) = variant_member.type_ref {
733 let payload = payload.ok_or_else(|| SerializeError::MissingField(variant_name.clone()))?;
734 let payload_bytes = serialize_value_inner(
735 payload,
736 ctx.type_graph,
737 variant_type,
738 runtime_member(ctx.runtime_value, variant_member.name.as_deref(), 0),
739 &format!("{}.{}", ctx.path, variant_name),
740 ctx.offsets,
741 )?;
742 let offset = member_offset(variant_member, ctx.runtime_value, 0)
743 .ok_or_else(|| SerializeError::MemberOffsetMissing(format!("enum::{variant_name}")))?;
744 let end = offset + payload_bytes.len();
745 if end > buffer.len() {
746 return Err(SerializeError::SizeMismatch {
747 expected: buffer.len(),
748 actual: end,
749 });
750 }
751 buffer[offset..end].copy_from_slice(&payload_bytes);
752 ctx.offsets.push(WriteOffset {
753 path: format!("{}.{}", ctx.path, variant_name),
754 offset,
755 size: payload_bytes.len(),
756 });
757 }
758
759 Ok(buffer)
760}
761
762fn member_path_suffix(member: &StructureMember, index: usize) -> String {
763 member
764 .name
765 .as_deref()
766 .map(|name| format!(".{name}"))
767 .unwrap_or_else(|| format!("[{index}]"))
768}
769
770fn member_name(member: &StructureMember, index: usize) -> String {
771 member
772 .name
773 .as_deref()
774 .map(|name| name.to_string())
775 .unwrap_or_else(|| format!("[{index}]"))
776}
777
778fn member_offset(
779 member: &StructureMember,
780 runtime_value: Option<&Value>,
781 index: usize,
782) -> Option<usize> {
783 match member.in_struct_location.as_ref()? {
784 MemberLocation::Offset(offset) => (*offset >= 0).then_some(*offset as usize),
785 MemberLocation::Expr(_) => {
786 let base = runtime_value?.in_memory_location()? as isize;
787 let member_value = runtime_member(runtime_value, member.name.as_deref(), index)?;
788 let member_addr = member_value.in_memory_location()? as isize;
789 let offset = member_addr - base;
790 (offset >= 0).then_some(offset as usize)
791 }
792 }
793}
794
795fn runtime_member<'a>(
796 runtime_value: Option<&'a Value>,
797 name: Option<&str>,
798 index: usize,
799) -> Option<&'a Value> {
800 let Value::Struct(structure) = runtime_value? else {
801 return None;
802 };
803 if let Some(name) = name {
804 structure
805 .members
806 .iter()
807 .find(|member| member.field_name.as_deref() == Some(name))
808 .map(|member| &member.value)
809 } else {
810 structure.members.get(index).map(|member| &member.value)
811 }
812}
813
814fn runtime_array_item(runtime_value: Option<&Value>, index: usize) -> Option<&Value> {
815 let Value::Array(array) = runtime_value? else {
816 return None;
817 };
818 array.items.as_ref()?.get(index).map(|item| &item.value)
819}
820
821fn int_to_bytes(value: i128, size: usize) -> Result<Vec<u8>, SerializeError> {
822 let bytes = match size {
823 1 => (value as i8).to_le_bytes().to_vec(),
824 2 => (value as i16).to_le_bytes().to_vec(),
825 4 => (value as i32).to_le_bytes().to_vec(),
826 8 => (value as i64).to_le_bytes().to_vec(),
827 16 => value.to_le_bytes().to_vec(),
828 0 => Vec::new(),
829 _ => {
830 return Err(SerializeError::ScalarParse(format!(
831 "unsupported int size {size}"
832 )));
833 }
834 };
835 Ok(bytes)
836}
837
838fn uint_to_bytes(value: u128, size: usize) -> Result<Vec<u8>, SerializeError> {
839 let bytes = match size {
840 1 => (value as u8).to_le_bytes().to_vec(),
841 2 => (value as u16).to_le_bytes().to_vec(),
842 4 => (value as u32).to_le_bytes().to_vec(),
843 8 => (value as u64).to_le_bytes().to_vec(),
844 16 => value.to_le_bytes().to_vec(),
845 0 => Vec::new(),
846 _ => {
847 return Err(SerializeError::ScalarParse(format!(
848 "unsupported uint size {size}"
849 )));
850 }
851 };
852 Ok(bytes)
853}