You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-26 10:41:01 +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:
committed by
GitHub
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: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.
|
// TODO: Implement ProtoMessage for Person and PhoneNumber.
|
||||||
|
|
||||||
|
@ -18,13 +18,15 @@
|
|||||||
enum WireType {
|
enum WireType {
|
||||||
/// The Varint WireType indicates the value is a single VARINT.
|
/// The Varint WireType indicates the value is a single VARINT.
|
||||||
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
|
//I64, -- not needed for this exercise
|
||||||
/// The Len WireType indicates that the value is a length represented as a
|
/// The Len WireType indicates that the value is a length represented as a
|
||||||
/// VARINT followed by exactly that number of bytes.
|
/// VARINT followed by exactly that number of bytes.
|
||||||
Len,
|
Len,
|
||||||
/// The I32 WireType indicates that the value is precisely 4 bytes in
|
// The I32 WireType indicates that the value is precisely 4 bytes in
|
||||||
/// little-endian order containing a 32-bit signed integer.
|
// little-endian order containing a 32-bit signed integer or float type.
|
||||||
I32,
|
//I32, -- not needed for this exercise
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -33,7 +35,7 @@ enum FieldValue<'a> {
|
|||||||
Varint(u64),
|
Varint(u64),
|
||||||
//I64(i64), -- not needed for this exercise
|
//I64(i64), -- not needed for this exercise
|
||||||
Len(&'a [u8]),
|
Len(&'a [u8]),
|
||||||
I32(i32),
|
//I32(i32), -- not needed for this exercise
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -53,7 +55,7 @@ impl From<u64> for WireType {
|
|||||||
0 => WireType::Varint,
|
0 => WireType::Varint,
|
||||||
//1 => WireType::I64, -- not needed for this exercise
|
//1 => WireType::I64, -- not needed for this exercise
|
||||||
2 => WireType::Len,
|
2 => WireType::Len,
|
||||||
5 => WireType::I32,
|
//5 => WireType::I32, -- not needed for this exercise
|
||||||
_ => panic!("Invalid wire type: {value}"),
|
_ => panic!("Invalid wire type: {value}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,14 +82,6 @@ impl<'a> FieldValue<'a> {
|
|||||||
};
|
};
|
||||||
*value
|
*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.
|
/// 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);
|
let (value, remainder) = remainder.split_at(len);
|
||||||
(FieldValue::Len(value), remainder)
|
(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)
|
(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_END: parse_message
|
||||||
|
|
||||||
// ANCHOR: message_types
|
#[derive(PartialEq)]
|
||||||
|
// ANCHOR: message_message_phone_number_type
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct PhoneNumber<'a> {
|
struct PhoneNumber<'a> {
|
||||||
number: &'a str,
|
number: &'a str,
|
||||||
type_: &'a str,
|
type_: &'a str,
|
||||||
}
|
}
|
||||||
|
// ANCHOR_END: message_phone_number_type
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
// ANCHOR: message_person_type
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct Person<'a> {
|
struct Person<'a> {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
id: u64,
|
id: u64,
|
||||||
phone: Vec<PhoneNumber<'a>>,
|
phone: Vec<PhoneNumber<'a>>,
|
||||||
}
|
}
|
||||||
// ANCHOR_END: message_types
|
// ANCHOR_END: message_person_type
|
||||||
|
|
||||||
impl<'a> ProtoMessage<'a> for Person<'a> {
|
impl<'a> ProtoMessage<'a> for Person<'a> {
|
||||||
fn add_field(&mut self, field: Field<'a>) {
|
fn add_field(&mut self, field: Field<'a>) {
|
||||||
@ -217,3 +206,50 @@ fn main() {
|
|||||||
println!("{:#?}", person);
|
println!("{:#?}", person);
|
||||||
}
|
}
|
||||||
// ANCHOR_END: main
|
// 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" },],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user