varint: reimplement as test balloon for Rust
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>
Patrick Steinhardt committed
Oct 2, 2025 at 09:29 UTC
8832e728d362992a38eef89613b44d24f18e6c2a
5 files changed
+101
-1
Makefile
+3
@@ -1307,7 +1307,9 @@ LIB_OBJS += urlmatch.o
1307
LIB_OBJS += usage.o
1308
LIB_OBJS += userdiff.o
1309
LIB_OBJS += utf8.o
1310
+ifndef WITH_RUST
1311
LIB_OBJS += varint.o
1312
+endif
1313
LIB_OBJS += version.o
1314
LIB_OBJS += versioncmp.o
1315
LIB_OBJS += walker.o
@@ -1499,6 +1501,7 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
1501
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
1502
1503
RUST_SOURCES += src/lib.rs
1504
+RUST_SOURCES += src/varint.rs
1505
1506
GIT-VERSION-FILE: FORCE
1507
@OLD=$$(cat $@ 2>/dev/null || :) && \
meson.build
+4
-1
@@ -522,7 +522,6 @@ libgit_sources = [
522
'usage.c',
523
'userdiff.c',
524
'utf8.c',
525
- 'varint.c',
525
'version.c',
526
'versioncmp.c',
527
'walker.c',
@@ -1707,6 +1706,10 @@ rust_option = get_option('rust').disable_auto_if(not cargo.found())
1706
if rust_option.allowed()
1707
subdir('src')
1708
libgit_c_args += '-DWITH_RUST'
1709
+else
1710
+ libgit_sources += [
1711
+ 'varint.c',
1712
+ ]
1713
endif
1714
1715
libgit = declare_dependency(
src/lib.rs
+1
@@ -0,0 +1 @@
1
+pub mod varint;
src/meson.build
+1
@@ -1,5 +1,6 @@
1
libgit_rs_sources = [
2
'lib.rs',
3
+ 'varint.rs',
4
]
5
6
# Unfortunately we must use a wrapper command to move the output file into the
src/varint.rs
new
+92
@@ -0,0 +1,92 @@
1
+#[no_mangle]
2
+pub unsafe extern "C" fn decode_varint(bufp: *mut *const u8) -> u64 {
3
+ let mut buf = *bufp;
4
+ let mut c = *buf;
5
+ let mut val = u64::from(c & 127);
6
+
7
+ buf = buf.add(1);
8
+
9
+ while (c & 128) != 0 {
10
+ val = val.wrapping_add(1);
11
+ if val == 0 || val.leading_zeros() < 7 {
12
+ return 0; // overflow
13
+ }
14
+
15
+ c = *buf;
16
+ buf = buf.add(1);
17
+
18
+ val = (val << 7) + u64::from(c & 127);
19
+ }
20
+
21
+ *bufp = buf;
22
+ val
23
+}
24
+
25
+#[no_mangle]
26
+pub unsafe extern "C" fn encode_varint(value: u64, buf: *mut u8) -> u8 {
27
+ let mut varint: [u8; 16] = [0; 16];
28
+ let mut pos = varint.len() - 1;
29
+
30
+ varint[pos] = (value & 127) as u8;
31
+
32
+ let mut value = value >> 7;
33
+ while value != 0 {
34
+ pos -= 1;
35
+ value -= 1;
36
+ varint[pos] = 128 | (value & 127) as u8;
37
+ value >>= 7;
38
+ }
39
+
40
+ if !buf.is_null() {
41
+ std::ptr::copy_nonoverlapping(varint.as_ptr().add(pos), buf, varint.len() - pos);
42
+ }
43
+
44
+ (varint.len() - pos) as u8
45
+}
46
+
47
+#[cfg(test)]
48
+mod tests {
49
+ use super::*;
50
+
51
+ #[test]
52
+ fn test_decode_varint() {
53
+ unsafe {
54
+ assert_eq!(decode_varint(&mut [0x00].as_slice().as_ptr()), 0);
55
+ assert_eq!(decode_varint(&mut [0x01].as_slice().as_ptr()), 1);
56
+ assert_eq!(decode_varint(&mut [0x7f].as_slice().as_ptr()), 127);
57
+ assert_eq!(decode_varint(&mut [0x80, 0x00].as_slice().as_ptr()), 128);
58
+ assert_eq!(decode_varint(&mut [0x80, 0x01].as_slice().as_ptr()), 129);
59
+ assert_eq!(decode_varint(&mut [0x80, 0x7f].as_slice().as_ptr()), 255);
60
+
61
+ // Overflows are expected to return 0.
62
+ assert_eq!(decode_varint(&mut [0x88; 16].as_slice().as_ptr()), 0);
63
+ }
64
+ }
65
+
66
+ #[test]
67
+ fn test_encode_varint() {
68
+ unsafe {
69
+ let mut varint: [u8; 16] = [0; 16];
70
+
71
+ assert_eq!(encode_varint(0, std::ptr::null_mut()), 1);
72
+
73
+ assert_eq!(encode_varint(0, varint.as_mut_slice().as_mut_ptr()), 1);
74
+ assert_eq!(varint, [0; 16]);
75
+
76
+ assert_eq!(encode_varint(10, varint.as_mut_slice().as_mut_ptr()), 1);
77
+ assert_eq!(varint, [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
78
+
79
+ assert_eq!(encode_varint(127, varint.as_mut_slice().as_mut_ptr()), 1);
80
+ assert_eq!(varint, [127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
81
+
82
+ assert_eq!(encode_varint(128, varint.as_mut_slice().as_mut_ptr()), 2);
83
+ assert_eq!(varint, [128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
84
+
85
+ assert_eq!(encode_varint(129, varint.as_mut_slice().as_mut_ptr()), 2);
86
+ assert_eq!(varint, [128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
87
+
88
+ assert_eq!(encode_varint(255, varint.as_mut_slice().as_mut_ptr()), 2);
89
+ assert_eq!(varint, [128, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
90
+ }
91
+ }
92
+}