Skip to content

Commit 348195f

Browse files
committed
refactor: move varint into its own file
1 parent cceda82 commit 348195f

File tree

8 files changed

+126
-117
lines changed

8 files changed

+126
-117
lines changed

datadog-profiling-protobuf/src/function.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ impl Value for Function {
1919

2020
fn proto_len(&self) -> u64 {
2121
Varint(self.id).field(1).proto_len()
22-
+ Varint(self.name.to_u64()).field(2).proto_len_small()
23-
+ Varint(self.system_name.to_u64()).field(3).proto_len_small()
24-
+ Varint(self.filename.to_u64()).field(4).proto_len_small()
22+
+ Varint::from(self.name).field(2).proto_len_small()
23+
+ Varint::from(self.system_name).field(3).proto_len_small()
24+
+ Varint::from(self.filename).field(4).proto_len_small()
2525
}
2626

2727
fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
2828
Varint(self.id).field(1).encode(writer)?;
29-
Varint(self.name.into()).field(2).encode_small(writer)?;
30-
Varint(self.system_name.into())
29+
Varint::from(self.name).field(2).encode_small(writer)?;
30+
Varint::from(self.system_name)
3131
.field(3)
3232
.encode_small(writer)?;
33-
Varint(self.filename.into()).field(4).encode_small(writer)
33+
Varint::from(self.filename).field(4).encode_small(writer)
3434
}
3535
}
3636

datadog-profiling-protobuf/src/label.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ impl Value for Label {
2020
const WIRE_TYPE: WireType = WireType::LengthDelimited;
2121

2222
fn proto_len(&self) -> u64 {
23-
Varint::from(self.key.to_u64()).field(1).proto_len()
24-
+ Varint(self.str.to_u64()).field(2).proto_len_small()
25-
+ Varint(self.num as u64).field(3).proto_len_small()
26-
+ Varint(self.num_unit.to_u64()).field(4).proto_len_small()
23+
Varint::from(self.key).field(1).proto_len()
24+
+ Varint::from(self.str).field(2).proto_len_small()
25+
+ Varint::from(self.num).field(3).proto_len_small()
26+
+ Varint::from(self.num_unit).field(4).proto_len_small()
2727
}
2828

2929
fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
30-
Varint::from(self.key.to_u64()).field(1).encode(writer)?;
31-
Varint(self.str.into()).field(2).encode_small(writer)?;
32-
Varint(self.num as u64).field(3).encode_small(writer)?;
33-
Varint(self.num_unit.into()).field(4).encode_small(writer)
30+
Varint::from(self.key).field(1).encode(writer)?;
31+
Varint::from(self.str).field(2).encode_small(writer)?;
32+
Varint::from(self.num).field(3).encode_small(writer)?;
33+
Varint::from(self.num_unit).field(4).encode_small(writer)
3434
}
3535
}
3636

datadog-profiling-protobuf/src/lib.rs

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod mapping;
1313
mod sample;
1414
mod string;
1515
mod value_type;
16+
mod varint;
1617

1718
#[cfg(feature = "prost_impls")]
1819
pub mod prost_impls;
@@ -24,6 +25,7 @@ pub use mapping::*;
2425
pub use sample::*;
2526
pub use string::*;
2627
pub use value_type::*;
28+
pub use varint::*;
2729

2830
use std::io::{self, Write};
2931

@@ -52,12 +54,6 @@ pub trait Value {
5254
}
5355
}
5456

55-
/// You can use varint to store any of the listed data types:
56-
/// int32 | int64 | uint32 | uint64 | bool | enum | sint32 | sint64
57-
#[repr(transparent)]
58-
#[derive(Copy, Clone)]
59-
pub struct Varint(pub u64);
60-
6157
/// A tag and value pair.
6258
///
6359
/// The wire type isn't stored; it's provided by the Value implementation,
@@ -122,9 +118,6 @@ const MIN_FIELD: u32 = 1;
122118
/// The largest possible protobuf field number.
123119
const MAX_FIELD: u32 = (1 << 29) - 1;
124120

