1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use crate::{
Error, Reader,
broad_routes::BroadRoutes,
layout::{Encoding, Section, slice, u32_at},
packed,
payload::Slots,
};
/// Physical target encoding; shared aliases do not expand these sections.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionEncoding {
/// Augmented interval rows supporting overlaps and inclusive ranges.
Interval,
/// Disjoint address/network columns with a fence per 256 assertions.
Packed,
/// Sorted exact-ASN key and insertion-ID pairs.
Asn,
}
/// Physical rows, bytes and column types for one encoded section.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SectionInspection {
/// Observed encoding, without assumptions about alternative representations.
pub encoding: SectionEncoding,
/// Physical assertion count, excluding projected aliases.
pub records: usize,
/// Encoded section bytes, including packed fences when present.
pub bytes: usize,
/// Packed blocks, zero for other encodings.
pub blocks: usize,
/// Blocks using exact-bit deltas; remaining blocks use byte widths.
pub bitpacked_blocks: usize,
}
/// Reference encoding; opaque payload contents are never decoded.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PayloadReferences {
/// Offset/length spans of this many bytes per assertion.
Spans {
/// Bytes per span.
width: usize,
},
/// Fixed payload length and compact offsets.
Fixed {
/// Bytes in each payload.
length: usize,
/// Bytes per offset; zero for empty payloads.
width: u8,
},
/// Shared span directory with compact ordinals.
Indexed {
/// Number of shared payload spans.
values: usize,
/// Bytes per ordinal.
width: u8,
},
}
/// Encoded accounting and reader allocation capacities, not process RSS.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Inspection {
/// Outer format version (5 for an alias envelope).
pub format: u32,
/// Embedded format for aliases, otherwise equal to `format`.
pub base_format: u32,
/// Logical assertions including projected aliases.
pub records: usize,
/// Physical assertions with payload references.
pub physical_records: usize,
/// Complete backing length; ownership and residency are caller-dependent.
pub artifact_bytes: usize,
/// Base header plus any alias header/descriptors.
pub header_bytes: usize,
/// Opaque metadata bytes.
pub metadata_bytes: usize,
/// Physical IPv4 section.
pub ipv4: SectionInspection,
/// Physical IPv6 section.
pub ipv6: SectionInspection,
/// Exact-ASN section.
pub asn: SectionInspection,
/// Reference region bytes, including shared directory/descriptors.
pub reference_bytes: usize,
/// Complete opaque payload region, counting shared values once.
pub payload_bytes: usize,
/// Observed reference encoding.
pub references: PayloadReferences,
/// Explicit IPv6 alias windows.
pub alias_windows: usize,
/// Reader object size, including its inline backing object/descriptor.
pub reader_struct_bytes: usize,
/// Allocated IPv4 directory capacity, excluding its inline descriptor.
pub directory_heap_bytes: usize,
/// Allocated broad-route table capacities, excluding inline descriptors.
pub broad_route_heap_bytes: usize,
/// Allocated alias vector capacities, excluding inline descriptors.
pub alias_heap_bytes: usize,
/// Requested transient ID-bitmap bytes during validation, already released.
/// Other validation allocations are not included.
pub validation_id_bitmap_bytes: usize,
}
impl<B: AsRef<[u8]>> Reader<B> {
/// Inspect representation and allocation capacities without allocating.
///
/// Visits packed descriptors only: O(blocks), without scanning targets or
/// payloads. Header + metadata + section + reference + payload bytes sum to
/// artifact bytes. Resource fields are separate measures, not an additive RSS
/// estimate: backing may be inline, borrowed, owned or mapped. This reports
/// selected representations, not hypothetical writer choices or schemas.
///
/// # Errors
/// Returns invalid-backing errors if required headers/descriptors changed.
pub fn inspect(&self) -> Result<Inspection, Error> {
let bytes = self.bytes.as_ref();
if bytes.len() != self.layout.bytes {
return Err(Error::Invalid("inspection backing length"));
}
let base = self.layout.header_offset();
Ok(Inspection {
format: u32_at(bytes, 8)?,
base_format: u32_at(bytes, base + 8)?,
records: self.len(),
physical_records: self.layout.records,
artifact_bytes: bytes.len(),
header_bytes: base + crate::layout::HEADER,
metadata_bytes: self.layout.metadata,
ipv4: section(bytes, self.layout.v4)?,
ipv6: section(bytes, self.layout.v6)?,
asn: SectionInspection {
encoding: SectionEncoding::Asn,
records: self.layout.asns.count,
bytes: self.layout.asns.length,
blocks: 0,
bitpacked_blocks: 0,
},
reference_bytes: self.layout.payloads - self.layout.slots,
payload_bytes: bytes.len() - self.layout.payloads,
references: match self.layout.slot_encoding {
Slots::Spans(width) => PayloadReferences::Spans { width },
Slots::Fixed { length, width } => PayloadReferences::Fixed { length, width },
Slots::Indexed { values, width } => PayloadReferences::Indexed { values, width },
},
alias_windows: self
.aliases
.as_ref()
.map_or(0, |aliases| aliases.windows.len()),
reader_struct_bytes: size_of_val(self),
directory_heap_bytes: self
.ipv4_directory
.as_ref()
.map_or(0, packed::Directory::heap_bytes),
broad_route_heap_bytes: self
.broad_routes
.as_ref()
.map_or(0, BroadRoutes::heap_bytes),
alias_heap_bytes: self
.aliases
.as_ref()
.map_or(0, crate::aliases::Aliases::heap_bytes),
validation_id_bitmap_bytes: self.layout.records.div_ceil(64) * size_of::<u64>(),
})
}
}
fn section(bytes: &[u8], section: Section) -> Result<SectionInspection, Error> {
let packed = section.encoding == Encoding::Packed;
Ok(SectionInspection {
encoding: if packed {
SectionEncoding::Packed
} else {
SectionEncoding::Interval
},
records: section.count,
bytes: section.length,
blocks: if packed {
section.count.div_ceil(packed::BLOCK)
} else {
0
},
bitpacked_blocks: if packed {
packed::bitpacked_blocks(slice(bytes, section.offset, section.length)?, section.count)?
} else {
0
},
})
}