pub enum FixedDigitCount {
Declared,
ValuePrecision,
ValueStringDigits,
}Expand description
Whether a fixed<P,S>’s digit count comes from the declaration or
from the value.
CORBA 3.3 part 2 §9.3.2.8 defines the wire form and nothing else:
packed binary-coded decimal, two digits to the octet, most
significant first, the low nibble of the last octet the sign — 0xC
for positive or zero and 0xD for negative — with a leading zero
nibble prepended when the nibble count is odd. IDL 4.2
§7.4.1.4.4.3.4 rule (42) gives the syntax and caps P at 31. XTypes
1.3 has no fixed-point type at all, which is why the rule is borrowed
by name. What neither clause says is how many digits go on the
wire, and the four implementations that write one split two and
two.
§Two on each side, which is what makes it an axis
| the digit count | measured on | |
|---|---|---|
| omniORB 4.3.3 | the declared P | fixed-basic, fixed-scales, fixed-scale-equals-digits, array-1d-fixed, sequence-fixed, both orders |
| this project | the declared P | the same rows, byte for byte with omniORB |
| JacORB | the value’s precision | the same rows; docs/corba-column.md §3 traced it to BigDecimal.precision() |
| ACE/TAO 2.5.24 | the digits of the string the value was parsed from | ACE_CDR::Fixed’s own CDR operator; tao_idl refuses the corpus’s fixed IDL so TAO has no recorded row, and its runtime was measured directly in unspecified_constructs.md §3 |
| OpenDDS 3.34 | the declared P | its serializer writes OpenDDS::FaceTypes::Fixed_T<P,S>, (P + 2) / 2 octets, not through ACE_CDR::Fixed’s operator: 0.00 under fixed<5,2> is 00000c, 7 is 00700c (measured 2026-10-07 through the FACE mapping) |
Judgement 3’s threshold, met: two independent implementations on each
side, and both were in a position to answer differently — a front end
that carried fixed<9,3> as far as a serialiser and then wrote the
value’s digits chose to.
§The octets
fixed-basic, fixed<9,3>, amount = 123456.789 and
debt = -000000.001, plain-cdr1 big endian:
ours 123456789c 00000000 1d ab
theirs 123456789c 1d abOnly a value with leading zeros differs. fixed-scales and
fixed-scale-equals-digits are byte-identical across omniORB, JacORB
and this project, which is what makes the cause exact rather than
inferred: fixed<31,10> holding thirty significant digits pads to
sixteen octets under both readings, and fixed<4,4> holding four
pads to three under both.
§The value’s precision is BigDecimal.precision()
The digit string with its leading zeros removed, and at least one
digit: new BigDecimal("0.00").precision() is 1 in Java, so a zero
goes out as the single nibble 0 and the sign, one octet 0c. That
is the same “at least one” the C++ and Rust sides need, and it is why
the rule is stated as max(significant, 1) rather than as “strip the
leading zeros”.
§It is decodable, and the estimate said it was not
docs/open-rows-breakdown.md cause K states that “the declared count
is the only decodable half: a reader must know the octet count from
the type before it reads the value”. That is wrong, and the clause
says why: a digit nibble is 0 to 9 and a sign nibble is 0xA to
0xF, so the field ends at the first octet whose low nibble is at
least 0xA. The count of nibbles is even by construction, so the
sign is always a low nibble and never a high one. A reader of this
form scans; all three columns do, and
crates/wire-probe/tests/fixed_digit_count.rs::the_value_precision_form_reads_back
is that as a test over the recorded JacORB rows.
§It is a planner setting
Unlike MapEntryOrder and UnionLabelMatch. A fixed’s extent
is ceil((P + 1) / 2) octets under Self::Declared and depends on
the value under Self::ValuePrecision and Self::ValueStringDigits,
so the type stops being fixed-size and every member behind it moves.
It is in LayoutKey::offset_key for that reason, and
the_extent_is_unbounded_under_the_value is the claim as a test.
§Three readings exist
- Declared —
Pdigits, padded to even nibble count. What omniORB 4.3.3 and this project’s default write. - ValuePrecision — the value’s precision with leading and
trailing zeros removed, minimum one digit. What JacORB 3.9 writes
(
BigDecimal.precision()). - ValueStringDigits — the integer digits of the decimal as
written, leading zeros included, plus the
Sfraction digits of the declaration, padded to an odd digit count by adding one leading zero if even. What ACE/TAO 2.5.24’sACE_CDR::Fixedwrites for a decimal withSfraction digits — it counts the digits of the string it was parsed from — which is what OpenDDS’s generatedwrite_fixedcalls. The fraction is counted atSand not as written:"7"underfixed<5,2>is700c, and counting one digit would have kept only its last nibble,0c.
The three differ on values with fewer digits than the type declares:
| declared | value string | digit count | Declared | ValuePrecision | ValueStringDigits |
|---|---|---|---|---|---|
fixed<5,5> | "0.12345" | 6 (even) | 5 | 5 | 7 (0012345) |
fixed<5,2> | "0.00" | 3 (odd) | 5 | 1 | 3 (000) |
fixed<4,2> | "12.34" | 4 (even) | 4 | 4 | 5 (01234) |
fixed<5,2> | "123.45" | 5 (odd) | 5 | 5 | 5 (12345) |
fixed<1,0> | "7" | 1 (odd) | 1 | 1 | 1 (7) |
fixed<5,2> | "7" | 1 + 2 (odd) | 5 | 3 | 3 (700) |
The ValueStringDigits column is pinned by the recorded ACE values
in unspecified_constructs.md §3:
fixed<5,5>"0.12345"→0012345c(7 digits) pins the even→odd padding.fixed<5,2>"0.00"→000c(3 digits) pins the odd count without padding.fixed<4,2>"12.34"→01234c(5 digits) pins the even→odd padding.fixed<5,2>"123.45"→12345c(5 digits) pins the odd count without padding.fixed<1,0>"7"→7c(1 digit) pins the minimum one digit.- The
fixed<31,0>row (31 nines) agrees across all three and does not separate them.
Variants§
Declared
P digits, whatever the value is — the declaration decides.
The default, and what omniORB 4.3.3 writes.
ValuePrecision
As many digits as the value has, and never fewer than one.
What JacORB 3.9 writes. Named for the rule and not for a vendor, because two implementations reached it independently.
ValueStringDigits
The integer digits of the decimal as written, leading zeros
included, plus the S fraction digits, padded to an odd digit
count by adding one leading zero if the count is even.
What ACE/TAO 2.5.24’s ACE_CDR::Fixed writes for a decimal with
S fraction digits, through its own CDR operator. Measured in
unspecified_constructs.md §3. OpenDDS does not write it: its
serializer writes the declared count (see Dialect::fixed_digits).
Implementations§
Source§impl FixedDigitCount
impl FixedDigitCount
Sourcepub const FIRST_SIGN_NIBBLE: u8 = 0x0a
pub const FIRST_SIGN_NIBBLE: u8 = 0x0a
The lowest nibble value that is a sign and not a digit.
CORBA 3.3 part 2 §9.3.2.8: a digit is 0 to 9, and every
nibble at or above this is a sign. It is what makes the
value-precision form self-delimiting, and it is a constant here
so the three runtimes cannot each pick their own.
Sourcepub const fn is_default(self) -> bool
pub const fn is_default(self) -> bool
Whether this is the default.
Sourcepub const fn wire_digits(
self,
declared: u8,
significant: u8,
string_digits: u8,
) -> u8
pub const fn wire_digits( self, declared: u8, significant: u8, string_digits: u8, ) -> u8
How many digit nibbles a value goes out with.
declared is P; significant is the value’s digit count with
its leading zeros removed. The one place the two cross into a
wire width. crate::fixed_wire_digits is what call sites use;
this is the arithmetic behind it, separated so that the crossing
can be tested without a value.
Never zero under any value: a field of no digits could not carry the sign nibble’s pair.