125-
/// An encoded 64-bit unsigned number takes between 1 and 10 bytes, inclusive.
126-
pub const MAX_VARINT_LEN: u64 = 10;
127-
128121
/// Represents the wire type for in-wire protobuf. There are more types than
129122
/// are represented here; these are just the supported ones.
130123
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -133,72 +126,6 @@ pub enum WireType {
133126
Varint = 0,
134127
LengthDelimited = 2,
135128
}
136-
impl Varint {
137-
/// Returns the number of bytes it takes to encode a varint. This is
138-
/// between 1 and 10 bytes, inclusive.
139-
pub const fn proto_len(&self) -> u64 {
140-
// https://github.com/google/protobuf/blob/3.3.x/src/google/protobuf/io/coded_stream.h#L1301-L1309
141-
((((self.0 | 1).leading_zeros() ^ 63) * 9 + 73) / 64) as u64
142-
}
143-
}
144-
145-
impl Value for Varint {
146-
const WIRE_TYPE: WireType = WireType::Varint;
147-
148-
fn proto_len(&self) -> u64 {
149-
self.proto_len()
150-
}
151-
152-
/// Encodes a varint according to protobuf semantics.
153-
///
154-
/// Note that it will write between 1 and 10 bytes, inclusive. You should
155-
/// probably write to a buffered Write object--if you write directly to
156-
/// something like a TCP stream, it's going to send one byte at a time,
157-
/// which is excessively inefficient. In libdatadog, we typically write to
158-
/// some sort of compressor which has its own input buffer.
159-
///
160-
/// See https://protobuf.dev/programming-guides/encoding/#varints
161-
#[inline]
162-
fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
163-
let mut value = self.0;
164-
loop {
165-
let byte = if value < 0x80 {
166-
value as u8
167-
} else {
168-
((value & 0x7F) | 0x80) as u8
169-
};
170-
writer.write_all(&[byte])?;
171-
if value < 0x80 {
172-
return Ok(());
173-
}
174-
value >>= 7;
175-
}
176-
}
177-
}
178-
179-
impl From<u64> for Varint {
180-
fn from(value: u64) -> Self {
181-
Varint(value)
182-
}
183-
}
184-
185-
impl From<&u64> for Varint {
186-
fn from(value: &u64) -> Self {
187-
Varint(*value)
188-
}
189-
}
190-
191-
impl From<i64> for Varint {
192-
fn from(value: i64) -> Self {
193-
Varint(value as u64)
194-
}
195-
}
196-
197-
impl From<&i64> for Varint {
198-
fn from(value: &i64) -> Self {
199-
Varint(*value as u64)
200-
}
201-
}
202129

203130
impl Tag {
204131
#[cfg_attr(debug_assertions, track_caller)]
@@ -209,7 +136,7 @@ impl Tag {
209136
}
210137

211138
#[inline]
212-
pub const fn proto_len(self) -> u64 {
139+
pub fn proto_len(self) -> u64 {
213140
self.into_varint().proto_len()
214141
}
215142

@@ -257,14 +184,3 @@ where
257184
Ok(())
258185
}
259186
}
260-
261-
#[cfg(test)]
262-
mod tests {
263-
use super::*;
264-
265-
#[test]
266-
fn max_varint_len() {
267-
assert_eq!(MAX_VARINT_LEN, 10);
268-
assert_eq!(MAX_VARINT_LEN, Varint(u64::MAX).proto_len());
269-
}
270-
}

datadog-profiling-protobuf/src/location.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use crate::{Tag, Value, Varint, WireType};
4+
use crate::varint::Varint;
5+
use crate::{Tag, Value, WireType};
56
use std::io::{self, Write};
67

78
#[repr(C)]
@@ -27,12 +28,12 @@ impl Value for Line {
2728

2829
fn proto_len(&self) -> u64 {
2930
Varint(self.function_id).field(1).proto_len_small()
30-
+ Varint(self.lineno as u64).field(2).proto_len_small()
31+
+ Varint::from(self.lineno).field(2).proto_len_small()
3132
}
3233

3334
fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
3435
Varint(self.function_id).field(1).encode_small(writer)?;
35-
Varint(self.lineno as u64).field(2).encode_small(writer)
36+
Varint::from(self.lineno).field(2).encode_small(writer)
3637
}
3738
}
3839

datadog-profiling-protobuf/src/mapping.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ impl Value for Mapping {
2626
+ Varint(self.memory_start).field(2).proto_len_small()
2727
+ Varint(self.memory_limit).field(3).proto_len_small()
2828
+ Varint(self.file_offset).field(4).proto_len_small()
29-
+ Varint(self.filename.to_u64()).field(5).proto_len_small()
30-
+ Varint(self.build_id.to_u64()).field(6).proto_len_small()
29+
+ Varint::from(self.filename).field(5).proto_len_small()
30+
+ Varint::from(self.build_id).field(6).proto_len_small()
3131
}
3232

3333
fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
3434
Varint(self.id).field(1).encode(writer)?;
3535
Varint(self.memory_start).field(2).encode_small(writer)?;
3636
Varint(self.memory_limit).field(3).encode_small(writer)?;
3737
Varint(self.file_offset).field(4).encode_small(writer)?;
38-
Varint(self.filename.into()).field(5).encode_small(writer)?;
39-
Varint(self.build_id.into()).field(6).encode_small(writer)
38+
Varint::from(self.filename).field(5).encode_small(writer)?;
39+
Varint::from(self.build_id).field(6).encode_small(writer)
4040
}
4141
}
4242

