ZeroDds.Wire 1.0.0-rc.7

This is a prerelease version of ZeroDds.Wire.
dotnet add package ZeroDds.Wire --version 1.0.0-rc.7
                    
NuGet\Install-Package ZeroDds.Wire -Version 1.0.0-rc.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ZeroDds.Wire" Version="1.0.0-rc.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZeroDds.Wire" Version="1.0.0-rc.7" />
                    
Directory.Packages.props
<PackageReference Include="ZeroDds.Wire" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ZeroDds.Wire --version 1.0.0-rc.7
                    
#r "nuget: ZeroDds.Wire, 1.0.0-rc.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ZeroDds.Wire@1.0.0-rc.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ZeroDds.Wire&version=1.0.0-rc.7&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ZeroDds.Wire&version=1.0.0-rc.7&prerelease
                    
Install as a Cake Tool

The C# wire runtime

The counterpart of crates/wire, runtime/c, runtime/cpp, runtime/java and runtime/python/zerodds_wire — a sixth implementation of DDS-XTypes 1.3 §7.4, not a binding to any of the other five. A C# column that reached the Rust core through P/Invoke would be byte-identical by construction and would prove nothing about whether the two read the specification the same way.

This assembly makes no decision about a type. Which members are written, in what order, with which header and which length code is the layout plan's answer and arrives here as arguments.

What is here

File What it carries
Writer.cs every write, the alignment rule, and the framing forms
Reader.cs its mirror, refusing every stream that cannot be true
Float128.cs IEEE 754 binary128, the type .NET has no primitive for
Md5.cs RFC 1321, for the KeyHash of DDSI-RTPS 2.5 §9.6.3.8
Encapsulation.cs the four bytes that announce an encoding
Endianness.cs, Encoding.cs byte order and MAXALIGN
Handles.cs DHeader, EmHeader, Pid, their read forms, and Status
PlCdr1Framing.cs how a PL_CDR1 parameter list is framed
Policies.cs the wchar/wstring axes, fixed's digit count, @try_construct
IdlName.cs the attribute a generated member's IDL spelling lives in
WireException.cs Truncated, ImpossibleLength, NotUtf8, OutOfRange

net8.0, TreatWarningsAsErrors, and no package reference at all: a measurement host has the SDK and no feed.

The four decisions this column makes, and why

1. The unsigned types are real, so the range checks are the compiler's

This is the whole difference from the Java column. There, writeU32(long) takes the next signed type up and range-checks at run time, because an int parameter would make 3735928559 arrive as -559038737 with the loss already done — and writeU64 cannot be a number at all and is documented as a bit pattern.

Here WriteU32(uint) takes a uint, WriteU64(ulong) takes a ulong, and 18446744073709551615 is a number. The value that does not fit is refused by csc rather than by a throw. What is left of the range checking is the ranges no C# type expresses: a char below U+0100, an @bit_bound between 1 and 32, a BCD field that fits fixed<P,S>.

2. long double is a sixteen-octet carrier and not decimal

Float128 holds the pattern as two ulong halves and converts to and from an exact decimal. decimal was considered and is not a binary128:

binary128 decimal
base two ten
significand 113 bits, ~34 decimal digits 96 bits, 28–29 digits
exponent range ±4932 0 to −28
signed zero yes no
infinity, NaN yes no

Three corpus values settle it on their own: 1e4000 is a finite binary128 and is outside decimal by a factor of 10^3971; -0.0 and +0.0 are different sixteen bytes on the wire and one decimal; primitive-longdouble carries five values no double holds. A member typed against decimal would put a different number on the wire and report success.

The namespace is ZeroDds.Idl and not ZeroDds.Wire, deliberately: crates/lang-rules/src/adapter/csharp.rs writes global::ZeroDds.Idl.Float128 as the member type for a long double, and a codec that met a second type of the same shape under a different name would not compile against the declarations. What is here is a superset of the struct that materialiser emits into a standalone file — the same two fields and the same constructor, plus the conversions — and tools/wireprobe/wireprobe-zerodds-csharp-gen drops the generated copy when it compiles against this assembly, because two declarations of one name is CS0101.

3. fixed<P,S> is a string and not decimal either

