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
//! Own a parsed view past the input buffer's borrow (feature `yoke`).
//!
//! Tables and descriptor loops parse **zero-copy**, borrowing the input section
//! slice — [`PmtSection<'a>`](crate::tables::pmt::PmtSection), [`SdtSection<'a>`](crate::tables::sdt::SdtSection),
//! [`DescriptorLoop<'a>`](crate::descriptors::DescriptorLoop), and so on. That is
//! ideal for parse-and-discard, but a consumer that needs to **retain** a parsed
//! table — stash it in a struct field, a cache, or a `tokio::sync::watch`
//! channel — would otherwise have to re-parse on every access or maintain a
//! hand-written owned mirror type.
//!
//! [`Owned`] bundles the owned backing bytes (`Arc<[u8]>`) and the borrowing
//! view into one `'static`, cheaply-`Clone`, `Send + Sync` value via the
//! [`yoke`] crate. The view's lifetime disappears from your signatures, and no
//! re-parse happens on access.
//!
//! ```
//! use std::sync::Arc;
//! use dvb_si::owned::Owned;
//! use dvb_si::tables::pmt::PmtSection;
//! use broadcast_common::Parse;
//!
//! # use broadcast_common::Serialize;
//! # use dvb_si::descriptors::DescriptorLoop;
//! # use dvb_si::tables::pmt::{StreamType, PmtStream};
//! # use mpeg_ts::pid::Pid;
//! # // A minimal one-stream PMT built through the serializer (doctest only —
//! # // nothing of this ships in the library).
//! # let pmt = PmtSection::new(1, 0, true, 0, 0, Pid::new(0x0100), DescriptorLoop::new(&[]),
//! # vec![PmtStream::new(StreamType::H264, Pid::new(0x0101), DescriptorLoop::new(&[]))]);
//! # let mut section = vec![0u8; pmt.serialized_len()];
//! # pmt.serialize_into(&mut section).unwrap();
//! // `section` is the complete PMT section bytes (e.g. straight off the demux).
//! let bytes: Arc<[u8]> = Arc::from(section);
//!
//! // Parse once, keep the result — no borrow of a local buffer escapes.
//! let owned: Owned<PmtSection<'static>> =
//! Owned::try_new(bytes, |b| PmtSection::parse(b))?;
//!
//! // The owned value is 'static, so it can live in a struct field…
//! struct Cache { pmt: Owned<PmtSection<'static>> }
//! let cache = Cache { pmt: owned };
//!
//! // …and move across a thread boundary, then read the typed view back out
//! // with no re-parse.
//! let handle = std::thread::spawn(move || {
//! let pmt: &PmtSection = cache.pmt.get();
//! (pmt.program_number, pmt.streams.len())
//! });
//! let (program_number, stream_count) = handle.join().unwrap();
//! assert_eq!(program_number, 1);
//! assert_eq!(stream_count, 1);
//! # Ok::<(), dvb_si::error::Error>(())
//! ```
use Arc;
use YokeTraitHack;
use ;
/// An owned, `'static`, `Send + Sync` bundle of (backing bytes, parsed view).
///
/// `Y` is the view type with its lifetime set to `'static` — e.g.
/// `Owned<PmtSection<'static>>`, `Owned<SdtSection<'static>>`,
/// `Owned<DescriptorLoop<'static>>`. The backing buffer is an `Arc<[u8]>`, so
/// [`Clone`] is a refcount bump and the view is shared, never re-parsed.
///
/// Construct one with [`Owned::try_new`] (fallible parse) or [`Owned::new`]
/// (infallible), then read the borrowing view with [`Owned::get`].
// Cloning is a refcount bump on the `Arc<[u8]>` plus a re-binding of the
// (already-parsed) view — no re-parse. The bound mirrors yoke's own `Clone`
// impl for `Yoke<Y, CloneableCart>`.