Skip to main content

UnionLabelMatch

Enum UnionLabelMatch 

Source
pub enum UnionLabelMatch {
    SignExtended,
    NegativeLabelUnmatchedBelow32,
}
Expand description

Whether a case label of a narrow signed discriminator can be negative.

IDL 4.2 §7.4.1.4.4.2.4 makes a case label a value of the discriminator’s type, and XTypes 1.3 §7.4.3.5.3 rule (26) writes the discriminator and then the member the labels select. Nothing in either clause is width-dependent: case -13: on an int8 selects its branch for _d = -13 exactly as case -1234567: on a long does.

§What one implementation does instead

Cyclone DDS 11.0.1 compares the label against the discriminator’s octets read unsigned, so f3 is 243 and not -13, and cfc7 is 53191 and not -12345. No label matches, and what happens next is whether the union declared a default::

the unionwhat Cyclone writesmeasured on
no default:the discriminator and no branch at allunion-discriminator-{int8,short}, four octets shorter
a default:the discriminator and the union’s storage read through the default branchcombined-everything, four and eight octets longer

It is the label’s width and its sign together. union-discriminator-long carries case -1234567: and agrees byte for byte; union-discriminator-{octet,uint8,ushort} carry unsigned narrow labels and agree byte for byte. Only the pair diverges.

§The storage, and why it is not the member zero-padded

combined-everything-unannotated, case -1: long whole; default: double fraction;, whole = 0x7fffffff, XCDR1:

le  cyclone   ffff 0000 00000000   ffffff7f 00000000
be  cyclone   ffff 0000 00000000   00000000 7fffffff

The discriminator, padding to the double’s eight-alignment, and then eight octets. The big-endian row is the same eight octets reversed whole: a member zero-padded to the branch’s width would give 7fffffff 00000000 there. So what is written is the union’s storage — the selected member’s octets in the host’s order at offset zero, zeros above them — emitted as one value of the default branch’s width in the stream’s byte order.

The zero octets are guaranteed rather than lucky: wireprobe-zerodds-c-gen declares the sample as static {root_type} zd_sample;, and §6.7.9 of the C standard zero-initialises a static object.

This is a host-storage dependence, the same class as WstringUnitOrder::HostUnswapped, and it is recorded here for the same reason: the corpus was measured on x86-64 and “little-endian” is what was measured, not “the host’s order”. The C column reaches it through a real C union and would follow a big-endian host; the Rust and Python columns synthesise the little-endian octets. The two coincide on every host this project measures on and would part on a big-endian one — unmeasured, and stated rather than left to be discovered.

§No dialect selects the second value

Not even Dialect::Cyclone, which is this project’s default. A default has to be the form a conforming reader gets right, and this one drops the selected branch off the wire: a peer reading union-discriminator-short takes the member after the union for the branch. That is a silent wrong value, and shipping it to every caller who wrote --dialect cyclone would be shipping the defect. --union-labels negative-unmatched-below-32 reaches it, and so does the configuration of that name — the same construction EnumHolderWidth::BitBoundDroppedByFrontEnd and PidFlagPolicy::ImplExtensionOnMembers are reached by.

§What it reaches, and what it does not

crate::union_negative_matches_nothing is the one crossing, and it answers two questions.

The discriminator has to be a signed integer primitive narrower than 32 bits — int8 and short. Not octet, char or boolean, none of which can carry a negative label; not long or long long, which were measured to agree; and not an enumeration discriminator: union-discriminator-enum declares no negative @value, so nothing measured says what Cyclone does with one and answering would be a claim about octets nobody has.

Every branch has to be a primitive of one, two, four or eight octets, because the storage above is what a default: branch is read through and a string or sequence branch is read as a pointer. union-member-sequence is switch (short) { case -1: sequence<long> ids; default: string text; }, its -1 is the union’s only label, and tests/interop-results/sources/vendor-corpus.tsv records Cyclone on it and on its twin — both encoding versions, both byte orders — as refused — the probe was killed: Segmentation fault. There are no octets to reproduce, so the setting does not reach the shape and this project writes the clause’s frame there: a complete frame a conforming reader can use.

It is not a planner setting. A union’s extent is the discriminator plus the widest branch under both values — with a default: Cyclone writes the widest branch’s storage, and without one the extent still bounds what any value of the discriminator could produce. Nothing here reaches an offset, so it stays out of LayoutKey::offset_key, and that is a claim rather than an omission.

Variants§

§

SignExtended

A case label is compared against the discriminator’s own signed value.

The clause, and what RTI, Fast DDS and this project write.

§

NegativeLabelUnmatchedBelow32

A negative label on a signed discriminator narrower than 32 bits matches nothing.

What Cyclone DDS writes. Named for the behaviour and not for the vendor, so that a reader does not take it for a reading of §7.4.1.4.4.2.4.

Implementations§

Source§

impl UnionLabelMatch

Source

pub const ALL: [Self; 2]

Both.

Source

pub const MATCHING_WIDTH: u16 = 32

The width at or above which a signed label still matches.

Thirty-two: union-discriminator-long’s case -1234567: was measured to match and union-discriminator-short’s case -12345: was measured not to.

Source

pub const fn is_default(self) -> bool

Whether this is the default.

Source

pub const fn as_str(self) -> &'static str

Short name, for configuration and diagnostics.

Source

pub const fn label_matches(self, label: i128, signed: bool, bits: u16) -> bool

Whether a label of the given value, on a discriminator of the given signedness and width, selects its branch.

The arithmetic behind crate::union_negative_matches_nothing, separated so that the crossing can be tested without an Ast.

Source

pub fn parse(value: &str) -> Option<Self>

Parse a configuration value.

An unknown value returns None rather than falling back to the default: a typo in a wire-affecting setting must be loud.

Trait Implementations§

Source§

impl Clone for UnionLabelMatch

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for UnionLabelMatch

Source§

impl Debug for UnionLabelMatch

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for UnionLabelMatch

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Eq for UnionLabelMatch

Source§

impl Hash for UnionLabelMatch

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Ord for UnionLabelMatch

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 (const: unstable) · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 (const: unstable) · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 (const: unstable) · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

fn clamp_to<R>(self, range: R) -> Self
where Self: Sized, R: ClampBounds<Self>,

🔬This is a nightly-only experimental API. (clamp_to)
Restrict a value to a certain range. Read more
Source§

impl PartialEq for UnionLabelMatch

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl PartialOrd for UnionLabelMatch

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 (const: unstable) · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 (const: unstable) · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 (const: unstable) · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 (const: unstable) · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl StructuralPartialEq for UnionLabelMatch

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.