Skip to content

Commit 8832e72

Browse files
pks-tgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f366bfe commit 8832e72

File tree

5 files changed

+101
-1
lines changed

5 files changed

+101
-1
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,9 @@ LIB_OBJS += urlmatch.o
13071307
LIB_OBJS += usage.o
13081308
LIB_OBJS += userdiff.o
13091309
LIB_OBJS += utf8.o
1310+
ifndef WITH_RUST
13101311
LIB_OBJS += varint.o
1312+
endif
13111313
LIB_OBJS += version.o
13121314
LIB_OBJS += versioncmp.o
13131315
LIB_OBJS += walker.o
@@ -1499,6 +1501,7 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
14991501
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
15001502

15011503
RUST_SOURCES += src/lib.rs
1504+
RUST_SOURCES += src/varint.rs
15021505

15031506
GIT-VERSION-FILE: FORCE
15041507
@OLD=$$(cat $@ 2>/dev/null || :) && \

meson.build

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,6 @@ libgit_sources = [
522522
'usage.c',
523523
'userdiff.c',
524524
'utf8.c',
525-
'varint.c',
526525
'version.c',
527526
'versioncmp.c',
528527
'walker.c',
@@ -1707,6 +1706,10 @@ rust_option = get_option('rust').disable_auto_if(not cargo.found())
17071706
if rust_option.allowed()
17081707
subdir('src')
17091708
libgit_c_args += '-DWITH_RUST'
1709+
else
1710+
libgit_sources += [
1711+
'varint.c',
1712+
]
17101713
endif
17111714

17121715
libgit = declare_dependency(

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod varint;

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
libgit_rs_sources = [
22
'lib.rs',
3+
'varint.rs',
34
]
45

56
# Unfortunately we must use a wrapper command to move the output file into the

src/varint.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)