gst: decouple GenericFormattedValue type bounds
FormattedValue
s
APIs with multiple Function Element::seek
takes 2 FormattedValues: one for start
and one for stop
. Currently, theses args are defined as being
of the same type using a single bind clause:
fn seek<V: Into<GenericFormattedValue>>(
...
start: V,
...
stop: V,
) -> ...
When called with a SpecificFormattedValue
such ClockTime
,
this signature ensures at compilation time that start
and stop
use the same format. However, this prevents the user from calling
seek
with e.g. an intrinsic value for start
and an Option
for stop
. E.g.:
element.seek(
...
gst::ClockTime::ZERO,
...
gst::ClockTime::NONE,
).unwrap();
Another example that would fail at compilation time would be
using a SpecificFormattedValue
for start
and a
GenericFormattedValue
for stop
.
Changes in this MR
This MR implements a solution to make the above APIs flexible
and safe to use. It strives to enforce type conformity at
compilation time when possible and fallbacks to runtime checks
in the case of GenericFormattedValues
.
Preparation
In order to ease the transition to a model which would implement
the above, a first pass on the format
module was performed.
The first commit implements the trait FormattedValue
for any
type that can be used as a FormattedValue
. Previously, only
types which were able to represent a "full range" FormattedValue
implemented the trait. E.g.: GenericFormattedValues
,
Option<ClockTime>
implemented it, but ClockTime
didn't.
APIs which would accept any formatted value used a bind clause
V: Into<GenericFormattedValue>
and the provided value was
forced into a GenericFormattedValue
in the function.
This change allows using a V: FormattedValue
bind instead.
In 95% of cases, this is all the function needs: no more
conversion to GenericFormattedValue
required.
When a function needs a "full range" formatted value instead,
we can use the new trait FormattedValueFullRange
. The trait
FormattedValue
uses an associated type FullRange
, in order
to refer to the full range type. This is needed when building
a FormattedValue
from a raw value.
Note: I'm not sure about the "full range" name here. This could also be "full scale", ...
Compatible Formatted Values
The second commit introduces the trait CompatibleFormattedValue
.
This trait uses a FormattedValue
type parameter against which
we want to check format compatibility for Self
. This trait is
implemented on compatible combinations only.
For SpecificFormattedValue
s, the implementation ensures type system
level checks.
For checks involving at least one GenericFormattedValue
, checks are
performed at runtime via the function try_into_checked
.
- Function
try_into_checked
should result to a no-op when the check can be performed at compilation. - User can't use the argument as a
FormattedValue
unlesstry_into_checked
was called.
In some cases (e.g. Segment<_>
), the format to check is not enforced
by another argument but by a field of Self
. For those cases, the
try_into_checked_explicit
performs the checks against an explicit
Format
with as low an overhead as possible.
Note: I'm not 100% sure about the CompatibleFormattedValue
and
try_into_checked*
names here. Alternatives could be:
-
CheckedFormattedValue
: shorter but I think we loose a bit of the semantic. -
Conforming...
: not sure if that would be more correct thatCompatible
.
Initial Proposal
The following § is the initial proposal. It is left here so as to understand the discussion in the first comment.
A workaround could be using different types for start
and stop
and binding them with the following clause:
where
Start: SpecificFormattedValue,
Stop: SpecificFormattedValue<FormattedValueType = <Start as SpecificFormattedValue>::FormattedValueType>
However, this would prevent the user from calling seek
with a
GenericFormattedValue
.
This commit decouples the types for functions with multiple formatted arguments. Format equivalence will no longer be enforced at compilation time, it will still be controlled at runtime thanks to the existing assertions.
The drawback is that we sometimes need to help the compiler with
type inference. See basic-tutorial-13.rs
as an example.
The commit also fixes message::StepDone
: the duration
argument
is said to be of Time
format in the documentation for
gst_message_new_step_done
while it was bound to the format of
the amount
argument.
See also: gst-plugins-rs!797 (merged)