summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2025-10-02 09:29:31 +0200
committerJunio C Hamano <gitster@pobox.com>2025-10-02 09:32:32 -0700
commit8832e728d362992a38eef89613b44d24f18e6c2a (patch)
tree0762b93f2b58aa01ebc8a39166bd363141a40821
parentf366bfe16b350240c70c487d180c76ddcb8a1b2d (diff)
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>
-rw-r--r--Makefile3
-rw-r--r--meson.build5
-rw-r--r--src/lib.rs1
-rw-r--r--src/meson.build1
-rw-r--r--src/varint.rs92
5 files changed, 101 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 31e79342e1..2a7fc5cb1f 100644
--- a/Makefile
+++ b/Makefile
@@ -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 || :) && \
diff --git a/meson.build b/meson.build
index 234a9e9d6f..37dfa28601 100644
--- a/meson.build
+++ b/meson.build
@@ -522,7 +522,6 @@ libgit_sources = [
'usage.c',
'userdiff.c',
'utf8.c',
- 'varint.c',
'version.c',
'versioncmp.c',
'walker.c',
@@ -1707,6 +1706,10 @@ rust_option = get_option('rust').disable_auto_if(not cargo.found())
if rust_option.allowed()
subdir('src')
libgit_c_args += '-DWITH_RUST'
+else
+ libgit_sources += [
+ 'varint.c',
+ ]
endif
libgit = declare_dependency(
diff --git a/src/lib.rs b/src/lib.rs
index e69de29bb2..9da70d8b57 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -0,0 +1 @@
+pub mod varint;
diff --git a/src/meson.build b/src/meson.build
index c8d874b210..25b9ad5a14 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,5 +1,6 @@
libgit_rs_sources = [
'lib.rs',
+ 'varint.rs',
]
# Unfortunately we must use a wrapper command to move the output file into the
diff --git a/src/varint.rs b/src/varint.rs
new file mode 100644
index 0000000000..6e610bdd8e
--- /dev/null
+++ b/src/varint.rs
@@ -0,0 +1,92 @@
+#[no_mangle]
+pub unsafe extern "C" fn decode_varint(bufp: *mut *const u8) -> u64 {
+ let mut buf = *bufp;
+ let mut c = *buf;
+ let mut val = u64::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) + u64::from(c & 127);
+ }
+
+ *bufp = buf;
+ val
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn encode_varint(value: u64, buf: *mut u8) -> u8 {
+ 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 u8
+}
+
+#[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]);
+ }
+ }
+}