rust: implement a test balloon via the "varint" subsystem

Implement a trivial test balloon for our Rust build infrastructure by
reimplementing the "varint.c" subsystem in Rust. This subsystem is
chosen because it is trivial to convert and because it doesn't have any
dependencies to other components of Git.

If support for Rust is enabled, we stop compiling "varint.c" and instead
compile and use "src/varint.rs".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2025-09-08 16:13:12 +02:00
committed by Junio C Hamano
parent 3df0d68b5a
commit 7f464d07d6
5 changed files with 104 additions and 1 deletions

View File

@@ -1307,7 +1307,9 @@ LIB_OBJS += urlmatch.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
ifndef WITH_RUST
LIB_OBJS += varint.o
endif
LIB_OBJS += version.o
LIB_OBJS += versioncmp.o
LIB_OBJS += walker.o
@@ -1499,6 +1501,7 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
RUST_SOURCES += src/lib.rs
RUST_SOURCES += src/varint.rs
GIT-VERSION-FILE: FORCE
@OLD=$$(cat $@ 2>/dev/null || :) && \

View File

@@ -522,7 +522,6 @@ libgit_sources = [
'usage.c',
'userdiff.c',
'utf8.c',
'varint.c',
'version.c',
'versioncmp.c',
'walker.c',
@@ -1716,6 +1715,10 @@ rust_option = get_option('rust').disable_auto_if(not rust_available)
if rust_option.allowed()
subdir('src')
libgit_c_args += '-DWITH_RUST'
else
libgit_sources += [
'varint.c',
]
endif
libgit = declare_dependency(

View File

@@ -0,0 +1 @@
pub mod varint;

View File

@@ -1,5 +1,6 @@
libgit_rs_sources = [
'lib.rs',
'varint.rs',
]
if meson.version().version_compare('>=1.5.0')

95
src/varint.rs Normal file
View File

@@ -0,0 +1,95 @@
use std::os::raw::c_int;
use std::os::raw::c_uchar;
#[no_mangle]
pub unsafe extern "C" fn decode_varint(bufp: *mut *const c_uchar) -> usize {
let mut buf = *bufp;
let mut c = *buf;
let mut val = usize::from(c & 127);
buf = buf.add(1);
while (c & 128) != 0 {
val = val.wrapping_add(1);
if val == 0 || val.leading_zeros() < 7 {
return 0; // overflow
}
c = *buf;
buf = buf.add(1);
val = (val << 7) + usize::from(c & 127);
}
*bufp = buf;
val
}
#[no_mangle]
pub unsafe extern "C" fn encode_varint(value: usize, buf: *mut c_uchar) -> c_int {
let mut varint: [u8; 16] = [0; 16];
let mut pos = varint.len() - 1;
varint[pos] = (value & 127) as u8;
let mut value = value >> 7;
while value != 0 {
pos -= 1;
value -= 1;
varint[pos] = 128 | (value & 127) as u8;
value >>= 7;
}
if !buf.is_null() {
std::ptr::copy_nonoverlapping(varint.as_ptr().add(pos), buf, varint.len() - pos);
}
(varint.len() - pos) as c_int
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decode_varint() {
unsafe {
assert_eq!(decode_varint(&mut [0x00].as_slice().as_ptr()), 0);
assert_eq!(decode_varint(&mut [0x01].as_slice().as_ptr()), 1);
assert_eq!(decode_varint(&mut [0x7f].as_slice().as_ptr()), 127);
assert_eq!(decode_varint(&mut [0x80, 0x00].as_slice().as_ptr()), 128);
assert_eq!(decode_varint(&mut [0x80, 0x01].as_slice().as_ptr()), 129);
assert_eq!(decode_varint(&mut [0x80, 0x7f].as_slice().as_ptr()), 255);
// Overflows are expected to return 0.
assert_eq!(decode_varint(&mut [0x88; 16].as_slice().as_ptr()), 0);
}
}
#[test]
fn test_encode_varint() {
unsafe {
let mut varint: [u8; 16] = [0; 16];
assert_eq!(encode_varint(0, std::ptr::null_mut()), 1);
assert_eq!(encode_varint(0, varint.as_mut_slice().as_mut_ptr()), 1);
assert_eq!(varint, [0; 16]);
assert_eq!(encode_varint(10, varint.as_mut_slice().as_mut_ptr()), 1);
assert_eq!(varint, [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(encode_varint(127, varint.as_mut_slice().as_mut_ptr()), 1);
assert_eq!(varint, [127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(encode_varint(128, varint.as_mut_slice().as_mut_ptr()), 2);
assert_eq!(varint, [128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(encode_varint(129, varint.as_mut_slice().as_mut_ptr()), 2);
assert_eq!(varint, [128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(encode_varint(255, varint.as_mut_slice().as_mut_ptr()), 2);
assert_eq!(varint, [128, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
}
}
}