From: Ramsay Jones Date: Tue, 18 Nov 2025 23:46:47 GMT Subject: Re: [PATCH v5 01/10] doc: define unambiguous type mappings across C and Rust Message-ID: <9c7a7d09-2cc0-40f7-b37a-befef5339d76@ramsayjones.plus.com> In-Reply-To: <8b56bf117289ca3be25533a36da1ea0c178ccfca.1763505262.git.gitgitgadget@gmail.com> On 18/11/2025 10:34 pm, Ezekiel Newren via GitGitGadget wrote: > From: Ezekiel Newren > > Document other nuances when crossing the FFI boundary. Other language > mappings may be added in the future. > > Signed-off-by: Ezekiel Newren > --- > Documentation/Makefile | 1 + > Documentation/technical/meson.build | 1 + > .../technical/unambiguous-types.adoc | 224 ++++++++++++++++++ > 3 files changed, 226 insertions(+) > create mode 100644 Documentation/technical/unambiguous-types.adoc > [snip] > diff --git a/Documentation/technical/unambiguous-types.adoc b/Documentation/technical/unambiguous-types.adoc > new file mode 100644 > index 0000000000..9a4990847c > --- /dev/null > +++ b/Documentation/technical/unambiguous-types.adoc > @@ -0,0 +1,224 @@ > += Unambiguous types > + > +Most of these mappings are obvious, but there are some nuances and gotchas with > +Rust FFI (Foreign Function Interface). > + > +This document defines clear, one-to-one mappings between primitive types in C, > +Rust (and possible other languages in the future). Its purpose is to eliminate > +ambiguity in type widths, signedness, and binary representation across > +platforms and languages. > + > +For Git, the only header required to use these unambiguous types in C is > +`git-compat-util.h`. > + > +== Boolean types > +[cols="1,1", options="header"] > +|=== > +| C Type | Rust Type > +| bool^1^ | bool > +|=== > + > +== Integer types > + > +In C, `` (or an equivalent) must be included. > + > +[cols="1,1", options="header"] > +|=== > +| C Type | Rust Type > +| uint8_t | u8 > +| uint16_t | u16 > +| uint32_t | u32 > +| uint64_t | u64 > + > +| int8_t | i8 > +| int16_t | i16 > +| int32_t | i32 > +| int64_t | i64 > +|=== > + > +== Floating-point types > + > +Rust requires IEEE-754 semantics. > +In C, that is typically true, but not guaranteed by the standard. > + > +[cols="1,1", options="header"] > +|=== > +| C Type | Rust Type > +| float^2^ | f32 > +| double^2^ | f64 > +|=== > + > +== Size types > + > +These types represent pointer-sized integers and are typically defined in > +`` or an equivalent header. > + > +Size types should be used any time pointer arithmetic is performed e.g. > +indexing an array, describing the number of elements in memory, etc... > + > +[cols="1,1", options="header"] > +|=== > +| C Type | Rust Type > +| size_t^3^ | usize > +| ptrdiff_t^3^ | isize > +|=== > + > +== Character types > + > +This is where C and Rust don't have a clean one-to-one mapping. > + > +A C `char` and a Rust `u8` share the same bit width, so any C struct containing > +a `char` will have the same size as the corresponding Rust struct using `u8`. > +In that sense, such structs are safe to pass over the FFI boundary, because > +their fields will be laid out identically. However, beyond bit width, C `char` > +has additional semantics and platform-dependent behavior that can cause > +problems, as discussed below. > + > +The C language leaves the signedness of `char` implementation defined. Because > +our developer build enables -Wsign-compare, comparison of a value of `char` > +type with either signed or unsigned integers may trigger warnings from the > +compiler. Yep, much better. Thanks! ATB, Ramsay Jones