1use core::slice;
22
23use crate::message;
24use crate::message::Allocator;
25use crate::message::ReaderSegments;
26use crate::private::read_limiter::ReadLimiter;
27use crate::private::units::*;
28use crate::OutputSegments;
29use crate::{Error, ErrorKind, Result};
30
31pub type SegmentId = u32;
32
33pub unsafe trait ReaderArena {
34 fn get_segment(&self, id: u32) -> Result<(*const u8, u32)>;
36
37 unsafe fn check_offset(
38 &self,
39 segment_id: u32,
40 start: *const u8,
41 offset_in_words: i32,
42 ) -> Result<*const u8> {
43 let (segment_start, segment_len) = self.get_segment(segment_id)?;
44 let this_start: usize = segment_start as usize;
45 let this_size: usize = segment_len as usize * BYTES_PER_WORD;
46 let offset: i64 = i64::from(offset_in_words) * i64::try_from(BYTES_PER_WORD).unwrap();
47 let start_idx = start as usize;
48 if start_idx < this_start {
49 return Err(Error::from_kind(
50 ErrorKind::MessageContainsOutOfBoundsPointer,
51 ));
52 }
53 let target_idx = i64::try_from(start_idx - this_start).unwrap() + offset;
54 if target_idx < 0 || usize::try_from(target_idx).unwrap() > this_size {
55 Err(Error::from_kind(
56 ErrorKind::MessageContainsOutOfBoundsPointer,
57 ))
58 } else {
59 unsafe { Ok(start.offset(isize::try_from(offset).unwrap())) }
60 }
61 }
62
63 fn contains_interval(&self, segment_id: u32, start: *const u8, size: usize) -> Result<()>;
64 fn amplified_read(&self, virtual_amount: u64) -> Result<()>;
65
66 fn nesting_limit(&self) -> i32;
67
68 fn size_in_words(&self) -> usize;
69
70 }
74
75pub struct ReaderArenaImpl<S> {
76 segments: S,
77 read_limiter: ReadLimiter,
78 nesting_limit: i32,
79}
80
81#[cfg(feature = "sync_reader")]
82fn _assert_sync() {
83 fn _assert_sync<T: Sync>() {}
84 fn _assert_reader<S: ReaderSegments + Sync>() {
85 _assert_sync::<ReaderArenaImpl<S>>();
86 }
87}
88
89impl<S> ReaderArenaImpl<S>
90where
91 S: ReaderSegments,
92{
93 pub fn new(segments: S, options: message::ReaderOptions) -> Self {
94 let limiter = ReadLimiter::new(options.traversal_limit_in_words);
95 Self {
96 segments,
97 read_limiter: limiter,
98 nesting_limit: options.nesting_limit,
99 }
100 }
101
102 pub fn into_segments(self) -> S {
103 self.segments
104 }
105
106 pub(crate) fn get_segments(&self) -> &S {
107 &self.segments
108 }
109}
110
111unsafe impl<S> ReaderArena for ReaderArenaImpl<S>
112where
113 S: ReaderSegments,
114{
115 fn get_segment(&self, id: u32) -> Result<(*const u8, u32)> {
116 match self.segments.get_segment(id) {
117 Some(seg) => {
118 #[cfg(not(feature = "unaligned"))]
119 {
120 if seg.as_ptr() as usize % BYTES_PER_WORD != 0 {
121 return Err(Error::from_kind(ErrorKind::UnalignedSegment));
122 }
123 }
124
125 Ok((
126 seg.as_ptr(),
127 u32::try_from(seg.len() / BYTES_PER_WORD).unwrap(),
128 ))
129 }
130 None => Err(Error::from_kind(ErrorKind::InvalidSegmentId(id))),
131 }
132 }
133
134 fn contains_interval(&self, id: u32, start: *const u8, size_in_words: usize) -> Result<()> {
135 let (segment_start, segment_len) = self.get_segment(id)?;
136 let this_start: usize = segment_start as usize;
137 let this_size: usize = segment_len as usize * BYTES_PER_WORD;
138 let start = start as usize;
139 let size = size_in_words * BYTES_PER_WORD;
140
141 if !(start >= this_start && start - this_start + size <= this_size) {
142 Err(Error::from_kind(
143 ErrorKind::MessageContainsOutOfBoundsPointer,
144 ))
145 } else {
146 self.read_limiter.can_read(size_in_words)
147 }
148 }
149
150 fn amplified_read(&self, virtual_amount: u64) -> Result<()> {
151 self.read_limiter
152 .can_read(usize::try_from(virtual_amount).unwrap())
153 }
154
155 fn nesting_limit(&self) -> i32 {
156 self.nesting_limit
157 }
158
159 fn size_in_words(&self) -> usize {
160 let mut result = 0;
161 for ii in 0..u32::try_from(self.segments.len()).unwrap() {
162 if let Some(seg) = self.segments.get_segment(ii) {
163 result += seg.len() / BYTES_PER_WORD;
164 }
165 }
166 result
167 }
168}
169
170pub unsafe trait BuilderArena: ReaderArena {
171 fn allocate(&mut self, segment_id: u32, amount: WordCount32) -> Option<u32>;
172 fn allocate_anywhere(&mut self, amount: u32) -> (SegmentId, u32);
173 fn get_segment_mut(&mut self, id: u32) -> (*mut u8, u32);
174
175 fn as_reader(&self) -> &dyn ReaderArena;
176}
177
178struct BuilderSegment {
180 ptr: core::ptr::NonNull<u8>,
182
183 capacity: u32,
186
187 allocated: u32,
189}
190
191#[cfg(feature = "alloc")]
192type BuilderSegmentArray = alloc::vec::Vec<BuilderSegment>;
193
194#[cfg(not(feature = "alloc"))]
195#[derive(Default)]
196struct BuilderSegmentArray {
197 segment: Option<BuilderSegment>,
199}
200
201#[cfg(not(feature = "alloc"))]
202impl BuilderSegmentArray {
203 fn len(&self) -> usize {
204 match self.segment {
205 Some(_) => 1,
206 None => 0,
207 }
208 }
209
210 fn push(&mut self, segment: BuilderSegment) {
211 if self.segment.is_some() {
212 panic!("multiple segments are not supported in no-alloc mode")
213 }
214 self.segment = Some(segment);
215 }
216}
217
218#[cfg(not(feature = "alloc"))]
219impl core::ops::Index<usize> for BuilderSegmentArray {
220 type Output = BuilderSegment;
221
222 fn index(&self, index: usize) -> &Self::Output {
223 assert_eq!(index, 0);
224 match &self.segment {
225 Some(s) => s,
226 None => panic!("no segment"),
227 }
228 }
229}
230
231#[cfg(not(feature = "alloc"))]
232impl core::ops::IndexMut<usize> for BuilderSegmentArray {
233 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
234 assert_eq!(index, 0);
235 match &mut self.segment {
236 Some(s) => s,
237 None => panic!("no segment"),
238 }
239 }
240}
241
242pub struct BuilderArenaImplInner<A>
243where
244 A: Allocator,
245{
246 allocator: Option<A>, segments: BuilderSegmentArray,
248}
249
250pub struct BuilderArenaImpl<A>
251where
252 A: Allocator,
253{
254 inner: BuilderArenaImplInner<A>,
255}
256
257unsafe impl<A> Send for BuilderArenaImpl<A> where A: Send + Allocator {}
260unsafe impl<A> Sync for BuilderArenaImpl<A> where A: Sync + Allocator {}
261
262impl<A> BuilderArenaImpl<A>
263where
264 A: Allocator,
265{
266 pub fn new(allocator: A) -> Self {
267 Self {
268 inner: BuilderArenaImplInner {
269 allocator: Some(allocator),
270 segments: Default::default(),
271 },
272 }
273 }
274
275 pub fn allocate_segment(&mut self, minimum_size: u32) -> Result<()> {
277 self.inner.allocate_segment(minimum_size)
278 }
279
280 pub fn get_segments_for_output(&self) -> OutputSegments<'_> {
281 let reff = &self.inner;
282 if reff.segments.len() == 1 {
283 let seg = &reff.segments[0];
284
285 let slice = unsafe {
289 slice::from_raw_parts(
290 seg.ptr.as_ptr() as *const _,
291 seg.allocated as usize * BYTES_PER_WORD,
292 )
293 };
294 OutputSegments::SingleSegment([slice])
295 } else {
296 #[cfg(feature = "alloc")]
297 {
298 let mut v = alloc::vec::Vec::with_capacity(reff.segments.len());
299 for seg in &reff.segments {
300 let slice = unsafe {
302 slice::from_raw_parts(
303 seg.ptr.as_ptr() as *const _,
304 seg.allocated as usize * BYTES_PER_WORD,
305 )
306 };
307 v.push(slice);
308 }
309 OutputSegments::MultiSegment(v)
310 }
311 #[cfg(not(feature = "alloc"))]
312 {
313 panic!("invalid number of segments: {}", reff.segments.len());
314 }
315 }
316 }
317
318 pub fn len(&self) -> usize {
319 self.inner.segments.len()
320 }
321
322 pub fn is_empty(&self) -> bool {
323 self.len() == 0
324 }
325
326 pub fn into_allocator(mut self) -> A {
329 self.inner.deallocate_all();
330 self.inner.allocator.take().unwrap()
331 }
332}
333
334unsafe impl<A> ReaderArena for BuilderArenaImpl<A>
335where
336 A: Allocator,
337{
338 fn get_segment(&self, id: u32) -> Result<(*const u8, u32)> {
339 let seg = &self.inner.segments[id as usize];
340 Ok((seg.ptr.as_ptr(), seg.allocated))
341 }
342
343 unsafe fn check_offset(
344 &self,
345 _segment_id: u32,
346 start: *const u8,
347 offset_in_words: i32,
348 ) -> Result<*const u8> {
349 unsafe {
350 Ok(start.offset(
351 isize::try_from(
352 i64::from(offset_in_words) * i64::try_from(BYTES_PER_WORD).unwrap(),
353 )
354 .unwrap(),
355 ))
356 }
357 }
358
359 fn contains_interval(&self, _id: u32, _start: *const u8, _size: usize) -> Result<()> {
360 Ok(())
361 }
362
363 fn amplified_read(&self, _virtual_amount: u64) -> Result<()> {
364 Ok(())
365 }
366
367 fn nesting_limit(&self) -> i32 {
368 0x7fffffff
369 }
370
371 fn size_in_words(&self) -> usize {
372 let mut result = 0;
373 for ii in 0..self.inner.segments.len() {
374 result += self.inner.segments[ii].allocated as usize
375 }
376 result
377 }
378}
379
380impl<A> BuilderArenaImplInner<A>
381where
382 A: Allocator,
383{
384 fn allocate_segment(&mut self, minimum_size: WordCount32) -> Result<()> {
386 let seg = match &mut self.allocator {
387 Some(a) => a.allocate_segment(minimum_size),
388 None => unreachable!(),
389 };
390 self.segments.push(BuilderSegment {
391 ptr: seg.0,
392 capacity: seg.1,
393 allocated: 0,
394 });
395 Ok(())
396 }
397
398 fn allocate(&mut self, segment_id: u32, amount: WordCount32) -> Option<u32> {
399 let seg = &mut self.segments[segment_id as usize];
400 if amount > seg.capacity - seg.allocated {
401 None
402 } else {
403 let result = seg.allocated;
404 seg.allocated += amount;
405 Some(result)
406 }
407 }
408
409 fn allocate_anywhere(&mut self, amount: u32) -> (SegmentId, u32) {
410 let allocated_len = u32::try_from(self.segments.len()).unwrap();
412 for segment_id in 0..allocated_len {
413 if let Some(idx) = self.allocate(segment_id, amount) {
414 return (segment_id, idx);
415 }
416 }
417
418 self.allocate_segment(amount).expect("allocate new segment");
421 (
422 allocated_len,
423 self.allocate(allocated_len, amount)
424 .expect("use freshly-allocated segment"),
425 )
426 }
427
428 fn deallocate_all(&mut self) {
429 if let Some(a) = &mut self.allocator {
430 #[cfg(feature = "alloc")]
431 for seg in &self.segments {
432 unsafe {
433 a.deallocate_segment(seg.ptr, seg.capacity, seg.allocated);
434 }
435 }
436
437 #[cfg(not(feature = "alloc"))]
438 if let Some(seg) = &self.segments.segment {
439 unsafe {
440 a.deallocate_segment(seg.ptr, seg.capacity, seg.allocated);
441 }
442 }
443 }
444 }
445
446 fn get_segment_mut(&mut self, id: u32) -> (*mut u8, u32) {
447 let seg = &self.segments[id as usize];
448 (seg.ptr.as_ptr(), seg.capacity)
449 }
450}
451
452unsafe impl<A> BuilderArena for BuilderArenaImpl<A>
453where
454 A: Allocator,
455{
456 fn allocate(&mut self, segment_id: u32, amount: WordCount32) -> Option<u32> {
457 self.inner.allocate(segment_id, amount)
458 }
459
460 fn allocate_anywhere(&mut self, amount: u32) -> (SegmentId, u32) {
461 self.inner.allocate_anywhere(amount)
462 }
463
464 fn get_segment_mut(&mut self, id: u32) -> (*mut u8, u32) {
465 self.inner.get_segment_mut(id)
466 }
467
468 fn as_reader(&self) -> &dyn ReaderArena {
469 self
470 }
471}
472
473impl<A> Drop for BuilderArenaImplInner<A>
474where
475 A: Allocator,
476{
477 fn drop(&mut self) {
478 self.deallocate_all()
479 }
480}
481
482pub struct NullArena;
483
484unsafe impl ReaderArena for NullArena {
485 fn get_segment(&self, _id: u32) -> Result<(*const u8, u32)> {
486 Err(Error::from_kind(ErrorKind::TriedToReadFromNullArena))
487 }
488
489 unsafe fn check_offset(
490 &self,
491 _segment_id: u32,
492 start: *const u8,
493 offset_in_words: i32,
494 ) -> Result<*const u8> {
495 let offset_in_bytes = (offset_in_words as i64) * i64::try_from(BYTES_PER_WORD).unwrap();
496 unsafe { Ok(start.offset(isize::try_from(offset_in_bytes).unwrap())) }
497 }
498
499 fn contains_interval(&self, _id: u32, _start: *const u8, _size: usize) -> Result<()> {
500 Ok(())
501 }
502
503 fn amplified_read(&self, _virtual_amount: u64) -> Result<()> {
504 Ok(())
505 }
506
507 fn nesting_limit(&self) -> i32 {
508 0x7fffffff
509 }
510
511 fn size_in_words(&self) -> usize {
512 0
513 }
514}
515
516pub struct GeneratedCodeArena {
521 words: &'static [crate::Word],
522}
523
524impl GeneratedCodeArena {
525 pub const fn new(words: &'static [crate::Word]) -> Self {
526 assert!((words.len() as u64) < u32::MAX as u64);
527 Self { words }
528 }
529}
530
531unsafe impl ReaderArena for GeneratedCodeArena {
532 fn get_segment(&self, id: u32) -> Result<(*const u8, u32)> {
533 if id == 0 {
534 Ok((
535 self.words.as_ptr() as *const _,
536 u32::try_from(self.words.len()).unwrap(),
537 ))
538 } else {
539 Err(Error::from_kind(ErrorKind::InvalidSegmentId(id)))
540 }
541 }
542
543 fn contains_interval(&self, id: u32, start: *const u8, size_in_words: usize) -> Result<()> {
544 let (segment_start, segment_len) = self.get_segment(id)?;
545 let this_start: usize = segment_start as usize;
546 let this_size: usize = segment_len as usize * BYTES_PER_WORD;
547 let start = start as usize;
548 let size = size_in_words * BYTES_PER_WORD;
549
550 if !(start >= this_start && start - this_start + size <= this_size) {
551 Err(Error::from_kind(
552 ErrorKind::MessageContainsOutOfBoundsPointer,
553 ))
554 } else {
555 Ok(())
556 }
557 }
558
559 fn amplified_read(&self, _virtual_amount: u64) -> Result<()> {
560 Ok(())
561 }
562
563 fn nesting_limit(&self) -> i32 {
564 0x7fffffff
565 }
566
567 fn size_in_words(&self) -> usize {
568 self.words.len()
569 }
570}