Skip to content

Commit 506df31

Browse files
committed
feat: optimize implement of the vortex
Signed-off-by: Gaius <gaius.qi@gmail.com>
1 parent 7dd0363 commit 506df31

File tree

7 files changed

+79
-124
lines changed

7 files changed

+79
-124
lines changed

README.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55

66
## Introduction
77

8-
Vortex is a high-performance peer-to-peer (P2P) file transfer protocol implementation in Rust, designed as part of the Dragonfly project. It utilizes the TLV (Tag-Length-Value) format for efficient and flexible data transmission, making it ideal for large-scale file distribution scenarios.
8+
Vortex is a high-performance peer-to-peer (P2P) file transfer protocol implementation in Rust,
9+
designed as part of the Dragonfly project. It utilizes the TLV (Tag-Length-Value) format for
10+
efficient and flexible data transmission, making it ideal for large-scale file distribution scenarios.
911

10-
### Key Features
12+
### Features
1113

12-
- **Efficient TLV Protocol**: Optimized for fast serialization and deserialization of data packets
13-
- **Large File Support**: Handles piece sizes up to 1 GiB and value fields up to 4 GiB
14-
- **Memory Safety**: Built in Rust with zero-cost abstractions and memory safety guarantees
15-
- **High Performance**: Designed for high-throughput file transfer scenarios
16-
- **Extensible Design**: Reserved tags for future protocol extensions like compression and encryption
14+
- **Efficient TLV Protocol**: Optimized for fast serialization and deserialization of data packets.
15+
- **Large File Support**: Handles piece sizes up to 1 GiB and value fields up to 4 GiB.
16+
- **Memory Safety**: Built in Rust with zero-cost abstractions and memory safety guarantees.
17+
- **High Performance**: Designed for high-throughput file transfer scenarios.
18+
- **Extensible Design**: Reserved tags for future protocol extensions like compression and encryption.
1719

1820
## Documentation
1921

@@ -37,7 +39,3 @@ The benchmarks cover various packet sizes:
3739
- Medium packets (1 KB)
3840
- Large packets (1 MB)
3941
- Extra large packets (16 MB)
40-
41-
## LICENSE
42-
43-
Apache 2.0 License. Please see [LICENSE](LICENSE) for more information.

src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ impl Vortex {
7676
tag,
7777
length: value.len(),
7878
};
79+
7980
(tag, header, value).try_into()
8081
}
8182

@@ -173,8 +174,11 @@ impl Vortex {
173174
}
174175
}
175176

