1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-01-04 15:41:57 +02:00

Added tests and implementation for I32(float) for Exercise: Protobuf Parsing (#2302)

Update for Exercise: Protobuf Parsing

* Include tests in the solution
* Remove implementatinon of wire type I32, but leave it as a "more-to-explore" extension
This commit is contained in:
Ivan Sakharovskii 2024-08-28 20:22:59 +03:00 committed by GitHub
parent 7af9690e3e
commit 6c0204fd50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 25 deletions

View File

@ -56,7 +56,9 @@ What remains for you is to implement the `parse_field` function and the
{{#include exercise.rs:parse_message }}
{{#include exercise.rs:message_types}}
{{#include exercise.rs:message_phone_number_type}}
{{#include exercise.rs:message_person_type}}
// TODO: Implement ProtoMessage for Person and PhoneNumber.

View File

@ -18,13 +18,15 @@
enum WireType {
/// The Varint WireType indicates the value is a single VARINT.
Varint,
/// The I64 WireType indicates that the value is precisely 8 bytes in
/// little-endian order containing a 64-bit signed integer or double type.
//I64, -- not needed for this exercise
/// The Len WireType indicates that the value is a length represented as a
/// VARINT followed by exactly that number of bytes.
Len,
/// The I32 WireType indicates that the value is precisely 4 bytes in
/// little-endian order containing a 32-bit signed integer.
I32,
// The I32 WireType indicates that the value is precisely 4 bytes in
// little-endian order containing a 32-bit signed integer or float type.
//I32, -- not needed for this exercise
}
#[derive(Debug)]
@ -33,7 +35,7 @@ enum FieldValue<'a> {
Varint(u64),
//I64(i64), -- not needed for this exercise
Len(&'a [u8]),
I32(i32),
//I32(i32), -- not needed for this exercise
}
#[derive(Debug)]
@ -53,7 +55,7 @@ impl From<u64> for WireType {
0 => WireType::Varint,
//1 => WireType::I64, -- not needed for this exercise
2 => WireType::Len,
5 => WireType::I32,
//5 => WireType::I32, -- not needed for this exercise
_ => panic!("Invalid wire type: {value}"),
}
}
@ -80,14 +82,6 @@ impl<'a> FieldValue<'a> {
};
*value
}
#[allow(dead_code)]
fn as_i32(&self) -> i32 {
let FieldValue::I32(value) = self else {
panic!("Expected `i32` to be an `I32` field");
};
*value
}
}
/// Parse a VARINT, returning the parsed value and the remaining bytes.
@ -139,15 +133,6 @@ fn parse_field(data: &[u8]) -> (Field, &[u8]) {
let (value, remainder) = remainder.split_at(len);
(FieldValue::Len(value), remainder)
}
WireType::I32 => {
if remainder.len() < 4 {
panic!("Unexpected EOF");
}
let (value, remainder) = remainder.split_at(4);
// Unwrap error because `value` is definitely 4 bytes long.
let value = i32::from_le_bytes(value.try_into().unwrap());
(FieldValue::I32(value), remainder)
}
};
(Field { field_num, value: fieldvalue }, remainder)
}
@ -168,20 +153,24 @@ fn parse_message<'a, T: ProtoMessage<'a>>(mut data: &'a [u8]) -> T {
}
// ANCHOR_END: parse_message
// ANCHOR: message_types
#[derive(PartialEq)]
// ANCHOR: message_message_phone_number_type
#[derive(Debug, Default)]
struct PhoneNumber<'a> {
number: &'a str,
type_: &'a str,
}
// ANCHOR_END: message_phone_number_type
#[derive(PartialEq)]
// ANCHOR: message_person_type
#[derive(Debug, Default)]
struct Person<'a> {
name: &'a str,
id: u64,
phone: Vec<PhoneNumber<'a>>,
}
// ANCHOR_END: message_types
// ANCHOR_END: message_person_type
impl<'a> ProtoMessage<'a> for Person<'a> {
fn add_field(&mut self, field: Field<'a>) {
@ -217,3 +206,50 @@ fn main() {
println!("{:#?}", person);
}
// ANCHOR_END: main
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_id() {
let person_id: Person = parse_message(&[0x10, 0x2a]);
assert_eq!(person_id, Person { name: "", id: 42, phone: vec![] });
}
#[test]
fn test_name() {
let person_name: Person = parse_message(&[
0x0a, 0x0e, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6c, 0x20,
0x6e, 0x61, 0x6d, 0x65,
]);
assert_eq!(
person_name,
Person { name: "beautiful name", id: 0, phone: vec![] }
);
}
#[test]
fn test_just_person() {
let person_name_id: Person =
parse_message(&[0x0a, 0x04, 0x45, 0x76, 0x61, 0x6e, 0x10, 0x16]);
assert_eq!(person_name_id, Person { name: "Evan", id: 22, phone: vec![] });
}
#[test]
fn test_phone() {
let phone: Person = parse_message(&[
0x0a, 0x00, 0x10, 0x00, 0x1a, 0x16, 0x0a, 0x0e, 0x2b, 0x31, 0x32, 0x33,
0x34, 0x2d, 0x37, 0x37, 0x37, 0x2d, 0x39, 0x30, 0x39, 0x30, 0x12, 0x04,
0x68, 0x6f, 0x6d, 0x65,
]);
assert_eq!(
phone,
Person {
name: "",
id: 0,
phone: vec![PhoneNumber { number: "+1234-777-9090", type_: "home" },],
}
);
}
}