Same table, one row of it: IDL 4.2 §7.4.1.4.4 allows 31 digits and decimal carries 28 to 29. The corpus case fixed-scales declares fixed<31,10> and its value -12345678901234567890.1234567890 has thirty significant digits, which a decimal rounds — measured, not inferred.

Beyond the digits there is the axis. FixedDigitCount.ValuePrecision exists to measure how many digits a peer writes into the BCD run — omniORB and this project write the declared P, JacORB as many as the value has, ACE/TAO (FixedDigitCount.ValueStringDigits) the digits of the string it parsed — and a holder that normalises its leading zeros away has already decided that answer. WriteFixed takes the decimal text and does not parse it through decimal.Parse, which would accept an exponent and normalise a scale.

4. MD5 is RFC 1321 by hand and not System.Security.Cryptography

Not distrust of the platform. MD5.Create() is unavailable under a FIPS-enforcing policy: the managed implementation throws InvalidOperationException and the OS refuses the native one. A KeyHash that stops working because a machine was put in FIPS mode is a wire feature depending on a security policy it has nothing to do with — DDSI-RTPS 2.5 §9.6.3.8 names MD5 to identify an instance, not to sign one. SelfTest checks the arithmetic against RFC 1321 §A.5's own vectors, so the assumption is asserted rather than commented.

The three things .NET makes easy to get wrong

string.Length is neither bytes nor characters. It is UTF-16 code units, so it is the length of neither a string nor a wstring on the wire. A string's length counts octets of UTF-8 and includes the NUL; a wstring's counts, under the specification policy, the octets its code units occupy, so "𝄞" is a length of four.

Encoding.UTF8 does not fail. It replaces an unpaired surrogate with U+FFFD and reports success — a different character on the wire, silently. Writer encodes through a UTF8Encoding built with throwOnInvalidBytes: true and raises WireException.NotUtf8 instead.

Alignment is MIN(N, MAXALIGN) counted from the origin. Eight under XCDR1 and four under XCDR2, and the origin is where a PL_CDR1 parameter's block began — not zero, and never the value's own start. SelfTest checks an eight-byte field after a one-byte field at both caps and asserts that a reader at the wrong cap returns a different number rather than an error.

Running the tests

runtime/csharp/run-tests.sh

Silent when everything holds. Three sections, and only the last two are worth anything on their own:

  • the wire checks assert what this runtime believes — alignment at both MAXALIGNs, every primitive in both byte orders including u64 at 0xFFFFFFFFFFFFFFFF, strings and wstrings and fixed, DHEADER, the EMHEADER length codes including the short-code rewrite, the short and extended parameter headers including the promotion at a length over 0xFFFF, and RFC 1321's own MD5 vectors;
  • the binary128 oracle reads crates/float128/tests/oracle/patterns.txt — 518 bit patterns the Rust, C, Java and Python columns already agree on, and which GCC's own __float128 was measured against — and asserts that each shortest decimal reads back here to the same sixteen bytes;
  • the corpus cross-check writes three pure-primitive cases by hand from their type.idl and values.json and compares the octets with what the Rust column recorded in tests/interop-results/<case>/zerodds-rust/, under plain-cdr2.le and plain-cdr1.be — the two encodings that disagree about whether an eight-byte field aligns to four or to eight.

The column itself is measured by tools/wireprobe/wireprobe-csharp-corpus over the whole interop corpus, and crates/wire-probe/tests/csharp_column_gate.rs runs the handful that separate the things a column can get wrong on every cargo test.

Package delivery

ZeroDds.Wire is the canonical generated-code runtime package, version 1.0.0-rc.7. The native ZeroDDS package references it transitively alongside ZeroDDS.Cdr. Wire-only consumers can reference ZeroDds.Wire directly.

dotnet pack runtime/csharp/ZeroDds.Wire.csproj -c Release -o target/nuget

This prepares a local package, not a registry publication. The separate native DDS library is not included in this runtime package.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on ZeroDds.Wire:

Package Downloads
ZeroDDS

C# binding for ZeroDDS via P/Invoke over zerodds.h C-API. Pure-Rust DDS 1.4 / RTPS 2.5 / XTypes 1.3 implementation.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-rc.7 51 10/30/2026