Skip to main content

g2g_core/
element.rs

1use core::future::Future;
2use core::pin::Pin;
3
4use alloc::boxed::Box;
5
6use crate::caps::Caps;
7use crate::clock::{ClockCandidate, ClockSync};
8use crate::error::G2gError;
9use crate::format_element::{
10    legacy_sink_constraint, legacy_transform_constraint, CapsConstraint, CapsPreferences,
11};
12use crate::frame::PipelinePacket;
13use crate::memory::{DomainSet, MemoryDomainKind};
14use crate::property::{ElementMetadata, PropError, PropValue, PropertySpec};
15use crate::query::{AllocationParams, LatencyReport};
16
17#[cfg(feature = "multi-thread")]
18pub trait ElementBound: Send {}
19#[cfg(feature = "multi-thread")]
20impl<T: Send> ElementBound for T {}
21
22#[cfg(not(feature = "multi-thread"))]
23pub trait ElementBound {}
24#[cfg(not(feature = "multi-thread"))]
25impl<T> ElementBound for T {}
26
27/// Boxed future alias for dyn-safe async methods in element / sink traits.
28pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
29
30/// Downstream-originated request to renegotiate caps. Travels upstream
31/// along a link's reverse channel and is surfaced to the producing element
32/// as a [`PushOutcome::Reconfigure`].
33#[derive(Debug, Clone, PartialEq)]
34pub enum Reconfigure {
35    /// Downstream proposes specific replacement caps (Phase 3 counter).
36    Propose(Caps),
37    /// Downstream wants renegotiation but has no specific proposal โ€”
38    /// the upstream element picks freely. Equivalent to GStreamer's
39    /// bare RECONFIGURE event.
40    Renegotiate,
41    /// Downstream needs a keyframe now (no caps change): an encoder should emit
42    /// an IDR / key frame on its next output. Originated by a WebRTC egress sink
43    /// on a remote PLI (Picture Loss Indication) and carried up the reverse
44    /// channel to the encoder. The GStreamer `GstForceKeyUnit` upstream-event
45    /// analog.
46    ForceKeyframe,
47    /// The sink downstream applies an
48    /// [`OrientationMeta`](crate::meta::OrientationMeta) itself, so a rotation
49    /// upstream should attach the descriptor rather than remap the pixels. Sent
50    /// once by a display sink that can turn a buffer for free (a Wayland
51    /// `set_buffer_transform`, a KMS plane rotation) before the first frame is
52    /// pulled, and relayed past any transform that does not answer it (see
53    /// [`AsyncElement::handles_orientation`]).
54    AbsorbOrientation,
55}
56
57/// Downstream-originated quality-of-service signal: a synchronising sink is
58/// running behind the pipeline clock and dropped a late frame. Travels upstream
59/// along a link's reverse channel and is surfaced to the producing element as a
60/// [`PushOutcome::Qos`], so a source / decoder can shed load (skip frames) to let
61/// the pipeline catch up. The GStreamer QoS event analog (the
62/// [`BusMessage::Qos`](crate::BusMessage::Qos) report is the out-of-band sibling
63/// the application observes).
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub struct QosMessage {
66    /// How far past its deadline the dropped frame was, ns. Positive is late
67    /// (behind the clock); the producer skips roughly this much stream time to
68    /// catch up.
69    pub jitter_ns: i64,
70    /// Running time (PTS) of the late frame, for reference.
71    pub running_time_ns: u64,
72}
73
74/// Cumulative presentation counters a paced sink kept over a run, read via
75/// [`AsyncElement::presentation_stats`] once the sink's arm ends. `consumed`
76/// alone can't say whether frames actually reached the display on time; these
77/// counters split it into shown vs shed.
78#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
79pub struct PresentationStats {
80    /// Frames the sink actually presented (e.g. committed and acknowledged by
81    /// the display server).
82    pub presented: u64,
83    /// Frames overwritten before they ever painted (a `DropOldest` pacing
84    /// policy under a slow consumer).
85    pub dropped: u64,
86    /// Frames discarded by QoS late-drop (past their deadline beyond the
87    /// configured bound).
88    pub late_dropped: u64,
89}
90
91/// Outcome of pushing a packet downstream. Sources and transforms must
92/// react to `Reconfigure` before pushing any further data; terminal sinks
93/// and intermediate adapters that can't renegotiate may ignore it. `Qos` is
94/// advisory: the packet still flowed, but the producer may shed load.
95#[derive(Debug, Clone, PartialEq)]
96pub enum PushOutcome {
97    /// Downstream accepted the packet; continue normally.
98    Accepted,
99    /// Downstream signaled a reconfigure request between this push and
100    /// the previous one. The producer should handle the request before
101    /// pushing further `DataFrame`s.
102    Reconfigure(Reconfigure),
103    /// Downstream is behind the clock (a sink dropped a late frame). Advisory:
104    /// the producer may skip ahead to shed load. Reconfigure takes priority when
105    /// both are pending (negotiation correctness over QoS).
106    Qos(QosMessage),
107    /// Downstream reports a target send bitrate in bits/second (a WebRTC sink
108    /// relaying its congestion-control / BWE estimate). Advisory: an encoder
109    /// upstream should retarget its bitrate. Lowest priority of the reverse
110    /// signals (Reconfigure > Qos > Bitrate); a held estimate surfaces on a
111    /// later push, and BWE updates far slower than the frame rate. A target of
112    /// `0` is the shed-layer idle hint (M722): the consumer downstream is
113    /// discarding this stream (a starved simulcast layer), so the encoder
114    /// should mostly stop encoding until a non-zero target resumes it.
115    Bitrate(u32),
116}
117
118/// Downstream output for elements. Push is async so backpressure-aware
119/// implementations can await downstream capacity instead of erroring on a
120/// full link. The required method is the poll form, so a push through a
121/// `dyn OutputSink` costs no heap: `push` wraps it in the concrete
122/// [`PushFuture`] (provided here for concrete sinks and on the trait object
123/// for `&mut dyn OutputSink` callers, so `out.push(pkt).await` reads the same
124/// either way).
125pub trait OutputSink {
126    /// Drive one packet toward downstream. `packet` is `Some` until this
127    /// implementation commits it (or resolves it early: a probe drop, a
128    /// pre-send reconfigure); the caller re-polls with the same slot until
129    /// `Ready`. Taking the packet on an early outcome matches the old
130    /// by-value push, where an unsent packet was dropped with the future.
131    fn poll_push(
132        &mut self,
133        cx: &mut core::task::Context<'_>,
134        packet: &mut Option<PipelinePacket>,
135    ) -> core::task::Poll<Result<PushOutcome, G2gError>>;
136
137    /// Discard any phase a cancelled earlier push left behind. Runs once per
138    /// [`PushFuture`] construction; stateless sinks keep the no-op.
139    fn begin_push(&mut self) {}
140}
141
142/// `push` for concrete (sized) sinks. Separate from [`OutputSink`] because a
143/// provided method there is ambiguous against the inherent `push` on the
144/// trait object (an inherent impl on `dyn` does not shadow trait methods).
145pub trait OutputSinkExt: OutputSink + Sized {
146    fn push(&mut self, packet: PipelinePacket) -> PushFuture<'_, Self> {
147        self.begin_push();
148        PushFuture {
149            sink: self,
150            packet: Some(packet),
151        }
152    }
153}
154
155impl<S: OutputSink> OutputSinkExt for S {}
156
157impl<'e> dyn OutputSink + 'e {
158    /// [`OutputSink::push`] for trait objects (the provided method needs
159    /// `Self: Sized`).
160    pub fn push(&mut self, packet: PipelinePacket) -> PushFuture<'_, dyn OutputSink + 'e> {
161        self.begin_push();
162        PushFuture {
163            sink: self,
164            packet: Some(packet),
165        }
166    }
167}
168
169/// Concrete future behind [`OutputSink::push`]: the packet slot
170/// [`OutputSink::poll_push`] drains. No heap.
171#[allow(missing_debug_implementations)]
172pub struct PushFuture<'a, S: OutputSink + ?Sized> {
173    sink: &'a mut S,
174    packet: Option<PipelinePacket>,
175}
176
177impl<S: OutputSink + ?Sized> Future for PushFuture<'_, S> {
178    type Output = Result<PushOutcome, G2gError>;
179
180    fn poll(
181        self: Pin<&mut Self>,
182        cx: &mut core::task::Context<'_>,
183    ) -> core::task::Poll<Self::Output> {
184        let this = self.get_mut();
185        this.sink.poll_push(cx, &mut this.packet)
186    }
187}
188
189// Closed set: intentionally exhaustive (not #[non_exhaustive]); see STABILITY.md.
190#[derive(Debug)]
191pub enum ConfigureOutcome {
192    Accepted,
193    ReFixate(Caps),
194}
195
196impl ConfigureOutcome {
197    /// Reject a mid-negotiation renegotiation request: at startup the caps handed
198    /// to `configure_pipeline` are already fixated, so an element that answers
199    /// `ReFixate` cannot be honored and is a hard error. Collapses the
200    /// `if let ConfigureOutcome::ReFixate(_) = elem.configure_pipeline(..)? { return
201    /// Err(FixationFailed) }` guard repeated across the runner startup paths.
202    pub fn reject_refixate(self) -> Result<(), G2gError> {
203        match self {
204            ConfigureOutcome::Accepted => Ok(()),
205            ConfigureOutcome::ReFixate(_) => Err(G2gError::FixationFailed),
206        }
207    }
208}
209
210pub trait AsyncElement: ElementBound {
211    type ProcessFuture<'a>: Future<Output = Result<(), G2gError>> + 'a
212    where
213        Self: 'a;
214
215    fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError>;
216
217    fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError>;
218
219    /// Receive this element's negotiated OUTPUT (source-pad) caps after the
220    /// solve, alongside the input caps from [`configure_pipeline`] (M185). A
221    /// geometry / format / rate-changing transform (videoscale, videoconvert,
222    /// audioresample) uses this to take its target from a downstream capsfilter
223    /// instead of its own properties, the gst caps-driven idiom. Default: no-op,
224    /// so elements that don't need it (and runners that don't yet deliver it)
225    /// are unaffected. Called only on transforms, with their single output
226    /// link's caps; sources and sinks never receive it.
227    fn configure_output(&mut self, _output_caps: &Caps) -> Result<(), G2gError> {
228        Ok(())
229    }
230
231    fn process<'a>(
232        &'a mut self,
233        packet: PipelinePacket,
234        out: &'a mut dyn OutputSink,
235    ) -> Self::ProcessFuture<'a>;
236
237    /// This element's contribution to the pipeline latency query (M12).
238    /// Default: zero, non-live. Transforms that buffer (jitter buffers,
239    /// reorder queues) and live sources override this; the linear runners
240    /// fold the chain into `RunStats::latency`.
241    fn latency(&self) -> LatencyReport {
242        LatencyReport::ZERO
243    }
244
245    /// The memory domain of the frames this element emits on its output pad.
246    /// Default [`System`](MemoryDomainKind::System); a GPU producer (a hardware
247    /// decoder emitting into VRAM, a wgpu/CUDA bridge) overrides it. Surfaced
248    /// per edge by the negotiate-only path so the DOT dump can mark the GPU /
249    /// zero-copy links (it is not part of `Caps`; see DESIGN.md 4.13.9).
250    fn output_memory(&self) -> MemoryDomainKind {
251        MemoryDomainKind::System
252    }
253
254    /// The full set of memory domains this element *can* emit on its output pad,
255    /// not just its preferred one. The producer-capability half of the M351
256    /// two-sided allocation-domain negotiation: the runner intersects it with the
257    /// downstream consumers' acceptance set and settles on a single domain, so a
258    /// decoder that can deliver to System *or* stay resident on the GPU lets the
259    /// runner keep the frame copy-free when a downstream wants it. Default: just
260    /// [`output_memory`](Self::output_memory), so a single-domain element
261    /// negotiates exactly as before. A multi-domain producer overrides this.
262    fn output_domains(&self) -> DomainSet {
263        DomainSet::only(self.output_memory())
264    }
265
266    /// The memory domains this element can accept on its *input* pad (M354), for
267    /// the domain-converter auto-plug. Default [`DomainSet::ALL`] (no requirement,
268    /// so no converter is forced); a domain-strict element (a CUDA encoder/sink
269    /// that needs device-resident input) narrows it, and the auto-plug splices a
270    /// converter when the upstream cannot produce a domain in this set. A pure
271    /// pass-through element (a memory-domain converter, an aggregator) leaves it
272    /// `ALL`. Caps-free so the splice runs before the caps solve.
273    fn input_domains(&self) -> DomainSet {
274        DomainSet::ALL
275    }
276
277    /// Answer the upstream peer's allocation query (M12): the buffer size,
278    /// count, alignment, and memory domain this element needs allocated so a
279    /// pool can be handed over without a copy. Default: no preference
280    /// (`None`). A transform that has already received its own downstream
281    /// proposal via [`configure_allocation`](Self::configure_allocation) can
282    /// fold it in with [`AllocationParams::merge`].
283    fn propose_allocation(&self, _caps: &Caps) -> Option<AllocationParams> {
284        None
285    }
286
287    /// Receive the downstream peer's allocation proposal (M12) so this element
288    /// can allocate its output buffers from a compatible pool. Default:
289    /// ignore and allocate however the element sees fit.
290    fn configure_allocation(&mut self, _params: &AllocationParams) {}
291
292    /// Offer a clock to the pipeline's clock election (M12). Default: none.
293    /// Elements that pace to real hardware (an audio sink to its DAC) override
294    /// this; the runner elects the highest-priority offered clock.
295    fn provide_clock(&self) -> Option<ClockCandidate> {
296        None
297    }
298
299    /// Receive the pipeline's elected clock + base time after election, so a
300    /// sink can present each frame at its running-time deadline (PTS mapped
301    /// through the active `Segment`) โ€” the "use PTS to decide when to display"
302    /// path. The runner calls this once before streaming, only when a clock was
303    /// elected. Default: ignore (present as fast as backpressure allows, the
304    /// pre-sync behaviour). See [`ClockSync`].
305    fn set_clock_sync(&mut self, _sync: ClockSync) {}
306
307    /// Take any QoS signal this element wants to send upstream, consuming it. A
308    /// synchronising sink that dropped a late frame returns a [`QosMessage`]
309    /// here; the runner forwards it onto the element's incoming link, where the
310    /// producer observes it as [`PushOutcome::Qos`]. Called by the runner after
311    /// each `process`. Default: nothing to send.
312    fn take_qos(&mut self) -> Option<QosMessage> {
313        None
314    }
315
316    /// Cumulative presentation counters a paced sink kept over the run, read by
317    /// the runner once its arm ends and surfaced in `RunStats::per_element`. A
318    /// display / audio sink that counts what it actually presented overrides
319    /// this. Default: not a presenting sink.
320    fn presentation_stats(&self) -> Option<PresentationStats> {
321        None
322    }
323
324    /// Take any [`Reconfigure`] this element wants to send upstream, consuming
325    /// it. The sink/transform analog of [`Self::take_qos`]: the runner forwards
326    /// it onto the element's incoming link, where the producer observes it as
327    /// [`PushOutcome::Reconfigure`]. The keyframe-request path uses this: a
328    /// WebRTC egress sink that received a remote PLI returns
329    /// [`Reconfigure::ForceKeyframe`] so the upstream encoder emits an IDR.
330    /// Called by the runner after each `process`. Default: nothing to send.
331    fn take_reconfigure(&mut self) -> Option<Reconfigure> {
332        None
333    }
334
335    /// Take a target send bitrate (bits/second) this element wants to push
336    /// upstream, consuming it. A WebRTC egress sink returns its latest
337    /// congestion-control / BWE estimate here; the runner forwards it onto the
338    /// incoming link, where the encoder observes it as [`PushOutcome::Bitrate`]
339    /// and retargets. Called by the runner after each `process`. Default: none.
340    fn take_bitrate(&mut self) -> Option<u32> {
341        None
342    }
343
344    /// Whether this element consumes a downstream keyframe request
345    /// (`PushOutcome::Reconfigure(ForceKeyframe)`) itself, i.e. it is an
346    /// encoder that forces an IDR. Default `false`: the runner then relays the
347    /// request onto the element's input link (M720), so a PLI crosses any
348    /// number of pass-through transforms (a parser between the encoder and a
349    /// WebRTC sink) to reach the encoder.
350    fn handles_keyframe_requests(&self) -> bool {
351        false
352    }
353
354    /// As [`Self::handles_keyframe_requests`], for a downstream bitrate target
355    /// (`PushOutcome::Bitrate`): an encoder that retargets returns `true`.
356    fn handles_bitrate_requests(&self) -> bool {
357        false
358    }
359
360    /// Whether this sink applies an
361    /// [`OrientationMeta`](crate::meta::OrientationMeta) itself, i.e. it can
362    /// turn the picture for free at present time. The runner sends
363    /// [`Reconfigure::AbsorbOrientation`] up this sink's input link before the
364    /// first frame is pulled, so a `videoflip` upstream attaches the descriptor
365    /// instead of remapping pixels. Default `false`: the flip realizes the
366    /// rotation as it always did.
367    fn absorbs_orientation(&self) -> bool {
368        false
369    }
370
371    /// Whether [`Reconfigure::AbsorbOrientation`] stops at this element instead
372    /// of being relayed toward the source. `true` for `videoflip`, which answers
373    /// it by switching to the descriptor, and for any transform whose output
374    /// geometry is chosen in the buffer's stored coordinates (a crop), which
375    /// would mean something different once the picture is turned. Default
376    /// `false`: the advertisement crosses.
377    ///
378    /// An element that returns `true` sees the signal as
379    /// [`PushOutcome::Reconfigure`] from its own `push`, and the pre-send check
380    /// holds that packet back rather than enqueuing it, so it has to push the
381    /// packet again.
382    fn handles_orientation(&self) -> bool {
383        false
384    }
385
386    /// Whether this element acts on a downstream QoS report itself, ie it sheds
387    /// work when the sink is behind (a decoder skipping non-reference frames).
388    /// Default `false`: the runner relays the report onto the element's input
389    /// link (M175) so it reaches the source, and `process` never sees it.
390    /// `true` surfaces it as [`PushOutcome::Qos`] from the element's own `push`
391    /// instead, and the relay stops here.
392    fn handles_qos(&self) -> bool {
393        false
394    }
395
396    /// Declares that this element changes the caps "domain" between its
397    /// input and output: a decoder turns compressed bitstream into raw
398    /// pixels, an encoder turns raw pixels into compressed bitstream, a
399    /// format converter shifts color space, etc. Default: false.
400    ///
401    /// Currently informational. The runner uses a single linear caps
402    /// cascade and the three workarounds documented in
403    /// `architecture_caps_nego_debt` apply on its behalf. The planned
404    /// caps redesign (Plan 2) will use this hint to split the pipeline
405    /// into per-domain negotiation segments, eliminating the
406    /// pass-through `intercept_caps` and deferred-configure dance that
407    /// sinks downstream of a boundary currently rely on.
408    ///
409    /// Declaring this true today changes no behavior โ€” it's a forward
410    /// declaration so the redesign can roll out without simultaneously
411    /// migrating every decoder.
412    fn is_format_boundary(&self) -> bool {
413        false
414    }
415
416    /// Derive the element's *output* caps from its negotiated input
417    /// caps. Only consulted by the runner when `is_format_boundary()`
418    /// is true. Default: pass input through (correct for non-boundary
419    /// elements that don't change format).
420    ///
421    /// Boundary elements (decoders, encoders, format converters)
422    /// override this to advertise their post-transform caps so the
423    /// downstream segment can negotiate honestly. A decoder typically
424    /// reads dims from the input caps (already populated from the
425    /// stream's SPS / container header) and returns raw video caps at
426    /// matching geometry.
427    ///
428    /// If the output caps genuinely can't be known until first decoded
429    /// frame (rare for modern stream containers), return ranged caps
430    /// here and emit a fixing `CapsChanged` mid-stream.
431    fn propose_output_caps(&self, input: &Caps) -> Caps {
432        input.clone()
433    }
434
435    /// The metadata [`Transform`](crate::meta::Transform) this element applies to
436    /// per-frame metadata, or `None` to opt out (the default). When `Some(t)` the
437    /// runner clones each input frame's metadata,
438    /// [`propagate(t)`](crate::meta::FrameMetaSet::propagate)s it, and attaches
439    /// the survivors to output frames whose own metadata is empty
440    /// (element-authored meta is never overwritten). `None` means the element
441    /// carries meta through itself (a pass-through forwarding the same frame) or
442    /// produces none, so the runner does nothing. Association is exact for a
443    /// 1-in-1-out transform; a pipelined element gets most-recent-input
444    /// association. See DESIGN.md 5.4.
445    #[cfg(feature = "metadata")]
446    fn meta_transform(&self) -> Option<crate::meta::Transform> {
447        None
448    }
449
450    /// The per-frame metadata this element wants attached to the frames it
451    /// receives (M976), the pull half of `meta_transform`'s push half. The
452    /// runner unions the declaration into the allocation cascade travelling
453    /// upstream, so a producer any number of hops away can ask
454    /// [`MetaRequests::wants`](crate::meta::MetaRequests::wants) in
455    /// [`configure_allocation`](Self::configure_allocation) and skip work nobody
456    /// downstream reads. Default: nothing requested, and a graph where every
457    /// element defaults cascades exactly as it did before the hook existed.
458    ///
459    /// Requesting a meta is a hint, never a guarantee: a consumer must still
460    /// handle a frame arriving without it (no producer upstream may be able to
461    /// attach one). Without the `metadata` feature
462    /// [`MetaRequests`](crate::meta::MetaRequests) is a zero-sized empty set, so
463    /// overriding this can only return the default.
464    fn meta_requests(&self) -> crate::meta::MetaRequests {
465        crate::meta::MetaRequests::new()
466    }
467
468    /// M16 step 5b: declare this element's negotiation-time constraint
469    /// when used as the **sink** of a chain. The default returns the
470    /// legacy bridge (`LegacySink` wrapping today's `intercept_caps`).
471    /// Migrated sinks override with `Accepts(CapsSet)` (or a more
472    /// elaborate native variant) to participate in arc consistency
473    /// and skip the dynamic intercept callback.
474    fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
475        legacy_sink_constraint(self)
476    }
477
478    /// M16 step 5b: same as `caps_constraint_as_sink` but for the
479    /// **transform** role. Default returns `LegacyTransform` wrapping
480    /// today's `intercept_caps` + `propose_output_caps`. Migrated
481    /// transforms override with `Identity` / `Mapping` /
482    /// `DerivedOutput`.
483    fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
484        legacy_transform_constraint(self)
485    }
486
487    /// What this element is willing to pay for each alternative of the set its
488    /// `caps_constraint_as_*` advertises. Default `None`: the alternatives are
489    /// already in preference order and cost their index. An element overrides
490    /// this to declare *equal* cost between alternatives it does not care
491    /// about (so a neighbour's preference decides) or a gap wide enough that a
492    /// neighbour's preference cannot pull the chain onto its fallback.
493    fn caps_preferences(&self) -> Option<CapsPreferences> {
494        None
495    }
496
497    /// The runtime properties this element type exposes (M104), the GObject
498    /// property-spec analog. Default: none. An element overrides this (and
499    /// [`set_property`](Self::set_property) / [`get_property`](Self::get_property))
500    /// to be settable by name from a `gst-launch` pipeline or inspectable by a
501    /// `gst-inspect` dump. The `with_*` builders remain the zero-cost
502    /// construction path; this is the string-keyed runtime face.
503    fn properties(&self) -> &'static [PropertySpec] {
504        &[]
505    }
506
507    /// Static introspection metadata for this element type (M178): the
508    /// `gst-inspect` "Factory Details" (long-name / classification / description
509    /// / author). Default: empty, like [`properties`](Self::properties). An
510    /// element overrides it with a `const ElementMetadata` to document itself.
511    fn metadata(&self) -> ElementMetadata {
512        ElementMetadata::default()
513    }
514
515    /// Receive this instance's log name (M179), assigned by the runner as
516    /// `<category>N`. Default: ignore. An element that logs about itself stores
517    /// it and returns it from its [`LogSource`](crate::log::LogSource) so its log
518    /// lines carry the instance name.
519    fn set_instance_name(&mut self, _name: alloc::string::String) {}
520
521    /// Override this instance's log category (M845), which is otherwise the
522    /// element type name. Default: ignore. An element that logs about itself
523    /// stores it (in a [`LogName`](crate::log::LogName)) and returns it from
524    /// `LogSource::log_category_override`, so `G2G_DEBUG` filtering keys off the
525    /// override for this instance while its siblings keep the type category.
526    fn set_log_category(&mut self, _category: alloc::string::String) {}
527
528    /// Set a property by name (M104). Default: every name is
529    /// [`PropError::Unknown`] (no properties). An overriding element validates
530    /// the value kind against its [`properties`](Self::properties) spec and
531    /// applies it.
532    fn set_property(&mut self, _name: &str, _value: PropValue) -> Result<(), PropError> {
533        Err(PropError::Unknown)
534    }
535
536    /// Read a property back by name (M104). Default: `None`. Overriding elements
537    /// return the current value for a known property.
538    fn get_property(&self, _name: &str) -> Option<PropValue> {
539        None
540    }
541
542    /// The log category for this element (M179): its short type name by
543    /// default, the `G2G_DEBUG` filtering key. A wrapper that erases another
544    /// element forwards the inner one's category instead.
545    fn log_category(&self) -> &'static str {
546        crate::log::short_type_name::<Self>()
547    }
548}
549
550/// Dyn-safe variant of [`AsyncElement`] for plugin registries on `std` targets.
551/// `no_std` graphs use the monomorphised `AsyncElement` directly.
552#[cfg(feature = "std")]
553pub trait DynAsyncElement: ElementBound {
554    fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError>;
555
556    fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError>;
557
558    /// Dyn-safe mirror of [`AsyncElement::configure_output`] (M185). Defaults to
559    /// no-op so unaffected erased elements need not implement it.
560    fn configure_output(&mut self, _output_caps: &Caps) -> Result<(), G2gError> {
561        Ok(())
562    }
563
564    fn process<'a>(
565        &'a mut self,
566        packet: PipelinePacket,
567        out: &'a mut dyn OutputSink,
568    ) -> core::pin::Pin<alloc::boxed::Box<dyn Future<Output = Result<(), G2gError>> + 'a>>;
569
570    /// Dyn-safe mirror of [`AsyncElement::caps_constraint_as_sink`], so a
571    /// `Box`-erased branch sink (fan-out Phase C FO-2) can be re-solved
572    /// against its declared constraint on a mid-stream `CapsChanged`.
573    fn caps_constraint_as_sink(&self) -> CapsConstraint<'_>;
574
575    /// Dyn-safe mirror of [`AsyncElement::caps_constraint_as_transform`], so
576    /// an interior element of an N-element linear chain (`run_linear_chain`)
577    /// declares its transform constraint to the solver while erased.
578    fn caps_constraint_as_transform(&self) -> CapsConstraint<'_>;
579
580    /// Dyn-safe mirror of [`AsyncElement::caps_preferences`], so an erased
581    /// element's declared per-alternative costs reach the solver. Defaults to
582    /// `None` (cost = alternative index), matching `AsyncElement`.
583    fn caps_preferences(&self) -> Option<CapsPreferences> {
584        None
585    }
586
587    /// Dyn-safe mirror of [`AsyncElement::propose_allocation`], so a
588    /// `Box`-erased branch sink can re-derive its own pool on a mid-stream
589    /// caps change (fan-out element-local ฮฑ).
590    fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams>;
591
592    /// Dyn-safe mirror of [`AsyncElement::configure_allocation`].
593    fn configure_allocation(&mut self, params: &AllocationParams);
594
595    /// Dyn-safe mirror of [`AsyncElement::latency`], so a buffering interior
596    /// element of an N-element chain (`run_linear_chain`) contributes to the
597    /// runner's latency fold. Defaults to zero, matching `AsyncElement`.
598    fn latency(&self) -> LatencyReport {
599        LatencyReport::ZERO
600    }
601
602    /// Dyn-safe mirror of [`AsyncElement::output_memory`]. Default
603    /// [`System`](MemoryDomainKind::System).
604    fn output_memory(&self) -> MemoryDomainKind {
605        MemoryDomainKind::System
606    }
607
608    /// Dyn-safe mirror of [`AsyncElement::output_domains`]. Default
609    /// `only(output_memory())`.
610    fn output_domains(&self) -> DomainSet {
611        DomainSet::only(self.output_memory())
612    }
613
614    /// Dyn-safe mirror of [`AsyncElement::input_domains`]. Default
615    /// [`DomainSet::ALL`].
616    fn input_domains(&self) -> DomainSet {
617        DomainSet::ALL
618    }
619
620    /// Dyn-safe mirror of [`AsyncElement::meta_transform`]. Default `None`.
621    #[cfg(feature = "metadata")]
622    fn meta_transform(&self) -> Option<crate::meta::Transform> {
623        None
624    }
625
626    /// Dyn-safe mirror of [`AsyncElement::meta_requests`]. Default: nothing
627    /// requested.
628    fn meta_requests(&self) -> crate::meta::MetaRequests {
629        crate::meta::MetaRequests::new()
630    }
631
632    /// Dyn-safe mirror of [`AsyncElement::provide_clock`], so an interior
633    /// element that paces to hardware joins the runner's clock election.
634    /// Defaults to none.
635    fn provide_clock(&self) -> Option<ClockCandidate> {
636        None
637    }
638
639    /// Dyn-safe mirror of [`AsyncElement::set_clock_sync`], so an erased sink
640    /// receives the elected clock + base time. Defaults to ignore.
641    fn set_clock_sync(&mut self, _sync: ClockSync) {}
642
643    /// Dyn-safe mirror of [`AsyncElement::take_qos`], so an erased sink can send
644    /// a QoS signal upstream. Defaults to nothing.
645    fn take_qos(&mut self) -> Option<QosMessage> {
646        None
647    }
648
649    /// Dyn-safe mirror of [`AsyncElement::presentation_stats`], so the runner
650    /// can read an erased sink's presentation counters at end of run.
651    fn presentation_stats(&self) -> Option<PresentationStats> {
652        None
653    }
654
655    /// Dyn-safe mirror of [`AsyncElement::take_reconfigure`], so an erased sink
656    /// can request a keyframe / renegotiation upstream. Defaults to nothing.
657    fn take_reconfigure(&mut self) -> Option<Reconfigure> {
658        None
659    }
660
661    /// Dyn-safe mirror of [`AsyncElement::take_bitrate`], so an erased sink can
662    /// push a target bitrate upstream. Defaults to nothing.
663    fn take_bitrate(&mut self) -> Option<u32> {
664        None
665    }
666
667    /// Dyn-safe mirror of [`AsyncElement::handles_keyframe_requests`] (M720).
668    fn handles_keyframe_requests(&self) -> bool {
669        false
670    }
671
672    /// Dyn-safe mirror of [`AsyncElement::handles_bitrate_requests`] (M720).
673    fn handles_bitrate_requests(&self) -> bool {
674        false
675    }
676
677    /// Dyn-safe mirror of [`AsyncElement::absorbs_orientation`] (M1058).
678    fn absorbs_orientation(&self) -> bool {
679        false
680    }
681
682    /// Dyn-safe mirror of [`AsyncElement::handles_orientation`] (M1058).
683    fn handles_orientation(&self) -> bool {
684        false
685    }
686
687    /// Dyn-safe mirror of [`AsyncElement::handles_qos`] (M997).
688    fn handles_qos(&self) -> bool {
689        false
690    }
691
692    /// Dyn-safe mirror of [`AsyncElement::properties`], so a `gst-inspect` dump
693    /// and the `gst-launch` parser can introspect / set an erased element.
694    fn properties(&self) -> &'static [PropertySpec] {
695        &[]
696    }
697
698    /// Dyn-safe mirror of [`AsyncElement::metadata`], so a `gst-inspect` dump can
699    /// read an erased element's "Factory Details". Defaults to empty.
700    fn metadata(&self) -> ElementMetadata {
701        ElementMetadata::default()
702    }
703
704    /// The log category for this erased element (M179): its short type name by
705    /// default (the blanket impl fills it from `core::any::type_name`), so the
706    /// runner can name (`<category>N`) and log about any element. Filtering key.
707    fn log_category(&self) -> &'static str {
708        "element"
709    }
710
711    /// Dyn-safe mirror of [`AsyncElement::set_instance_name`], so the runner can
712    /// name an erased element instance for logging.
713    fn set_instance_name(&mut self, _name: alloc::string::String) {}
714
715    /// Dyn-safe mirror of [`AsyncElement::set_log_category`].
716    fn set_log_category(&mut self, _category: alloc::string::String) {}
717
718    /// Dyn-safe mirror of [`AsyncElement::set_property`]. Defaults to "no
719    /// properties" so a hand-written `DynAsyncElement` need not implement it; the
720    /// blanket `impl<T: AsyncElement>` overrides it to forward to the element.
721    fn set_property(&mut self, _name: &str, _value: PropValue) -> Result<(), PropError> {
722        Err(PropError::Unknown)
723    }
724
725    /// Dyn-safe mirror of [`AsyncElement::get_property`]. Defaults to `None`; the
726    /// blanket impl forwards to the element.
727    fn get_property(&self, _name: &str) -> Option<PropValue> {
728        None
729    }
730
731    /// Consume this element into its graph-runner transform arm (M1000). The
732    /// blanket impl monomorphizes the arm loop over the concrete element type,
733    /// so the per-frame `process` future is unboxed: the one box is this
734    /// method's returned arm future, once per run. Implementations outside the
735    /// blanket cannot build the runner's `TransformArmIo`; implement
736    /// [`AsyncElement`] instead.
737    #[cfg(feature = "runtime")]
738    #[doc(hidden)]
739    fn drive_transform_arm<'s>(
740        self: alloc::boxed::Box<Self>,
741        io: crate::runtime::TransformArmIo,
742    ) -> BoxFuture<'s, Result<u64, G2gError>>
743    where
744        Self: 's;
745
746    /// As [`Self::drive_transform_arm`], for the sink arm.
747    #[cfg(feature = "runtime")]
748    #[doc(hidden)]
749    fn drive_sink_arm<'s>(
750        self: alloc::boxed::Box<Self>,
751        io: crate::runtime::SinkArmIo,
752    ) -> BoxFuture<'s, Result<u64, G2gError>>
753    where
754        Self: 's;
755}
756
757/// Blanket adapter: every [`AsyncElement`] is usable as a
758/// [`DynAsyncElement`] by boxing its `process` future (DESIGN.md ยง4.3).
759/// This is what lets real plugin elements drop into a `Box<dyn
760/// DynAsyncElement>` slot without a hand-written impl. Method calls are
761/// disambiguated to `AsyncElement::` because the two traits share names.
762#[cfg(feature = "std")]
763impl<T: AsyncElement> DynAsyncElement for T {
764    fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError> {
765        AsyncElement::intercept_caps(self, upstream_caps)
766    }
767
768    fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError> {
769        AsyncElement::configure_pipeline(self, absolute_caps)
770    }
771
772    fn configure_output(&mut self, output_caps: &Caps) -> Result<(), G2gError> {
773        AsyncElement::configure_output(self, output_caps)
774    }
775
776    fn process<'a>(
777        &'a mut self,
778        packet: PipelinePacket,
779        out: &'a mut dyn OutputSink,
780    ) -> BoxFuture<'a, Result<(), G2gError>> {
781        Box::pin(AsyncElement::process(self, packet, out))
782    }
783
784    fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
785        AsyncElement::caps_constraint_as_sink(self)
786    }
787
788    fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
789        AsyncElement::caps_constraint_as_transform(self)
790    }
791
792    fn caps_preferences(&self) -> Option<CapsPreferences> {
793        AsyncElement::caps_preferences(self)
794    }
795
796    fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams> {
797        AsyncElement::propose_allocation(self, caps)
798    }
799
800    fn configure_allocation(&mut self, params: &AllocationParams) {
801        AsyncElement::configure_allocation(self, params)
802    }
803
804    fn latency(&self) -> LatencyReport {
805        AsyncElement::latency(self)
806    }
807
808    fn output_memory(&self) -> MemoryDomainKind {
809        AsyncElement::output_memory(self)
810    }
811
812    fn output_domains(&self) -> DomainSet {
813        AsyncElement::output_domains(self)
814    }
815
816    fn input_domains(&self) -> DomainSet {
817        AsyncElement::input_domains(self)
818    }
819
820    #[cfg(feature = "metadata")]
821    fn meta_transform(&self) -> Option<crate::meta::Transform> {
822        AsyncElement::meta_transform(self)
823    }
824
825    fn meta_requests(&self) -> crate::meta::MetaRequests {
826        AsyncElement::meta_requests(self)
827    }
828
829    fn provide_clock(&self) -> Option<ClockCandidate> {
830        AsyncElement::provide_clock(self)
831    }
832
833    fn set_clock_sync(&mut self, sync: ClockSync) {
834        AsyncElement::set_clock_sync(self, sync)
835    }
836
837    fn take_qos(&mut self) -> Option<QosMessage> {
838        AsyncElement::take_qos(self)
839    }
840
841    fn presentation_stats(&self) -> Option<PresentationStats> {
842        AsyncElement::presentation_stats(self)
843    }
844
845    fn take_reconfigure(&mut self) -> Option<Reconfigure> {
846        AsyncElement::take_reconfigure(self)
847    }
848
849    fn take_bitrate(&mut self) -> Option<u32> {
850        AsyncElement::take_bitrate(self)
851    }
852
853    fn handles_keyframe_requests(&self) -> bool {
854        AsyncElement::handles_keyframe_requests(self)
855    }
856
857    fn handles_bitrate_requests(&self) -> bool {
858        AsyncElement::handles_bitrate_requests(self)
859    }
860
861    fn absorbs_orientation(&self) -> bool {
862        AsyncElement::absorbs_orientation(self)
863    }
864
865    fn handles_orientation(&self) -> bool {
866        AsyncElement::handles_orientation(self)
867    }
868
869    fn handles_qos(&self) -> bool {
870        AsyncElement::handles_qos(self)
871    }
872
873    fn properties(&self) -> &'static [PropertySpec] {
874        AsyncElement::properties(self)
875    }
876
877    fn metadata(&self) -> ElementMetadata {
878        AsyncElement::metadata(self)
879    }
880
881    fn log_category(&self) -> &'static str {
882        AsyncElement::log_category(self)
883    }
884
885    fn set_instance_name(&mut self, name: alloc::string::String) {
886        AsyncElement::set_instance_name(self, name)
887    }
888
889    fn set_log_category(&mut self, category: alloc::string::String) {
890        AsyncElement::set_log_category(self, category)
891    }
892
893    fn set_property(&mut self, name: &str, value: PropValue) -> Result<(), PropError> {
894        AsyncElement::set_property(self, name, value)
895    }
896
897    fn get_property(&self, name: &str) -> Option<PropValue> {
898        AsyncElement::get_property(self, name)
899    }
900
901    #[cfg(feature = "runtime")]
902    fn drive_transform_arm<'s>(
903        self: Box<Self>,
904        io: crate::runtime::TransformArmIo,
905    ) -> BoxFuture<'s, Result<u64, G2gError>>
906    where
907        Self: 's,
908    {
909        Box::pin(crate::runtime::transform_arm(*self, io))
910    }
911
912    #[cfg(feature = "runtime")]
913    fn drive_sink_arm<'s>(
914        self: Box<Self>,
915        io: crate::runtime::SinkArmIo,
916    ) -> BoxFuture<'s, Result<u64, G2gError>>
917    where
918        Self: 's,
919    {
920        Box::pin(crate::runtime::sink_arm(*self, io))
921    }
922}
923
924/// Private [`AsyncElement`] face over an erased element, so the generic
925/// (monomorphized) arms can drive a `&mut dyn DynAsyncElement` graph node too.
926/// Its per-frame process future stays boxed (the element underneath is
927/// erased); a newtype rather than an impl on `&mut dyn` itself, which would
928/// make method calls ambiguous wherever both traits are imported.
929#[cfg(all(feature = "std", feature = "runtime"))]
930struct DynRef<'b>(&'b mut (dyn DynAsyncElement + 'b));
931
932#[cfg(all(feature = "std", feature = "runtime"))]
933impl<'b> AsyncElement for DynRef<'b> {
934    type ProcessFuture<'a>
935        = BoxFuture<'a, Result<(), G2gError>>
936    where
937        Self: 'a;
938
939    fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError> {
940        self.0.intercept_caps(upstream_caps)
941    }
942
943    fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError> {
944        self.0.configure_pipeline(absolute_caps)
945    }
946
947    fn configure_output(&mut self, output_caps: &Caps) -> Result<(), G2gError> {
948        self.0.configure_output(output_caps)
949    }
950
951    fn process<'a>(
952        &'a mut self,
953        packet: PipelinePacket,
954        out: &'a mut dyn OutputSink,
955    ) -> Self::ProcessFuture<'a> {
956        self.0.process(packet, out)
957    }
958
959    fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
960        self.0.caps_constraint_as_sink()
961    }
962
963    fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
964        self.0.caps_constraint_as_transform()
965    }
966
967    fn caps_preferences(&self) -> Option<CapsPreferences> {
968        self.0.caps_preferences()
969    }
970
971    fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams> {
972        self.0.propose_allocation(caps)
973    }
974
975    fn configure_allocation(&mut self, params: &AllocationParams) {
976        self.0.configure_allocation(params)
977    }
978
979    fn latency(&self) -> LatencyReport {
980        self.0.latency()
981    }
982
983    fn output_memory(&self) -> MemoryDomainKind {
984        self.0.output_memory()
985    }
986
987    fn output_domains(&self) -> DomainSet {
988        self.0.output_domains()
989    }
990
991    fn input_domains(&self) -> DomainSet {
992        self.0.input_domains()
993    }
994
995    #[cfg(feature = "metadata")]
996    fn meta_transform(&self) -> Option<crate::meta::Transform> {
997        self.0.meta_transform()
998    }
999
1000    fn meta_requests(&self) -> crate::meta::MetaRequests {
1001        self.0.meta_requests()
1002    }
1003
1004    fn provide_clock(&self) -> Option<ClockCandidate> {
1005        self.0.provide_clock()
1006    }
1007
1008    fn set_clock_sync(&mut self, sync: ClockSync) {
1009        self.0.set_clock_sync(sync)
1010    }
1011
1012    fn take_qos(&mut self) -> Option<QosMessage> {
1013        self.0.take_qos()
1014    }
1015
1016    fn presentation_stats(&self) -> Option<PresentationStats> {
1017        self.0.presentation_stats()
1018    }
1019
1020    fn take_reconfigure(&mut self) -> Option<Reconfigure> {
1021        self.0.take_reconfigure()
1022    }
1023
1024    fn take_bitrate(&mut self) -> Option<u32> {
1025        self.0.take_bitrate()
1026    }
1027
1028    fn handles_keyframe_requests(&self) -> bool {
1029        self.0.handles_keyframe_requests()
1030    }
1031
1032    fn handles_bitrate_requests(&self) -> bool {
1033        self.0.handles_bitrate_requests()
1034    }
1035
1036    fn absorbs_orientation(&self) -> bool {
1037        self.0.absorbs_orientation()
1038    }
1039
1040    fn handles_orientation(&self) -> bool {
1041        self.0.handles_orientation()
1042    }
1043
1044    fn handles_qos(&self) -> bool {
1045        self.0.handles_qos()
1046    }
1047
1048    fn properties(&self) -> &'static [PropertySpec] {
1049        self.0.properties()
1050    }
1051
1052    fn metadata(&self) -> ElementMetadata {
1053        self.0.metadata()
1054    }
1055
1056    fn log_category(&self) -> &'static str {
1057        self.0.log_category()
1058    }
1059
1060    fn set_instance_name(&mut self, name: alloc::string::String) {
1061        self.0.set_instance_name(name)
1062    }
1063
1064    fn set_log_category(&mut self, category: alloc::string::String) {
1065        self.0.set_log_category(category)
1066    }
1067
1068    fn set_property(&mut self, name: &str, value: PropValue) -> Result<(), PropError> {
1069        self.0.set_property(name, value)
1070    }
1071
1072    fn get_property(&self, name: &str) -> Option<PropValue> {
1073        self.0.get_property(name)
1074    }
1075}
1076
1077/// Forwarding impl so a borrowed `&mut dyn DynAsyncElement` can be boxed into a
1078/// `Box<dyn DynAsyncElement + 'a>` graph node (the convenience wrappers build a
1079/// borrowing `Graph` over their `&mut` element references). Disjoint from the
1080/// `AsyncElement` blanket above: a `&mut dyn DynAsyncElement` does not implement
1081/// `AsyncElement`.
1082#[cfg(feature = "std")]
1083impl<'b> DynAsyncElement for &'b mut (dyn DynAsyncElement + 'b) {
1084    fn intercept_caps(&self, upstream_caps: &Caps) -> Result<Caps, G2gError> {
1085        (**self).intercept_caps(upstream_caps)
1086    }
1087
1088    fn configure_pipeline(&mut self, absolute_caps: &Caps) -> Result<ConfigureOutcome, G2gError> {
1089        (**self).configure_pipeline(absolute_caps)
1090    }
1091
1092    fn configure_output(&mut self, output_caps: &Caps) -> Result<(), G2gError> {
1093        (**self).configure_output(output_caps)
1094    }
1095
1096    fn process<'a>(
1097        &'a mut self,
1098        packet: PipelinePacket,
1099        out: &'a mut dyn OutputSink,
1100    ) -> BoxFuture<'a, Result<(), G2gError>> {
1101        (**self).process(packet, out)
1102    }
1103
1104    fn caps_constraint_as_sink(&self) -> CapsConstraint<'_> {
1105        (**self).caps_constraint_as_sink()
1106    }
1107
1108    fn caps_constraint_as_transform(&self) -> CapsConstraint<'_> {
1109        (**self).caps_constraint_as_transform()
1110    }
1111
1112    fn caps_preferences(&self) -> Option<CapsPreferences> {
1113        (**self).caps_preferences()
1114    }
1115
1116    fn propose_allocation(&self, caps: &Caps) -> Option<AllocationParams> {
1117        (**self).propose_allocation(caps)
1118    }
1119
1120    fn configure_allocation(&mut self, params: &AllocationParams) {
1121        (**self).configure_allocation(params)
1122    }
1123
1124    fn latency(&self) -> LatencyReport {
1125        (**self).latency()
1126    }
1127
1128    fn output_memory(&self) -> MemoryDomainKind {
1129        (**self).output_memory()
1130    }
1131
1132    fn output_domains(&self) -> DomainSet {
1133        (**self).output_domains()
1134    }
1135
1136    fn input_domains(&self) -> DomainSet {
1137        (**self).input_domains()
1138    }
1139
1140    #[cfg(feature = "metadata")]
1141    fn meta_transform(&self) -> Option<crate::meta::Transform> {
1142        (**self).meta_transform()
1143    }
1144
1145    fn meta_requests(&self) -> crate::meta::MetaRequests {
1146        (**self).meta_requests()
1147    }
1148
1149    fn provide_clock(&self) -> Option<ClockCandidate> {
1150        (**self).provide_clock()
1151    }
1152
1153    fn set_clock_sync(&mut self, sync: ClockSync) {
1154        (**self).set_clock_sync(sync)
1155    }
1156
1157    fn take_qos(&mut self) -> Option<QosMessage> {
1158        (**self).take_qos()
1159    }
1160
1161    fn presentation_stats(&self) -> Option<PresentationStats> {
1162        (**self).presentation_stats()
1163    }
1164
1165    fn take_reconfigure(&mut self) -> Option<Reconfigure> {
1166        (**self).take_reconfigure()
1167    }
1168
1169    fn take_bitrate(&mut self) -> Option<u32> {
1170        (**self).take_bitrate()
1171    }
1172
1173    fn handles_keyframe_requests(&self) -> bool {
1174        (**self).handles_keyframe_requests()
1175    }
1176
1177    fn handles_bitrate_requests(&self) -> bool {
1178        (**self).handles_bitrate_requests()
1179    }
1180
1181    fn absorbs_orientation(&self) -> bool {
1182        (**self).absorbs_orientation()
1183    }
1184
1185    fn handles_orientation(&self) -> bool {
1186        (**self).handles_orientation()
1187    }
1188
1189    fn handles_qos(&self) -> bool {
1190        (**self).handles_qos()
1191    }
1192
1193    fn properties(&self) -> &'static [PropertySpec] {
1194        (**self).properties()
1195    }
1196
1197    fn metadata(&self) -> ElementMetadata {
1198        (**self).metadata()
1199    }
1200
1201    fn log_category(&self) -> &'static str {
1202        (**self).log_category()
1203    }
1204
1205    fn set_instance_name(&mut self, name: alloc::string::String) {
1206        (**self).set_instance_name(name)
1207    }
1208
1209    fn set_log_category(&mut self, category: alloc::string::String) {
1210        (**self).set_log_category(category)
1211    }
1212
1213    fn set_property(&mut self, name: &str, value: PropValue) -> Result<(), PropError> {
1214        (**self).set_property(name, value)
1215    }
1216
1217    fn get_property(&self, name: &str) -> Option<PropValue> {
1218        (**self).get_property(name)
1219    }
1220
1221    #[cfg(feature = "runtime")]
1222    fn drive_transform_arm<'s>(
1223        self: Box<Self>,
1224        io: crate::runtime::TransformArmIo,
1225    ) -> BoxFuture<'s, Result<u64, G2gError>>
1226    where
1227        Self: 's,
1228    {
1229        Box::pin(crate::runtime::transform_arm(DynRef(*self), io))
1230    }
1231
1232    #[cfg(feature = "runtime")]
1233    fn drive_sink_arm<'s>(
1234        self: Box<Self>,
1235        io: crate::runtime::SinkArmIo,
1236    ) -> BoxFuture<'s, Result<u64, G2gError>>
1237    where
1238        Self: 's,
1239    {
1240        Box::pin(crate::runtime::sink_arm(DynRef(*self), io))
1241    }
1242}