Skip to main content

sim_codec_classfile/attribute/
basic.rs

1/// A stable structured-attribute failure category.
2#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3pub enum AttributeErrorKind {
4    /// The bounded byte lane rejected the input or output.
5    Bytes,
6    /// A reserved stack-map frame tag or verification-type tag was encountered.
7    ReservedTag,
8    /// An attribute body contained trailing bytes.
9    TrailingBytes,
10    /// A collection cannot be represented by its classfile count field.
11    CountOverflow,
12    /// A locally checkable attribute constraint is invalid.
13    StaticConstraint,
14    /// A nested annotation value exceeded the caller's structural budget.
15    NestingBudgetExceeded,
16}
17/// A located structured-attribute format error.
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub struct AttributeError {
20    /// Stable machine-matchable failure category.
21    pub kind: AttributeErrorKind,
22    /// Absolute byte offset at which the failure was detected.
23    pub offset: usize,
24    /// Human-readable context.
25    pub message: String,
26}
27
28impl fmt::Display for AttributeError {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        write!(f, "{} at byte {}", self.message, self.offset)
31    }
32}
33
34impl std::error::Error for AttributeError {}
35
36impl From<ByteError> for AttributeError {
37    fn from(value: ByteError) -> Self {
38        Self {
39            kind: AttributeErrorKind::Bytes,
40            offset: value.offset,
41            message: value.message,
42        }
43    }
44}
45
46fn error(kind: AttributeErrorKind, offset: usize, message: impl Into<String>) -> AttributeError {
47    AttributeError {
48        kind,
49        offset,
50        message: message.into(),
51    }
52}
53
54fn finish(reader: &ByteReader<'_>) -> Result<(), AttributeError> {
55    if reader.remaining() == 0 {
56        Ok(())
57    } else {
58        Err(error(
59            AttributeErrorKind::TrailingBytes,
60            reader.offset(),
61            format!("{} trailing attribute bytes", reader.remaining()),
62        ))
63    }
64}
65
66fn count(value: usize, what: &str) -> Result<u16, AttributeError> {
67    u16::try_from(value).map_err(|_| {
68        error(
69            AttributeErrorKind::CountOverflow,
70            0,
71            format!("too many {what}"),
72        )
73    })
74}
75
76fn read_u2s(reader: &mut ByteReader<'_>, what: &str) -> Result<Vec<u16>, AttributeError> {
77    let n = usize::from(reader.read_u2()?);
78    reader.preflight_allocation(n)?;
79    let mut values = Vec::with_capacity(n);
80    for _ in 0..n {
81        values.push(reader.read_u2()?);
82    }
83    finish(reader)?;
84    let _ = what;
85    Ok(values)
86}
87
88fn write_u2s(values: &[u16], budget: usize, what: &str) -> Result<Vec<u8>, AttributeError> {
89    let mut out = ByteWriter::new(budget);
90    out.write_u2(count(values.len(), what)?)?;
91    for value in values {
92        out.write_u2(*value)?;
93    }
94    Ok(out.into_bytes())
95}
96
97/// A standard attribute whose payload is exactly one unresolved constant-pool index.
98///
99/// This represents `ConstantValue`, `Signature`, `SourceFile`, `NestHost`, and
100/// `ModuleMainClass` metadata.
101#[derive(Clone, Copy, Debug, Eq, PartialEq)]
102pub struct IndexAttribute {
103    /// The unresolved constant-pool index.
104    pub index: u16,
105}
106
107impl IndexAttribute {
108    /// Decode the exact two-byte payload.
109    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
110        let index = reader.read_u2()?;
111        finish(reader)?;
112        Ok(Self { index })
113    }
114
115    /// Encode the index without inspecting its target.
116    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
117        let mut out = ByteWriter::new(budget);
118        out.write_u2(self.index)?;
119        Ok(out.into_bytes())
120    }
121}
122
123/// A marker attribute (`Synthetic` or `Deprecated`), whose payload must be empty.
124#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
125pub struct MarkerAttribute;
126
127impl MarkerAttribute {
128    /// Accept only an empty bounded payload.
129    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
130        finish(reader)?;
131        Ok(Self)
132    }
133
134    /// Encode the empty payload.
135    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
136        Ok(ByteWriter::new(budget).into_bytes())
137    }
138}
139
140/// An opaque byte payload, used by `SourceDebugExtension`.
141#[derive(Clone, Debug, Eq, PartialEq)]
142pub struct ByteAttribute {
143    /// Exact bytes, without text decoding or newline normalization.
144    pub bytes: Vec<u8>,
145}
146
147impl ByteAttribute {
148    /// Retain all remaining bytes.
149    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
150        let bytes = reader.take(reader.remaining())?.to_vec();
151        Ok(Self { bytes })
152    }
153
154    /// Encode the retained bytes exactly.
155    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
156        let mut out = ByteWriter::new(budget);
157        out.write_bytes(&self.bytes)?;
158        Ok(out.into_bytes())
159    }
160}
161
162/// An ordered list of unresolved indices (`Exceptions`, `NestMembers`,
163/// `PermittedSubclasses`, or `ModulePackages`).
164#[derive(Clone, Debug, Eq, PartialEq)]
165pub struct IndexListAttribute {
166    /// Indices in classfile order.
167    pub indices: Vec<u16>,
168}
169
170impl IndexListAttribute {
171    /// Decode an unsigned-short-counted index list.
172    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
173        Ok(Self {
174            indices: read_u2s(reader, "indices")?,
175        })
176    }
177
178    /// Encode the list without sorting or deduplication.
179    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
180        write_u2s(&self.indices, budget, "indices")
181    }
182}
183
184/// One `InnerClasses` table row.
185#[derive(Clone, Copy, Debug, Eq, PartialEq)]
186pub struct InnerClass {
187    /// Class index for the nested class.
188    pub inner_class_index: u16,
189    /// Enclosing class index, or zero.
190    pub outer_class_index: u16,
191    /// Simple-name index, or zero for anonymous classes.
192    pub inner_name_index: u16,
193    /// Raw inner-class access flags.
194    pub access_flags: u16,
195}
196
197/// The ordered `InnerClasses` payload.
198#[derive(Clone, Debug, Eq, PartialEq)]
199pub struct InnerClassesAttribute {
200    /// Rows in declaration order.
201    pub classes: Vec<InnerClass>,
202}
203
204impl InnerClassesAttribute {
205    /// Decode all rows without resolving their indices.
206    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
207        let n = usize::from(reader.read_u2()?);
208        reader.preflight_allocation(n)?;
209        let mut classes = Vec::with_capacity(n);
210        for _ in 0..n {
211            classes.push(InnerClass {
212                inner_class_index: reader.read_u2()?,
213                outer_class_index: reader.read_u2()?,
214                inner_name_index: reader.read_u2()?,
215                access_flags: reader.read_u2()?,
216            });
217        }
218        finish(reader)?;
219        Ok(Self { classes })
220    }
221    /// Encode rows exactly as stored.
222    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
223        let mut out = ByteWriter::new(budget);
224        out.write_u2(count(self.classes.len(), "inner classes")?)?;
225        for v in &self.classes {
226            out.write_u2(v.inner_class_index)?;
227            out.write_u2(v.outer_class_index)?;
228            out.write_u2(v.inner_name_index)?;
229            out.write_u2(v.access_flags)?;
230        }
231        Ok(out.into_bytes())
232    }
233}
234
235/// The `EnclosingMethod` payload; a zero method index denotes no specific method.
236#[derive(Clone, Copy, Debug, Eq, PartialEq)]
237pub struct EnclosingMethodAttribute {
238    /// Enclosing class index.
239    pub class_index: u16,
240    /// Name-and-type index, or zero.
241    pub method_index: u16,
242}
243
244impl EnclosingMethodAttribute {
245    /// Decode the two unresolved indices.
246    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
247        let class_index = reader.read_u2()?;
248        let method_index = reader.read_u2()?;
249        finish(reader)?;
250        Ok(Self {
251            class_index,
252            method_index,
253        })
254    }
255    /// Encode the two indices.
256    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
257        let mut out = ByteWriter::new(budget);
258        out.write_u2(self.class_index)?;
259        out.write_u2(self.method_index)?;
260        Ok(out.into_bytes())
261    }
262}
263
264/// One source line mapping in a `LineNumberTable`.
265#[derive(Clone, Copy, Debug, Eq, PartialEq)]
266pub struct LineNumber {
267    /// Code-array start offset.
268    pub start_pc: u16,
269    /// Source line number.
270    pub line_number: u16,
271}
272
273/// An ordered `LineNumberTable` payload.
274#[derive(Clone, Debug, Eq, PartialEq)]
275pub struct LineNumberTableAttribute {
276    /// Mappings in encoded order.
277    pub lines: Vec<LineNumber>,
278}
279
280impl LineNumberTableAttribute {
281    /// Decode mappings without validating instruction boundaries.
282    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
283        let n = usize::from(reader.read_u2()?);
284        reader.preflight_allocation(n)?;
285        let mut lines = Vec::with_capacity(n);
286        for _ in 0..n {
287            lines.push(LineNumber {
288                start_pc: reader.read_u2()?,
289                line_number: reader.read_u2()?,
290            });
291        }
292        finish(reader)?;
293        Ok(Self { lines })
294    }
295    /// Encode mappings exactly as stored.
296    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
297        let mut out = ByteWriter::new(budget);
298        out.write_u2(count(self.lines.len(), "line numbers")?)?;
299        for v in &self.lines {
300            out.write_u2(v.start_pc)?;
301            out.write_u2(v.line_number)?;
302        }
303        Ok(out.into_bytes())
304    }
305}
306
307/// One local-variable range, shared by `LocalVariableTable` and `LocalVariableTypeTable`.
308#[derive(Clone, Copy, Debug, Eq, PartialEq)]
309pub struct LocalVariable {
310    /// Code-array start offset.
311    pub start_pc: u16,
312    /// Range length.
313    pub length: u16,
314    /// Name index.
315    pub name_index: u16,
316    /// Descriptor or signature index.
317    pub type_index: u16,
318    /// Local-variable slot.
319    pub slot: u16,
320}
321
322/// An ordered local-variable table payload.
323#[derive(Clone, Debug, Eq, PartialEq)]
324pub struct LocalVariablesAttribute {
325    /// Ranges in encoded order.
326    pub variables: Vec<LocalVariable>,
327}
328
329impl LocalVariablesAttribute {
330    /// Decode ranges without resolving names or checking code offsets.
331    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
332        let n = usize::from(reader.read_u2()?);
333        reader.preflight_allocation(n)?;
334        let mut variables = Vec::with_capacity(n);
335        for _ in 0..n {
336            variables.push(LocalVariable {
337                start_pc: reader.read_u2()?,
338                length: reader.read_u2()?,
339                name_index: reader.read_u2()?,
340                type_index: reader.read_u2()?,
341                slot: reader.read_u2()?,
342            });
343        }
344        finish(reader)?;
345        Ok(Self { variables })
346    }
347    /// Encode ranges exactly as stored.
348    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
349        let mut out = ByteWriter::new(budget);
350        out.write_u2(count(self.variables.len(), "local variables")?)?;
351        for v in &self.variables {
352            out.write_u2(v.start_pc)?;
353            out.write_u2(v.length)?;
354            out.write_u2(v.name_index)?;
355            out.write_u2(v.type_index)?;
356            out.write_u2(v.slot)?;
357        }
358        Ok(out.into_bytes())
359    }
360}
361
362/// One `MethodParameters` row.
363#[derive(Clone, Copy, Debug, Eq, PartialEq)]
364pub struct MethodParameter {
365    /// Name index, or zero.
366    pub name_index: u16,
367    /// Raw parameter access flags.
368    pub access_flags: u16,
369}
370
371/// The ordered `MethodParameters` payload.
372#[derive(Clone, Debug, Eq, PartialEq)]
373pub struct MethodParametersAttribute {
374    /// Parameters in descriptor order.
375    pub parameters: Vec<MethodParameter>,
376}
377
378impl MethodParametersAttribute {
379    /// Decode the u1-counted parameter table.
380    pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
381        let n = usize::from(reader.read_u1()?);
382        reader.preflight_allocation(n)?;
383        let mut parameters = Vec::with_capacity(n);
384        for _ in 0..n {
385            parameters.push(MethodParameter {
386                name_index: reader.read_u2()?,
387                access_flags: reader.read_u2()?,
388            });
389        }
390        finish(reader)?;
391        Ok(Self { parameters })
392    }
393    /// Encode the parameter table.
394    pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
395        let mut out = ByteWriter::new(budget);
396        out.write_u1(u8::try_from(self.parameters.len()).map_err(|_| {
397            error(
398                AttributeErrorKind::CountOverflow,
399                0,
400                "too many method parameters",
401            )
402        })?)?;
403        for v in &self.parameters {
404            out.write_u2(v.name_index)?;
405            out.write_u2(v.access_flags)?;
406        }
407        Ok(out.into_bytes())
408    }
409}