Skip to main content

miden_mast_package/debug_info/
serialization.rs

1//! Serialization and deserialization for the debug_info section.
2
3use alloc::{string::String, sync::Arc, vec::Vec};
4
5use miden_core::{
6    Word,
7    mast::MastNodeId,
8    serde::{
9        ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
10        read_bounded_len,
11    },
12};
13use miden_debug_types::{ByteIndex, ColumnNumber, LineNumber, Location, Uri};
14
15use super::{
16    DEBUG_ERROR_MESSAGES_VERSION, DEBUG_FUNCTIONS_VERSION, DEBUG_SOURCE_GRAPH_VERSION,
17    DEBUG_SOURCE_MAP_VERSION, DEBUG_SOURCES_VERSION, DEBUG_TYPES_VERSION, DebugErrorMessage,
18    DebugErrorMessagesSection, DebugFieldInfo, DebugFileInfo, DebugFunctionInfo,
19    DebugFunctionsSection, DebugPrimitiveType, DebugSourceAsmOp, DebugSourceGraphSection,
20    DebugSourceInlineCall, DebugSourceMapSection, DebugSourceNode, DebugSourceNodeId,
21    DebugSourceVar, DebugSourcesSection, DebugTypeIdx, DebugTypeInfo, DebugTypesSection,
22    DebugVariantInfo,
23};
24
25// DEBUG TYPES SECTION SERIALIZATION
26// ================================================================================================
27
28impl Serializable for DebugTypesSection {
29    fn write_into<W: ByteWriter>(&self, target: &mut W) {
30        target.write_u8(self.version);
31
32        // Write string table
33        target.write_usize(self.strings.len());
34        for s in &self.strings {
35            s.as_ref().write_into(target);
36        }
37
38        // Write type table
39        target.write_usize(self.types.len());
40        for ty in &self.types {
41            ty.write_into(target);
42        }
43    }
44}
45
46impl Deserializable for DebugTypesSection {
47    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
48        let version = source.read_u8()?;
49        if version != DEBUG_TYPES_VERSION {
50            return Err(DeserializationError::InvalidValue(alloc::format!(
51                "unsupported debug_types version: {version}, expected {DEBUG_TYPES_VERSION}"
52            )));
53        }
54
55        // Manual bounds check required: read_string is a local helper, not Deserializable,
56        // so we can't use read_many_iter. Each string serializes to at least 1 byte (the
57        // varint length prefix), so max_alloc(1) bounds the vector pre-allocation.
58        let strings_len = read_bounded_len(source, "debug_types strings", 1)?;
59        let mut strings = Vec::with_capacity(strings_len);
60        for _ in 0..strings_len {
61            strings.push(read_string(source)?);
62        }
63
64        let types_len = read_bounded_len(source, "debug_types types", 1)?;
65        let types = source.read_many_iter(types_len)?.collect::<Result<_, _>>()?;
66
67        Ok(Self { version, strings, types })
68    }
69}
70
71// DEBUG SOURCES SECTION SERIALIZATION
72// ================================================================================================
73
74impl Serializable for DebugSourcesSection {
75    fn write_into<W: ByteWriter>(&self, target: &mut W) {
76        target.write_u8(self.version);
77
78        // Write string table
79        target.write_usize(self.strings.len());
80        for s in &self.strings {
81            s.as_ref().write_into(target);
82        }
83
84        // Write file table
85        target.write_usize(self.files.len());
86        for file in &self.files {
87            file.write_into(target);
88        }
89    }
90}
91
92impl Deserializable for DebugSourcesSection {
93    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
94        let version = source.read_u8()?;
95        if version != DEBUG_SOURCES_VERSION {
96            return Err(DeserializationError::InvalidValue(alloc::format!(
97                "unsupported debug_sources version: {version}, expected {DEBUG_SOURCES_VERSION}"
98            )));
99        }
100
101        // Manual bounds check required: read_string is a local helper, not Deserializable,
102        // so we can't use read_many_iter. Each string serializes to at least 1 byte (the
103        // varint length prefix), so max_alloc(1) bounds the vector pre-allocation.
104        let strings_len = read_bounded_len(source, "debug_sources strings", 1)?;
105        let mut strings = Vec::with_capacity(strings_len);
106        for _ in 0..strings_len {
107            strings.push(read_string(source)?);
108        }
109
110        let files_len = read_bounded_len(source, "debug_sources files", 1)?;
111        let files = source.read_many_iter(files_len)?.collect::<Result<_, _>>()?;
112
113        Ok(Self { version, strings, files })
114    }
115}
116
117// DEBUG FUNCTIONS SECTION SERIALIZATION
118// ================================================================================================
119
120impl Serializable for DebugFunctionsSection {
121    fn write_into<W: ByteWriter>(&self, target: &mut W) {
122        target.write_u8(self.version);
123
124        // Write string table
125        target.write_usize(self.strings.len());
126        for s in &self.strings {
127            s.as_ref().write_into(target);
128        }
129
130        // Write function table
131        target.write_usize(self.functions.len());
132        for func in &self.functions {
133            func.write_into(target);
134        }
135    }
136}
137
138impl Deserializable for DebugFunctionsSection {
139    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
140        let version = source.read_u8()?;
141        if version != DEBUG_FUNCTIONS_VERSION {
142            return Err(DeserializationError::InvalidValue(alloc::format!(
143                "unsupported debug_functions version: {version}, expected {DEBUG_FUNCTIONS_VERSION}"
144            )));
145        }
146
147        // Manual bounds check required: read_string is a local helper, not Deserializable,
148        // so we can't use read_many_iter. Each string serializes to at least 1 byte (the
149        // varint length prefix), so max_alloc(1) bounds the vector pre-allocation.
150        let strings_len = read_bounded_len(source, "debug_functions strings", 1)?;
151        let mut strings = Vec::with_capacity(strings_len);
152        for _ in 0..strings_len {
153            strings.push(read_string(source)?);
154        }
155
156        let functions_len = read_bounded_len(source, "debug_functions functions", 1)?;
157        let functions = source.read_many_iter(functions_len)?.collect::<Result<_, _>>()?;
158
159        Ok(Self { version, strings, functions })
160    }
161}
162
163// DEBUG SOURCE GRAPH SECTION SERIALIZATION
164// ================================================================================================
165
166impl Serializable for DebugSourceNode {
167    fn write_into<W: ByteWriter>(&self, target: &mut W) {
168        target.write_u32(self.exec_node.into());
169        self.children.write_into(target);
170        target.write_u32(self.op_start);
171        target.write_u32(self.op_end);
172    }
173}
174
175impl Deserializable for DebugSourceNode {
176    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
177        Ok(Self {
178            exec_node: MastNodeId::new_unchecked(source.read_u32()?),
179            children: read_debug_source_node_ids(source, "debug_source_node children")?,
180            op_start: source.read_u32()?,
181            op_end: source.read_u32()?,
182        })
183    }
184
185    fn min_serialized_size() -> usize {
186        12 + Vec::<DebugSourceNodeId>::min_serialized_size()
187    }
188}
189
190impl Serializable for DebugSourceGraphSection {
191    fn write_into<W: ByteWriter>(&self, target: &mut W) {
192        target.write_u8(self.version());
193        self.nodes().write_into(target);
194        self.roots().write_into(target);
195    }
196}
197
198impl Deserializable for DebugSourceGraphSection {
199    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
200        let version = source.read_u8()?;
201        if version != DEBUG_SOURCE_GRAPH_VERSION {
202            return Err(DeserializationError::InvalidValue(alloc::format!(
203                "unsupported debug_source_graph version: {version}, expected {DEBUG_SOURCE_GRAPH_VERSION}"
204            )));
205        }
206
207        let nodes_len = read_bounded_len(source, "debug_source_graph nodes", 1)?;
208        let nodes = source.read_many_iter(nodes_len)?.collect::<Result<_, _>>()?;
209        let roots = read_debug_source_node_ids(source, "debug_source_graph roots")?;
210        Ok(Self::from_parts(nodes, roots))
211    }
212}
213
214// DEBUG SOURCE MAP SECTION SERIALIZATION
215// ================================================================================================
216
217impl Serializable for DebugSourceAsmOp {
218    fn write_into<W: ByteWriter>(&self, target: &mut W) {
219        self.source_node.write_into(target);
220        target.write_u32(self.op_idx);
221        write_location(&self.location, target);
222        self.context_name.write_into(target);
223        self.op.write_into(target);
224        target.write_u8(self.num_cycles);
225    }
226}
227
228impl Deserializable for DebugSourceAsmOp {
229    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
230        let source_node = DebugSourceNodeId::read_from(source)?;
231        let op_idx = source.read_u32()?;
232        let location = read_location(source)?;
233        let context_name = String::read_from(source)?;
234        let op = String::read_from(source)?;
235        let num_cycles = source.read_u8()?;
236        Ok(Self {
237            source_node,
238            op_idx,
239            location,
240            context_name,
241            op,
242            num_cycles,
243        })
244    }
245
246    fn min_serialized_size() -> usize {
247        DebugSourceNodeId::min_serialized_size() + 4 + 1 + 1 + 1 + 1
248    }
249}
250
251impl Serializable for DebugSourceVar {
252    fn write_into<W: ByteWriter>(&self, target: &mut W) {
253        self.source_node.write_into(target);
254        target.write_u32(self.op_idx);
255        self.var.write_into(target);
256    }
257}
258
259impl Deserializable for DebugSourceVar {
260    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
261        Ok(Self {
262            source_node: DebugSourceNodeId::read_from(source)?,
263            op_idx: source.read_u32()?,
264            var: Deserializable::read_from(source)?,
265        })
266    }
267
268    fn min_serialized_size() -> usize {
269        DebugSourceNodeId::min_serialized_size() + 4
270    }
271}
272
273impl Serializable for DebugSourceInlineCall {
274    fn write_into<W: ByteWriter>(&self, target: &mut W) {
275        self.source_node.write_into(target);
276        target.write_u32(self.op_idx);
277        target.write_u32(self.callee_idx);
278        target.write_u32(self.file_idx);
279        target.write_u32(self.line.to_u32());
280        target.write_u32(self.column.to_u32());
281    }
282}
283
284impl Deserializable for DebugSourceInlineCall {
285    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
286        let source_node = DebugSourceNodeId::read_from(source)?;
287        let op_idx = source.read_u32()?;
288        let callee_idx = source.read_u32()?;
289        let file_idx = source.read_u32()?;
290        let line_raw = source.read_u32()?;
291        let column_raw = source.read_u32()?;
292        let line = LineNumber::new(line_raw).ok_or_else(|| {
293            DeserializationError::InvalidValue(alloc::format!(
294                "debug source inline call line {line_raw} is invalid"
295            ))
296        })?;
297        let column = ColumnNumber::new(column_raw).ok_or_else(|| {
298            DeserializationError::InvalidValue(alloc::format!(
299                "debug source inline call column {column_raw} is invalid"
300            ))
301        })?;
302        Ok(Self::new(source_node, op_idx, callee_idx, file_idx, line, column))
303    }
304
305    fn min_serialized_size() -> usize {
306        DebugSourceNodeId::min_serialized_size() + 20
307    }
308}
309
310impl Serializable for DebugSourceMapSection {
311    fn write_into<W: ByteWriter>(&self, target: &mut W) {
312        target.write_u8(self.version());
313        target.write_usize(self.locations().len());
314        for location in self.locations() {
315            write_required_location(location, target);
316        }
317
318        target.write_usize(self.strings().len());
319        for string in self.strings() {
320            string.write_into(target);
321        }
322
323        target.write_usize(self.asm_ops().len());
324        for asm_op in self.asm_ops() {
325            write_source_asm_op(asm_op, self.locations(), self.strings(), target);
326        }
327
328        self.debug_vars().write_into(target);
329        self.inline_calls().write_into(target);
330    }
331}
332
333impl Deserializable for DebugSourceMapSection {
334    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
335        let version = source.read_u8()?;
336        if version != DEBUG_SOURCE_MAP_VERSION {
337            return Err(DeserializationError::InvalidValue(alloc::format!(
338                "unsupported debug_source_map version: {version}, expected {DEBUG_SOURCE_MAP_VERSION}"
339            )));
340        }
341
342        let locations_len = read_bounded_len(
343            source,
344            "debug_source_map locations",
345            MIN_REQUIRED_LOCATION_SERIALIZED_SIZE,
346        )?;
347        let mut locations = Vec::with_capacity(locations_len);
348        for _ in 0..locations_len {
349            locations.push(read_required_location(source)?);
350        }
351
352        let strings_len = read_bounded_len(source, "debug_source_map strings", 1)?;
353        let mut strings = Vec::with_capacity(strings_len);
354        for _ in 0..strings_len {
355            strings.push(read_owned_string(source)?);
356        }
357
358        let asm_ops_len = read_bounded_len(
359            source,
360            "debug_source_map asm ops",
361            min_source_map_asm_op_row_serialized_size(),
362        )?;
363        let mut asm_ops = Vec::with_capacity(asm_ops_len);
364        for _ in 0..asm_ops_len {
365            asm_ops.push(read_source_asm_op(source, &locations, &strings)?);
366        }
367
368        let debug_vars_len = read_bounded_len(source, "debug_source_map debug vars", 1)?;
369        let debug_vars = source.read_many_iter(debug_vars_len)?.collect::<Result<_, _>>()?;
370        let inline_calls_len = read_bounded_len(source, "debug_source_map inline calls", 1)?;
371        let inline_calls = source.read_many_iter(inline_calls_len)?.collect::<Result<_, _>>()?;
372        Ok(Self::from_parts_with_inline_calls(asm_ops, debug_vars, inline_calls))
373    }
374}
375
376fn write_source_asm_op<W: ByteWriter>(
377    asm_op: &DebugSourceAsmOp,
378    locations: &[Location],
379    strings: &[String],
380    target: &mut W,
381) {
382    asm_op.source_node.write_into(target);
383    target.write_u32(asm_op.op_idx);
384    if let Some(location) = asm_op.location.as_ref() {
385        target.write_bool(true);
386        let location_idx = locations
387            .iter()
388            .position(|candidate| candidate == location)
389            .expect("debug source map location table should contain every row location");
390        target.write_u32(location_idx as u32);
391    } else {
392        target.write_bool(false);
393    }
394    write_source_map_string_ref(&asm_op.context_name, strings, target);
395    write_source_map_string_ref(&asm_op.op, strings, target);
396    target.write_u8(asm_op.num_cycles);
397}
398
399fn read_source_asm_op<R: ByteReader>(
400    source: &mut R,
401    locations: &[Location],
402    strings: &[String],
403) -> Result<DebugSourceAsmOp, DeserializationError> {
404    let source_node = DebugSourceNodeId::read_from(source)?;
405    let op_idx = source.read_u32()?;
406    let location = if source.read_bool()? {
407        let location_idx = source.read_u32()? as usize;
408        Some(locations.get(location_idx).cloned().ok_or_else(|| {
409            DeserializationError::InvalidValue(alloc::format!(
410                "debug source asm op location index {location_idx} out of bounds for {} locations",
411                locations.len()
412            ))
413        })?)
414    } else {
415        None
416    };
417    let context_name = read_source_map_string_ref(source, strings)?;
418    let op = read_source_map_string_ref(source, strings)?;
419    let num_cycles = source.read_u8()?;
420    Ok(DebugSourceAsmOp::new(
421        source_node,
422        op_idx,
423        location,
424        context_name,
425        op,
426        num_cycles,
427    ))
428}
429
430fn min_source_map_asm_op_row_serialized_size() -> usize {
431    // The location index is conditional and is omitted for location-less rows.
432    DebugSourceNodeId::min_serialized_size() + 4 + 1 + 4 + 4 + 1
433}
434
435fn write_source_map_string_ref<W: ByteWriter>(string: &String, strings: &[String], target: &mut W) {
436    let string_idx = strings
437        .iter()
438        .position(|candidate| candidate == string)
439        .expect("debug source map string table should contain every row string");
440    target.write_u32(string_idx as u32);
441}
442
443fn read_source_map_string_ref<R: ByteReader>(
444    source: &mut R,
445    strings: &[String],
446) -> Result<String, DeserializationError> {
447    let string_idx = source.read_u32()? as usize;
448    strings.get(string_idx).cloned().ok_or_else(|| {
449        DeserializationError::InvalidValue(alloc::format!(
450            "debug source asm op string index {string_idx} out of bounds for {} strings",
451            strings.len()
452        ))
453    })
454}
455
456// DEBUG ERROR MESSAGES SECTION SERIALIZATION
457// ================================================================================================
458
459impl Serializable for DebugErrorMessage {
460    fn write_into<W: ByteWriter>(&self, target: &mut W) {
461        target.write_u64(self.err_code);
462        self.message.as_ref().write_into(target);
463    }
464}
465
466impl Deserializable for DebugErrorMessage {
467    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
468        Ok(Self {
469            err_code: source.read_u64()?,
470            message: read_string(source)?,
471        })
472    }
473
474    fn min_serialized_size() -> usize {
475        8 + 1
476    }
477}
478
479impl Serializable for DebugErrorMessagesSection {
480    fn write_into<W: ByteWriter>(&self, target: &mut W) {
481        target.write_u8(self.version());
482        self.messages().write_into(target);
483    }
484}
485
486impl Deserializable for DebugErrorMessagesSection {
487    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
488        let version = source.read_u8()?;
489        if version != DEBUG_ERROR_MESSAGES_VERSION {
490            return Err(DeserializationError::InvalidValue(alloc::format!(
491                "unsupported debug_error_messages version: {version}, expected {DEBUG_ERROR_MESSAGES_VERSION}"
492            )));
493        }
494
495        let messages_len = read_bounded_len(source, "debug_error_messages messages", 1)?;
496        let messages = source.read_many_iter(messages_len)?.collect::<Result<_, _>>()?;
497        Ok(Self::from_parts(messages))
498    }
499}
500
501fn write_location<W: ByteWriter>(location: &Option<Location>, target: &mut W) {
502    if let Some(location) = location {
503        target.write_bool(true);
504        write_required_location(location, target);
505    } else {
506        target.write_bool(false);
507    }
508}
509
510fn read_location<R: ByteReader>(source: &mut R) -> Result<Option<Location>, DeserializationError> {
511    if !source.read_bool()? {
512        return Ok(None);
513    }
514
515    let uri = Uri::read_from(source)?;
516    let start = ByteIndex::new(source.read_u32()?);
517    let end = ByteIndex::new(source.read_u32()?);
518    Ok(Some(Location::new(uri, start, end)))
519}
520
521const MIN_REQUIRED_LOCATION_SERIALIZED_SIZE: usize = 9;
522
523fn write_required_location<W: ByteWriter>(location: &Location, target: &mut W) {
524    location.uri.write_into(target);
525    target.write_u32(location.start.to_u32());
526    target.write_u32(location.end.to_u32());
527}
528
529fn read_required_location<R: ByteReader>(source: &mut R) -> Result<Location, DeserializationError> {
530    let uri = Uri::read_from(source)?;
531    let start = ByteIndex::new(source.read_u32()?);
532    let end = ByteIndex::new(source.read_u32()?);
533    Ok(Location::new(uri, start, end))
534}
535
536// DEBUG TYPE INFO SERIALIZATION
537// ================================================================================================
538
539// Type tags for serialization
540const TYPE_TAG_PRIMITIVE: u8 = 0;
541const TYPE_TAG_POINTER: u8 = 1;
542const TYPE_TAG_ARRAY: u8 = 2;
543const TYPE_TAG_STRUCT: u8 = 3;
544const TYPE_TAG_FUNCTION: u8 = 4;
545const TYPE_TAG_UNKNOWN: u8 = 5;
546const TYPE_TAG_ENUM: u8 = 6;
547
548impl Serializable for DebugTypeInfo {
549    fn write_into<W: ByteWriter>(&self, target: &mut W) {
550        match self {
551            Self::Primitive(prim) => {
552                target.write_u8(TYPE_TAG_PRIMITIVE);
553                target.write_u8(*prim as u8);
554            },
555            Self::Pointer { pointee_type_idx } => {
556                target.write_u8(TYPE_TAG_POINTER);
557                target.write_u32(pointee_type_idx.as_u32());
558            },
559            Self::Array { element_type_idx, count } => {
560                target.write_u8(TYPE_TAG_ARRAY);
561                target.write_u32(element_type_idx.as_u32());
562                target.write_bool(count.is_some());
563                if let Some(count) = count {
564                    target.write_u32(*count);
565                }
566            },
567            Self::Struct { name_idx, size, fields } => {
568                target.write_u8(TYPE_TAG_STRUCT);
569                target.write_u32(*name_idx);
570                target.write_u32(*size);
571                target.write_usize(fields.len());
572                for field in fields {
573                    field.write_into(target);
574                }
575            },
576            Self::Function { return_type_idx, param_type_indices } => {
577                target.write_u8(TYPE_TAG_FUNCTION);
578                target.write_bool(return_type_idx.is_some());
579                if let Some(idx) = return_type_idx {
580                    target.write_u32(idx.as_u32());
581                }
582                target.write_usize(param_type_indices.len());
583                for idx in param_type_indices {
584                    target.write_u32(idx.as_u32());
585                }
586            },
587            Self::Enum {
588                name_idx,
589                size,
590                discriminant_type_idx,
591                variants,
592            } => {
593                target.write_u8(TYPE_TAG_ENUM);
594                target.write_u32(*name_idx);
595                target.write_u32(*size);
596                target.write_u32(discriminant_type_idx.as_u32());
597                target.write_usize(variants.len());
598                for variant in variants {
599                    variant.write_into(target);
600                }
601            },
602            Self::Unknown => {
603                target.write_u8(TYPE_TAG_UNKNOWN);
604            },
605        }
606    }
607}
608
609impl Deserializable for DebugTypeInfo {
610    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
611        let tag = source.read_u8()?;
612        match tag {
613            TYPE_TAG_PRIMITIVE => {
614                let prim_tag = source.read_u8()?;
615                let prim = DebugPrimitiveType::from_discriminant(prim_tag).ok_or_else(|| {
616                    DeserializationError::InvalidValue(alloc::format!(
617                        "invalid primitive type tag: {prim_tag}"
618                    ))
619                })?;
620                Ok(Self::Primitive(prim))
621            },
622            TYPE_TAG_POINTER => {
623                let pointee_type_idx = DebugTypeIdx::from(source.read_u32()?);
624                Ok(Self::Pointer { pointee_type_idx })
625            },
626            TYPE_TAG_ARRAY => {
627                let element_type_idx = DebugTypeIdx::from(source.read_u32()?);
628                let has_count = source.read_bool()?;
629                let count = if has_count { Some(source.read_u32()?) } else { None };
630                Ok(Self::Array { element_type_idx, count })
631            },
632            TYPE_TAG_STRUCT => {
633                let name_idx = source.read_u32()?;
634                let size = source.read_u32()?;
635                let fields_len = read_bounded_len(source, "debug struct fields", 1)?;
636                let fields = source.read_many_iter(fields_len)?.collect::<Result<_, _>>()?;
637                Ok(Self::Struct { name_idx, size, fields })
638            },
639            TYPE_TAG_FUNCTION => {
640                let has_return = source.read_bool()?;
641                let return_type_idx = if has_return {
642                    Some(DebugTypeIdx::from(source.read_u32()?))
643                } else {
644                    None
645                };
646                let param_type_indices =
647                    read_debug_type_indices(source, "debug function parameters")?;
648                Ok(Self::Function { return_type_idx, param_type_indices })
649            },
650            TYPE_TAG_ENUM => {
651                let name_idx = source.read_u32()?;
652                let size = source.read_u32()?;
653                let discriminant_type_idx = DebugTypeIdx::from(source.read_u32()?);
654                let variants_len = read_bounded_len(source, "debug enum variants", 1)?;
655                let variants = source.read_many_iter(variants_len)?.collect::<Result<_, _>>()?;
656                Ok(Self::Enum {
657                    name_idx,
658                    size,
659                    discriminant_type_idx,
660                    variants,
661                })
662            },
663            TYPE_TAG_UNKNOWN => Ok(Self::Unknown),
664            _ => Err(DeserializationError::InvalidValue(alloc::format!("invalid type tag: {tag}"))),
665        }
666    }
667}
668
669// DEBUG FIELD INFO SERIALIZATION
670// ================================================================================================
671
672impl Serializable for DebugFieldInfo {
673    fn write_into<W: ByteWriter>(&self, target: &mut W) {
674        target.write_u32(self.name_idx);
675        target.write_u32(self.type_idx.as_u32());
676        target.write_u32(self.offset);
677    }
678}
679
680impl Deserializable for DebugFieldInfo {
681    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
682        let name_idx = source.read_u32()?;
683        let type_idx = DebugTypeIdx::from(source.read_u32()?);
684        let offset = source.read_u32()?;
685        Ok(Self { name_idx, type_idx, offset })
686    }
687}
688
689// DEBUG VARIANT INFO SERIALIZATION
690// ================================================================================================
691
692impl Serializable for DebugVariantInfo {
693    fn write_into<W: ByteWriter>(&self, target: &mut W) {
694        target.write_u32(self.name_idx);
695        target.write_bool(self.type_idx.is_some());
696        if let Some(type_idx) = self.type_idx {
697            target.write_u32(type_idx.as_u32());
698        }
699        target.write_bool(self.payload_offset.is_some());
700        if let Some(payload_offset) = self.payload_offset {
701            target.write_u32(payload_offset);
702        }
703        target.write_u64((self.discriminant >> 64) as u64);
704        target.write_u64(self.discriminant as u64);
705    }
706}
707
708impl Deserializable for DebugVariantInfo {
709    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
710        let name_idx = source.read_u32()?;
711        let type_idx = if source.read_bool()? {
712            Some(DebugTypeIdx::from(source.read_u32()?))
713        } else {
714            None
715        };
716        let payload_offset = if source.read_bool()? {
717            Some(source.read_u32()?)
718        } else {
719            None
720        };
721        let hi = source.read_u64()? as u128;
722        let lo = source.read_u64()? as u128;
723        Ok(Self {
724            name_idx,
725            type_idx,
726            payload_offset,
727            discriminant: (hi << 64) | lo,
728        })
729    }
730}
731
732// DEBUG FILE INFO SERIALIZATION
733// ================================================================================================
734
735impl Serializable for DebugFileInfo {
736    fn write_into<W: ByteWriter>(&self, target: &mut W) {
737        target.write_u32(self.path_idx);
738
739        target.write_bool(self.checksum.is_some());
740        if let Some(checksum) = &self.checksum {
741            target.write_bytes(checksum.as_ref());
742        }
743    }
744}
745
746impl Deserializable for DebugFileInfo {
747    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
748        let path_idx = source.read_u32()?;
749
750        let has_checksum = source.read_bool()?;
751        let checksum = if has_checksum {
752            let bytes = source.read_slice(32)?;
753            let mut arr = [0u8; 32];
754            arr.copy_from_slice(bytes);
755            Some(alloc::boxed::Box::new(arr))
756        } else {
757            None
758        };
759
760        Ok(Self { path_idx, checksum })
761    }
762}
763
764// DEBUG FUNCTION INFO SERIALIZATION
765// ================================================================================================
766
767impl Serializable for DebugFunctionInfo {
768    fn write_into<W: ByteWriter>(&self, target: &mut W) {
769        target.write_u32(self.name_idx);
770
771        target.write_bool(self.linkage_name_idx.is_some());
772        if let Some(idx) = self.linkage_name_idx {
773            target.write_u32(idx);
774        }
775
776        target.write_u32(self.file_idx);
777        target.write_u32(self.line.to_u32());
778        target.write_u32(self.column.to_u32());
779
780        target.write_bool(self.type_idx.is_some());
781        if let Some(idx) = self.type_idx {
782            target.write_u32(idx.as_u32());
783        }
784
785        target.write_bool(self.mast_root.is_some());
786        if let Some(root) = &self.mast_root {
787            root.write_into(target);
788        }
789    }
790}
791
792impl Deserializable for DebugFunctionInfo {
793    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
794        let name_idx = source.read_u32()?;
795
796        let has_linkage_name = source.read_bool()?;
797        let linkage_name_idx = if has_linkage_name {
798            Some(source.read_u32()?)
799        } else {
800            None
801        };
802
803        let file_idx = source.read_u32()?;
804        let line_raw = source.read_u32()?;
805        let column_raw = source.read_u32()?;
806        let line = LineNumber::new(line_raw).unwrap_or_default();
807        let column = ColumnNumber::new(column_raw).unwrap_or_default();
808
809        let has_type = source.read_bool()?;
810        let type_idx = if has_type {
811            Some(DebugTypeIdx::from(source.read_u32()?))
812        } else {
813            None
814        };
815
816        let has_mast_root = source.read_bool()?;
817        let mast_root = if has_mast_root {
818            Some(Word::read_from(source)?)
819        } else {
820            None
821        };
822
823        Ok(Self {
824            name_idx,
825            linkage_name_idx,
826            file_idx,
827            line,
828            column,
829            type_idx,
830            mast_root,
831        })
832    }
833}
834
835// HELPER FUNCTIONS
836// ================================================================================================
837
838fn read_string<R: ByteReader>(source: &mut R) -> Result<Arc<str>, DeserializationError> {
839    let len = read_bounded_len(source, "debug string bytes", 1)?;
840    let bytes = source.read_slice(len)?;
841    let s = core::str::from_utf8(bytes).map_err(|err| {
842        DeserializationError::InvalidValue(alloc::format!("invalid utf-8 in string: {err}"))
843    })?;
844    Ok(Arc::from(s))
845}
846
847fn read_owned_string<R: ByteReader>(source: &mut R) -> Result<String, DeserializationError> {
848    read_string(source).map(|value| String::from(value.as_ref()))
849}
850
851fn read_debug_source_node_ids<R: ByteReader>(
852    source: &mut R,
853    label: &str,
854) -> Result<Vec<DebugSourceNodeId>, DeserializationError> {
855    let len = read_bounded_len(source, label, DebugSourceNodeId::min_serialized_size())?;
856    source.read_many_iter(len)?.collect::<Result<_, _>>()
857}
858
859fn read_debug_type_indices<R: ByteReader>(
860    source: &mut R,
861    label: &str,
862) -> Result<Vec<DebugTypeIdx>, DeserializationError> {
863    let len = read_bounded_len(source, label, DebugTypeIdx::min_serialized_size())?;
864    source.read_many_iter(len)?.collect::<Result<_, _>>()
865}
866
867#[cfg(test)]
868mod tests {
869    use miden_core::operations::{DebugVarInfo, DebugVarLocation};
870
871    use super::*;
872
873    struct FixedBudgetReader<'a> {
874        inner: miden_core::serde::SliceReader<'a>,
875        max_bytes: usize,
876    }
877
878    impl<'a> FixedBudgetReader<'a> {
879        fn new(bytes: &'a [u8], max_bytes: usize) -> Self {
880            Self {
881                inner: miden_core::serde::SliceReader::new(bytes),
882                max_bytes,
883            }
884        }
885    }
886
887    impl<'a> ByteReader for FixedBudgetReader<'a> {
888        fn read_u8(&mut self) -> Result<u8, DeserializationError> {
889            self.inner.read_u8()
890        }
891
892        fn peek_u8(&self) -> Result<u8, DeserializationError> {
893            self.inner.peek_u8()
894        }
895
896        fn read_slice(&mut self, len: usize) -> Result<&[u8], DeserializationError> {
897            self.inner.read_slice(len)
898        }
899
900        fn read_array<const N: usize>(&mut self) -> Result<[u8; N], DeserializationError> {
901            self.inner.read_array()
902        }
903
904        fn check_eor(&self, num_bytes: usize) -> Result<(), DeserializationError> {
905            self.inner.check_eor(num_bytes)
906        }
907
908        fn has_more_bytes(&self) -> bool {
909            self.inner.has_more_bytes()
910        }
911
912        fn max_alloc(&self, element_size: usize) -> usize {
913            if element_size == 0 {
914                usize::MAX
915            } else {
916                self.max_bytes.checked_div(element_size).unwrap_or(0)
917            }
918        }
919    }
920
921    fn section_with_strings(version: u8, strings_len: usize) -> Vec<u8> {
922        let mut bytes = Vec::new();
923        bytes.write_u8(version);
924        bytes.write_usize(strings_len);
925        for _ in 0..strings_len {
926            "".write_into(&mut bytes);
927        }
928        bytes.write_usize(0);
929        bytes
930    }
931
932    fn function_type_bytes(params_len: usize) -> Vec<u8> {
933        let mut bytes = Vec::new();
934        bytes.write_u8(TYPE_TAG_FUNCTION);
935        bytes.write_bool(false);
936        bytes.write_usize(params_len);
937        for _ in 0..params_len {
938            bytes.write_u32(0);
939        }
940        bytes
941    }
942
943    fn roundtrip<T: Serializable + Deserializable + PartialEq + core::fmt::Debug>(value: &T) {
944        let mut bytes = Vec::new();
945        value.write_into(&mut bytes);
946        let result = T::read_from(&mut miden_core::serde::SliceReader::new(&bytes)).unwrap();
947        assert_eq!(value, &result);
948    }
949
950    #[test]
951    fn test_debug_types_section_roundtrip() {
952        let mut section = DebugTypesSection::new();
953
954        // Add primitive types
955        let i32_type_idx = section.add_type(DebugTypeInfo::Primitive(DebugPrimitiveType::I32));
956        let felt_type_idx = section.add_type(DebugTypeInfo::Primitive(DebugPrimitiveType::Felt));
957
958        // Add a pointer type
959        section.add_type(DebugTypeInfo::Pointer { pointee_type_idx: i32_type_idx });
960
961        // Add an array type
962        section.add_type(DebugTypeInfo::Array {
963            element_type_idx: felt_type_idx,
964            count: Some(4),
965        });
966
967        // Add a struct type
968        let x_idx = section.add_string(Arc::from("x"));
969        let y_idx = section.add_string(Arc::from("y"));
970        let point_idx = section.add_string(Arc::from("Point"));
971        section.add_type(DebugTypeInfo::Struct {
972            name_idx: point_idx,
973            size: 16,
974            fields: alloc::vec![
975                DebugFieldInfo {
976                    name_idx: x_idx,
977                    type_idx: felt_type_idx,
978                    offset: 0,
979                },
980                DebugFieldInfo {
981                    name_idx: y_idx,
982                    type_idx: felt_type_idx,
983                    offset: 8,
984                },
985            ],
986        });
987
988        // Add an enum type
989        let status_idx = section.add_string(Arc::from("Status"));
990        let ok_idx = section.add_string(Arc::from("Ok"));
991        let err_idx = section.add_string(Arc::from("Err"));
992        section.add_type(DebugTypeInfo::Enum {
993            name_idx: status_idx,
994            size: 8,
995            discriminant_type_idx: i32_type_idx,
996            variants: alloc::vec![
997                DebugVariantInfo {
998                    name_idx: ok_idx,
999                    type_idx: None,
1000                    payload_offset: None,
1001                    discriminant: 0,
1002                },
1003                DebugVariantInfo {
1004                    name_idx: err_idx,
1005                    type_idx: Some(felt_type_idx),
1006                    payload_offset: Some(8),
1007                    discriminant: 1,
1008                },
1009            ],
1010        });
1011
1012        roundtrip(&section);
1013    }
1014
1015    #[test]
1016    fn test_debug_sources_section_roundtrip() {
1017        let mut section = DebugSourcesSection::new();
1018
1019        let path_idx = section.add_string(Arc::from("test.rs"));
1020        section.add_file(DebugFileInfo::new(path_idx));
1021
1022        let path2_idx = section.add_string(Arc::from("main.rs"));
1023        section.add_file(DebugFileInfo::new(path2_idx).with_checksum([42u8; 32]));
1024
1025        roundtrip(&section);
1026    }
1027
1028    #[test]
1029    fn test_debug_functions_section_roundtrip() {
1030        let mut section = DebugFunctionsSection::new();
1031
1032        let name_idx = section.add_string(Arc::from("test_function"));
1033
1034        let line = LineNumber::new(10).unwrap();
1035        let column = ColumnNumber::new(1).unwrap();
1036        let func = DebugFunctionInfo::new(name_idx, 0, line, column);
1037        section.add_function(func);
1038
1039        roundtrip(&section);
1040    }
1041
1042    #[test]
1043    fn test_debug_source_graph_section_roundtrip() {
1044        let section = DebugSourceGraphSection::from_parts(
1045            alloc::vec![
1046                DebugSourceNode::new(MastNodeId::new_unchecked(0), alloc::vec![], 0, 1),
1047                DebugSourceNode::new(
1048                    MastNodeId::new_unchecked(1),
1049                    alloc::vec![DebugSourceNodeId::from(0)],
1050                    1,
1051                    3,
1052                ),
1053            ],
1054            alloc::vec![DebugSourceNodeId::from(1)],
1055        );
1056
1057        roundtrip(&section);
1058    }
1059
1060    #[test]
1061    fn test_debug_source_map_section_roundtrip() {
1062        let source_node = DebugSourceNodeId::from(0);
1063        let section = DebugSourceMapSection::from_parts_with_inline_calls(
1064            alloc::vec![DebugSourceAsmOp::new(
1065                source_node,
1066                2,
1067                None,
1068                "test::ctx".into(),
1069                "add".into(),
1070                1,
1071            )],
1072            alloc::vec![DebugSourceVar::new(
1073                source_node,
1074                2,
1075                DebugVarInfo::new("x", DebugVarLocation::Stack(0)),
1076            )],
1077            alloc::vec![DebugSourceInlineCall::new(
1078                source_node,
1079                2,
1080                0,
1081                0,
1082                LineNumber::new(10).unwrap(),
1083                ColumnNumber::new(5).unwrap(),
1084            )],
1085        );
1086
1087        roundtrip(&section);
1088    }
1089
1090    #[test]
1091    fn test_debug_source_map_locationless_asm_op_min_size() {
1092        let source_node = DebugSourceNodeId::from(0);
1093        let asm_op = |op_idx| {
1094            DebugSourceAsmOp::new(source_node, op_idx, None, "test::ctx".into(), "add".into(), 1)
1095        };
1096        let section = DebugSourceMapSection::from_parts(
1097            // Three location-less rows exceed the trailing empty debug_vars/inline_calls
1098            // length prefixes, so an overestimated row size rejects this section.
1099            alloc::vec![asm_op(2), asm_op(3), asm_op(4)],
1100            alloc::vec![],
1101        );
1102
1103        let bytes = section.to_bytes();
1104        let deserialized = DebugSourceMapSection::read_from_bytes(&bytes).unwrap();
1105        assert_eq!(deserialized.asm_ops(), section.asm_ops());
1106    }
1107
1108    #[test]
1109    fn test_debug_source_map_locations_are_deduplicated() {
1110        let source_node = DebugSourceNodeId::from(0);
1111        let location =
1112            Location::new(Uri::new("file://test.masm"), ByteIndex::new(10), ByteIndex::new(14));
1113        let section = DebugSourceMapSection::from_parts(
1114            alloc::vec![
1115                DebugSourceAsmOp::new(
1116                    source_node,
1117                    0,
1118                    Some(location.clone()),
1119                    "test::ctx".into(),
1120                    "push.1".into(),
1121                    1,
1122                ),
1123                DebugSourceAsmOp::new(
1124                    source_node,
1125                    1,
1126                    Some(location.clone()),
1127                    "test::ctx".into(),
1128                    "add".into(),
1129                    1,
1130                ),
1131            ],
1132            alloc::vec![],
1133        );
1134
1135        assert_eq!(section.locations(), &[location]);
1136
1137        let bytes = section.to_bytes();
1138        let deserialized = DebugSourceMapSection::read_from_bytes(&bytes).unwrap();
1139        assert_eq!(deserialized.locations(), section.locations());
1140        assert_eq!(deserialized.asm_ops(), section.asm_ops());
1141    }
1142
1143    #[test]
1144    fn test_debug_source_map_strings_are_deduplicated() {
1145        let source_node = DebugSourceNodeId::from(0);
1146        let section = DebugSourceMapSection::from_parts(
1147            alloc::vec![
1148                DebugSourceAsmOp::new(source_node, 0, None, "test::ctx".into(), "add".into(), 1,),
1149                DebugSourceAsmOp::new(source_node, 1, None, "test::ctx".into(), "mul".into(), 1,),
1150                DebugSourceAsmOp::new(source_node, 2, None, "test::other".into(), "add".into(), 1,),
1151            ],
1152            alloc::vec![],
1153        );
1154
1155        assert_eq!(
1156            section.strings(),
1157            &[
1158                String::from("test::ctx"),
1159                String::from("add"),
1160                String::from("mul"),
1161                String::from("test::other"),
1162            ]
1163        );
1164
1165        let bytes = section.to_bytes();
1166        let deserialized = DebugSourceMapSection::read_from_bytes(&bytes).unwrap();
1167        assert_eq!(deserialized.strings(), section.strings());
1168        assert_eq!(deserialized.asm_ops(), section.asm_ops());
1169    }
1170
1171    #[test]
1172    fn test_debug_error_messages_section_roundtrip() {
1173        let section = DebugErrorMessagesSection::from_parts(alloc::vec![DebugErrorMessage::new(
1174            42,
1175            Arc::from("assertion message"),
1176        )]);
1177
1178        roundtrip(&section);
1179        assert_eq!(section.message(42).as_deref(), Some("assertion message"));
1180    }
1181
1182    #[test]
1183    fn test_empty_sections_roundtrip() {
1184        roundtrip(&DebugTypesSection::new());
1185        roundtrip(&DebugSourcesSection::new());
1186        roundtrip(&DebugFunctionsSection::new());
1187        roundtrip(&DebugSourceGraphSection::new());
1188        roundtrip(&DebugSourceMapSection::new());
1189        roundtrip(&DebugErrorMessagesSection::new());
1190    }
1191
1192    #[test]
1193    fn test_all_primitive_types_roundtrip() {
1194        let mut section = DebugTypesSection::new();
1195
1196        for prim in [
1197            DebugPrimitiveType::Void,
1198            DebugPrimitiveType::Bool,
1199            DebugPrimitiveType::I8,
1200            DebugPrimitiveType::U8,
1201            DebugPrimitiveType::I16,
1202            DebugPrimitiveType::U16,
1203            DebugPrimitiveType::I32,
1204            DebugPrimitiveType::U32,
1205            DebugPrimitiveType::I64,
1206            DebugPrimitiveType::U64,
1207            DebugPrimitiveType::I128,
1208            DebugPrimitiveType::U128,
1209            DebugPrimitiveType::F32,
1210            DebugPrimitiveType::F64,
1211            DebugPrimitiveType::Felt,
1212            DebugPrimitiveType::Word,
1213            DebugPrimitiveType::U256,
1214        ] {
1215            section.add_type(DebugTypeInfo::Primitive(prim));
1216        }
1217
1218        roundtrip(&section);
1219    }
1220
1221    #[test]
1222    fn test_function_type_roundtrip() {
1223        let ty = DebugTypeInfo::Function {
1224            return_type_idx: Some(DebugTypeIdx::from(0)),
1225            param_type_indices: alloc::vec![
1226                DebugTypeIdx::from(1),
1227                DebugTypeIdx::from(2),
1228                DebugTypeIdx::from(3)
1229            ],
1230        };
1231        roundtrip(&ty);
1232
1233        let void_fn = DebugTypeInfo::Function {
1234            return_type_idx: None,
1235            param_type_indices: alloc::vec![],
1236        };
1237        roundtrip(&void_fn);
1238    }
1239
1240    #[test]
1241    fn test_file_info_with_checksum_roundtrip() {
1242        let file = DebugFileInfo::new(0).with_checksum([42u8; 32]);
1243        roundtrip(&file);
1244    }
1245
1246    #[test]
1247    fn test_function_with_mast_root_roundtrip() {
1248        let line1 = LineNumber::new(1).unwrap();
1249        let col1 = ColumnNumber::new(1).unwrap();
1250        let func = DebugFunctionInfo::new(0, 0, line1, col1)
1251            .with_linkage_name(1)
1252            .with_type(DebugTypeIdx::from(2))
1253            .with_mast_root(Word::default());
1254
1255        roundtrip(&func);
1256    }
1257
1258    #[test]
1259    fn test_debug_functions_v1_is_rejected() {
1260        let bytes = section_with_strings(1, 0);
1261        let mut reader = miden_core::serde::SliceReader::new(&bytes);
1262        let err = DebugFunctionsSection::read_from(&mut reader).unwrap_err();
1263        let DeserializationError::InvalidValue(message) = err else {
1264            panic!("expected InvalidValue error");
1265        };
1266        assert!(message.contains("unsupported debug_functions version: 1"));
1267    }
1268
1269    #[test]
1270    fn test_debug_section_string_bounds() {
1271        let types_bytes = section_with_strings(DEBUG_TYPES_VERSION, 2);
1272        let sources_bytes = section_with_strings(DEBUG_SOURCES_VERSION, 2);
1273        let functions_bytes = section_with_strings(DEBUG_FUNCTIONS_VERSION, 2);
1274
1275        let mut reader = FixedBudgetReader::new(&types_bytes, 1);
1276        let err = DebugTypesSection::read_from(&mut reader).unwrap_err();
1277        let DeserializationError::InvalidValue(message) = err else {
1278            panic!("expected InvalidValue error");
1279        };
1280        assert!(message.contains("exceeds budget"));
1281
1282        let mut reader = FixedBudgetReader::new(&sources_bytes, 1);
1283        let err = DebugSourcesSection::read_from(&mut reader).unwrap_err();
1284        let DeserializationError::InvalidValue(message) = err else {
1285            panic!("expected InvalidValue error");
1286        };
1287        assert!(message.contains("exceeds budget"));
1288
1289        let mut reader = FixedBudgetReader::new(&functions_bytes, 1);
1290        let err = DebugFunctionsSection::read_from(&mut reader).unwrap_err();
1291        let DeserializationError::InvalidValue(message) = err else {
1292            panic!("expected InvalidValue error");
1293        };
1294        assert!(message.contains("exceeds budget"));
1295
1296        let types_ok = section_with_strings(DEBUG_TYPES_VERSION, 1);
1297        let sources_ok = section_with_strings(DEBUG_SOURCES_VERSION, 1);
1298        let functions_ok = section_with_strings(DEBUG_FUNCTIONS_VERSION, 1);
1299
1300        let mut reader = FixedBudgetReader::new(&types_ok, 1);
1301        assert_eq!(DebugTypesSection::read_from(&mut reader).unwrap().strings.len(), 1);
1302
1303        let mut reader = FixedBudgetReader::new(&sources_ok, 1);
1304        assert_eq!(DebugSourcesSection::read_from(&mut reader).unwrap().strings.len(), 1);
1305
1306        let mut reader = FixedBudgetReader::new(&functions_ok, 1);
1307        assert_eq!(DebugFunctionsSection::read_from(&mut reader).unwrap().strings.len(), 1);
1308    }
1309
1310    #[test]
1311    fn test_debug_functions_rejects_oversized_string_table_count() {
1312        let bytes = [0x02, 0x08, 0x2a, 0xfe, 0xfe, 0x01];
1313        let mut reader = miden_core::serde::SliceReader::new(&bytes);
1314        let err = DebugFunctionsSection::read_from(&mut reader).unwrap_err();
1315        let DeserializationError::InvalidValue(message) = err else {
1316            panic!("expected InvalidValue error");
1317        };
1318        assert!(message.contains("debug_functions strings count"));
1319        assert!(message.contains("exceeds remaining input"));
1320    }
1321
1322    #[test]
1323    fn test_function_params_bounds() {
1324        let too_many = function_type_bytes(2);
1325        let mut reader = FixedBudgetReader::new(&too_many, 4);
1326        let err = DebugTypeInfo::read_from(&mut reader).unwrap_err();
1327        assert!(matches!(err, DeserializationError::InvalidValue(_)));
1328
1329        let ok = function_type_bytes(1);
1330        let mut reader = FixedBudgetReader::new(&ok, 4);
1331        let ty = DebugTypeInfo::read_from(&mut reader).unwrap();
1332        match ty {
1333            DebugTypeInfo::Function { param_type_indices, .. } => {
1334                assert_eq!(param_type_indices.len(), 1);
1335            },
1336            _ => panic!("expected function type"),
1337        }
1338    }
1339}