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:
parent
7af9690e3e
commit
6c0204fd50
@ -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.
|
||||
|
||||
|
@ -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" },],
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user