177+
/// Implement TryFrom<(tlv::Tag, Header, Bytes)> for Vortex.
176178
impl TryFrom<(tlv::Tag, Header, Bytes)> for Vortex {
177179
type Error = Error;
180+
181+
/// try_from converts a tuple of Tag, Header, and Bytes into a Vortex packet.
178182
fn try_from((tag, header, value): (tlv::Tag, Header, Bytes)) -> Result<Self> {
179183
match tag {
180184
tlv::Tag::DownloadPiece => {
@@ -216,6 +220,7 @@ mod tests {
216220
let value = b"piece content";
217221
let packet = Vortex::new(Tag::PieceContent, Bytes::from_static(value))
218222
.expect("Failed to create packet");
223+
219224
assert_eq!(packet.tag(), &Tag::PieceContent);
220225
assert_eq!(packet.length(), value.len());
221226
}
@@ -227,6 +232,7 @@ mod tests {
227232
.expect("Failed to create packet");
228233
let bytes = packet.to_bytes();
229234
let deserialized = Vortex::from_bytes(bytes).expect("Failed to deserialize packet");
235+
230236
assert_eq!(packet.tag(), deserialized.tag());
231237
assert_eq!(packet.length(), deserialized.length());
232238
}
@@ -237,14 +243,15 @@ mod tests {
237243
let packet = Vortex::new(Tag::PieceContent, Bytes::from_static(value))
238244
.expect("Failed to create packet");
239245
let bytes = packet.to_bytes();
246+
240247
assert_eq!(bytes.len(), HEADER_SIZE + value.len());
241248
}
242249

243250
#[test]
244251
fn test_error_handling() {
245-
// Test invalid length
246252
let value = vec![0; MAX_VALUE_SIZE + 1];
247253
let result = Vortex::new(Tag::PieceContent, value.into());
254+
248255
assert!(matches!(result, Err(Error::InvalidLength(_))));
249256
}
250257
}

src/tlv/download_piece.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,11 @@ impl DownloadPiece {
7575
}
7676
}
7777

78-
/// Implement TryFrom<Bytes> for DownloadPiece.
78+
/// Implement TryFrom<Bytes> for DownloadPiece for conversion from a byte slice.
7979
impl TryFrom<Bytes> for DownloadPiece {
8080
type Error = Error;
8181

82+
/// try_from decodes the download piece request from the byte slice.
8283
fn try_from(bytes: Bytes) -> Result<Self> {
8384
let mut parts = bytes.splitn(2, |&b| b == SEPARATOR);
8485
let task_id = std::str::from_utf8(
@@ -103,8 +104,9 @@ impl TryFrom<Bytes> for DownloadPiece {
103104
}
104105
}
105106

106-
/// Implement From<DownloadPiece> for Bytes.
107+
/// Implement From<DownloadPiece> for Bytes for conversion to a byte slice.
107108
impl From<DownloadPiece> for Bytes {
109+
/// from converts the download piece request to a byte slice.
108110
fn from(piece: DownloadPiece) -> Self {
109111
let mut bytes = BytesMut::with_capacity(DOWNLOAD_PIECE_SIZE);
110112
bytes.extend_from_slice(piece.task_id.as_bytes());
@@ -145,31 +147,28 @@ mod tests {
145147
let piece_number = 42;
146148
let download_piece = DownloadPiece::new(task_id.clone(), piece_number);
147149

148-
// Test From<DownloadPiece> for Bytes
149150
let bytes: Bytes = download_piece.into();
151+
let download_piece = DownloadPiece::try_from(bytes).unwrap();
150152

151-
// Test TryFrom<Bytes> for DownloadPiece
152-
let download_piece_decoded = DownloadPiece::try_from(bytes).unwrap();
153-
154-
assert_eq!(download_piece_decoded.task_id(), task_id);
155-
assert_eq!(download_piece_decoded.piece_number(), piece_number);
153+
assert_eq!(download_piece.task_id(), task_id);
154+
assert_eq!(download_piece.piece_number(), piece_number);
156155
}
157156

158157
#[test]
159158
fn test_invalid_conversion() {
160-
// Test missing separator
159+
// Test missing separator.
161160
let invalid_bytes = Bytes::from("invalid_input_without_separator");
162161
let result = DownloadPiece::try_from(invalid_bytes);
163162
assert!(result.is_err());
164163
assert!(matches!(result.unwrap_err(), Error::InvalidPacket(_)));
165164

166-
// Test missing piece number
165+
// Test missing piece number.
167166
let invalid_bytes = Bytes::from("task_id-");
168167
let result = DownloadPiece::try_from(invalid_bytes);
169168
assert!(result.is_err());
170169
assert!(matches!(result.unwrap_err(), Error::ParseIntError(_)));
171170

172-
// Test invalid piece number
171+
// Test invalid piece number.
173172
let invalid_bytes = Bytes::from("task_id-invalid");
174173
let result = DownloadPiece::try_from(invalid_bytes);
175174
assert!(result.is_err());

src/tlv/error.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ impl Error {
118118
}
119119
}
120120

121+
/// Implement From<Error> for Bytes.
121122
impl From<Error> for Bytes {
122-
// Converts a Error request to a byte slice.
123+
/// from converts the error request to a byte slice.
123124
fn from(err: Error) -> Self {
124125
let mut bytes = BytesMut::with_capacity(err.len());
125126
bytes.put_u8(err.code.into());
@@ -129,9 +130,11 @@ impl From<Error> for Bytes {
129130
}
130131
}
131132

133+
/// Implement TryFrom<Bytes> for Error.
132134
impl TryFrom<Bytes> for Error {
133135
type Error = VortexError;
134136

137+
/// try_from decodes the error request from the byte slice.
135138
fn try_from(bytes: Bytes) -> VortexResult<Self> {
136139
let mut parts = bytes.splitn(2, |&b| b == SEPARATOR);
137140

@@ -194,23 +197,23 @@ mod tests {
194197
let error = Error::new(code, message.clone());
195198

196199
let bytes: Bytes = error.into();
197-
let error_decoded = Error::try_from(bytes).unwrap();
200+
let error = Error::try_from(bytes).unwrap();
198201

199-
assert_eq!(error_decoded.code(), code);
200-
assert_eq!(error_decoded.message(), message);
202+
assert_eq!(error.code(), code);
203+
assert_eq!(error.message(), message);
201204
}
202205

203206
#[test]
204207
fn test_from_bytes_invalid_input() {
205-
// Test missing separator
208+
// Test missing separator.
206209
let invalid_bytes = Bytes::from("invalid_input_without_separator");
207210
assert!(Error::try_from(invalid_bytes).is_err());
208211

209-
// Test missing error message
212+
// Test missing error message.
210213
let invalid_bytes = Bytes::from(format!("{}:", 1));
211214
assert!(Error::try_from(invalid_bytes).is_err());
212215

213-
// Test invalid error code format
216+
// Test invalid error code format.
214217
let invalid_bytes = Bytes::from(format!("{}:{}", 256, "Invalid code"));
215218
assert!(Error::try_from(invalid_bytes).is_err());
216219
}

src/tlv/piece_content.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@
1515
*/
1616

1717
use crate::error::{Error, Result};
18+
use crate::MAX_VALUE_SIZE;
1819
use bytes::Bytes;
1920
use std::convert::TryFrom;
2021

21-
/// MAX_PIECE_SIZE is the maximum size of a piece content (4 GiB).
22-
const MAX_PIECE_SIZE: usize = crate::MAX_VALUE_SIZE;
23-
2422
/// PieceContent represents the content of a piece.
2523
#[derive(Debug, Clone)]
2624
pub struct PieceContent(Bytes);
@@ -30,11 +28,11 @@ impl PieceContent {
3028
/// new creates a new piece content.
3129
pub fn new(content: Bytes) -> Result<Self> {
3230
// Check content length
33-
if content.len() > MAX_PIECE_SIZE {
31+
if content.len() > MAX_VALUE_SIZE {
3432
return Err(Error::InvalidLength(format!(
3533
"content length {} exceeds maximum size {}",
3634
content.len(),
37-
MAX_PIECE_SIZE
35+
MAX_VALUE_SIZE
3836
)));
3937
}
4038

@@ -56,13 +54,15 @@ impl PieceContent {
5654
impl TryFrom<Bytes> for PieceContent {
5755
type Error = Error;
5856

57+
/// try_from converts Bytes to PieceContent.
5958
fn try_from(bytes: Bytes) -> Result<Self> {
6059
Self::new(bytes)
6160
}
6261
}
6362

6463
/// Implement From<PieceContent> for Bytes.
6564
impl From<PieceContent> for Bytes {
65+
/// from converts PieceContent to Bytes.
6666
fn from(piece: PieceContent) -> Self {
6767
piece.0
6868
}
@@ -76,6 +76,7 @@ mod tests {
7676
fn test_new() {
7777
let content = vec![1, 2, 3, 4];
7878
let result = PieceContent::new(content.into());
79+
7980
assert!(result.is_ok());
8081
assert_eq!(result.unwrap().len(), 4);
8182
}
@@ -84,6 +85,7 @@ mod tests {
8485
fn test_is_empty() {
8586
let content = Bytes::new();
8687
let result = PieceContent::new(content);
88+
8789
assert!(result.is_ok());
8890
assert!(result.unwrap().is_empty());
8991
}
@@ -93,21 +95,16 @@ mod tests {
9395
let content = vec![1, 2, 3, 4];
9496
let bytes = Bytes::from(content.clone());
9597

96-
// Test TryFrom<Bytes>
9798
let piece_content = PieceContent::try_from(bytes.clone()).unwrap();
98-
99-
// Test From<PieceContent> for Bytes
10099
let bytes_back: Bytes = piece_content.clone().into();
101100
assert_eq!(bytes_back, content);
102101
}
103102

104103
#[test]
105104
fn test_invalid_conversion() {
106-
// Create bytes larger than MAX_PIECE_SIZE
107-
let large_content = vec![0; MAX_PIECE_SIZE + 1];
105+
let large_content = vec![0; MAX_VALUE_SIZE + 1];
108106
let bytes = Bytes::from(large_content);
109107

110-
// Test conversion fails
111108
let result = PieceContent::try_from(bytes);
112109
assert!(result.is_err());
113110
match result {

0 commit comments

Comments
 (0)