datadog-profiling-protobuf/src/string.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ impl Value for &str {
2121
/// equal to 2 GiB. By the time you encode the tag and length prefix for each
2222
/// string, there's no way to get this many unique-ish strings without first
2323
/// exceeding the protobuf 2 GiB limit.
24+
///
25+
/// A value of 0 means "no string" or "empty string" (they are synonymous).
2426
#[repr(C)]
2527
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
2628
#[cfg_attr(test, derive(bolero::generator::TypeGenerator))]
@@ -158,9 +160,4 @@ impl StringOffset {
158160
pub const fn is_zero(&self) -> bool {
159161
self.0 == 0
160162
}
161-
162-
#[inline]
163-
pub const fn to_u64(&self) -> u64 {
164-
self.0 as u64
165-
}
166163
}

datadog-profiling-protobuf/src/value_type.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ impl Value for ValueType {
1616
const WIRE_TYPE: WireType = WireType::LengthDelimited;
1717

1818
fn proto_len(&self) -> u64 {
19-
Varint(self.r#type.to_u64()).field(1).proto_len_small()
20-
+ Varint(self.unit.to_u64()).field(2).proto_len_small()
19+
Varint::from(self.r#type).field(1).proto_len_small()
20+
+ Varint::from(self.unit).field(2).proto_len_small()
2121
}
2222

2323
fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
24-
Varint(self.r#type.into()).field(1).encode_small(writer)?;
25-
Varint(self.unit.into()).field(2).encode_small(writer)
24+
Varint::from(self.r#type).field(1).encode_small(writer)?;
25+
Varint::from(self.unit).field(2).encode_small(writer)
2626
}
2727
}
2828

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::{StringOffset, Value, WireType};
5+
use std::io::{self, Write};
6+
7+
/// You can use varint to store any of the listed data types:
8+
/// int32 | int64 | uint32 | uint64 | bool | enum | sint32 | sint64
9+
#[repr(transparent)]
10+
#[derive(Copy, Clone)]
11+
pub struct Varint(pub u64);
12+
13+
impl Value for Varint {
14+
const WIRE_TYPE: WireType = WireType::Varint;
15+
16+
/// Returns the number of bytes it takes to encode a varint. This is
17+
/// between 1 and 10 bytes, inclusive.
18+
fn proto_len(&self) -> u64 {
19+
// https://github.com/google/protobuf/blob/3.3.x/src/google/protobuf/io/coded_stream.h#L1301-L1309
20+
((((self.0 | 1).leading_zeros() ^ 63) * 9 + 73) / 64) as u64
21+
}
22+
23+
/// Encodes a varint according to protobuf semantics.
24+
///
25+
/// Note that it will write between 1 and 10 bytes, inclusive. You should
26+
/// probably write to a buffered Write object--if you write directly to
27+
/// something like a TCP stream, it's going to send one byte at a time,
28+
/// which is excessively inefficient. In libdatadog, we typically write to
29+
/// some sort of compressor which has its own input buffer.
30+
///
31+
/// See https://protobuf.dev/programming-guides/encoding/#varints
32+
#[inline]
33+
fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
34+
let mut value = self.0;
35+
loop {
36+
let byte = if value < 0x80 {
37+
value as u8
38+
} else {
39+
((value & 0x7F) | 0x80) as u8
40+
};
41+
writer.write_all(&[byte])?;
42+
if value < 0x80 {
43+
return Ok(());
44+
}
45+
value >>= 7;
46+
}
47+
}
48+
}
49+
50+
impl From<u64> for Varint {
51+
fn from(value: u64) -> Self {
52+
Varint(value)
53+
}
54+
}
55+
56+
impl From<&u64> for Varint {
57+
fn from(value: &u64) -> Self {
58+
Varint(*value)
59+
}
60+
}
61+
62+
impl From<i64> for Varint {
63+
fn from(value: i64) -> Self {
64+
Varint(value as u64)
65+
}
66+
}
67+
68+
impl From<&i64> for Varint {
69+
fn from(value: &i64) -> Self {
70+
Varint(*value as u64)
71+
}
72+
}
73+
74+
impl From<StringOffset> for Varint {
75+
fn from(string_offset: StringOffset) -> Self {
76+
Self(u64::from(string_offset))
77+
}
78+
}
79+
80+
impl From<&StringOffset> for Varint {
81+
fn from(string_offset: &StringOffset) -> Self {
82+
Self(u64::from(string_offset))
83+
}
84+
}
85+
86+
#[cfg(test)]
87+
mod tests {
88+
use super::*;
89+
90+
#[test]
91+
fn max_varint_len() {
92+
assert_eq!(Varint(0).proto_len(), 1);
93+
assert_eq!(Varint(u64::MAX).proto_len(), 10);
94+
}
95+
}

0 commit comments

Comments
 (0)