Chapter 2 Hints

Getting bytes from a string

You can turn a &str into a Vec<u8> using str::bytes.

let bytes: Vec<u8> = your_str.bytes().collect();

Getting a string from bytes

You can turn a Vec<u8> into a String using String::from_utf8.

Working with iterators

You can chain iterators together using Iterator::chain.

You might run into trouble getting the types of your iterators to match. You can use Iterator::copied or Iterator::cloned to ensure that your iterator is working with values rather than references.


#![allow(unused_variables)]
fn main() {
let result = first_collection
    .iter()
    .cloned()
    .chain(second_collection.iter().cloned())
    .chain(third_collection.iter().cloned())
    .collect();
}

Reading bytes

You can turn a [u8; 4] into a u32 with u32::from_be_bytes. The be stands for big endian.

You can read a fixed number of bytes from a reader using Read::read_exact. Chunks have several different 4-byte sequences.


#![allow(unused_variables)]
fn main() {
let mut reader = BufReader::new(bytes);
let mut buffer: [u8; 4] = [0, 0, 0, 0];

reader.read_exact(&mut buffer)?;
let data_length = u32::from_be_bytes(buffer);
}

Stubs


#![allow(unused_variables)]
fn main() {
use std::convert::TryFrom;
use std::fmt;
use std::io::{BufReader, Read};

use crate::{Error, Result};
use crate::png::ChunkType;

/// A validated PNG chunk. See the PNG Spec for more details
/// http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html
#[derive(Debug, Clone)]
pub struct Chunk {
    // Write me!
}

impl Chunk {
    /// The length of the data portion of this chunk.
    pub fn length(&self) -> u32 {
        todo!()
    }

    /// The `ChunkType` of this chunk
    pub fn chunk_type(&self) -> &ChunkType {
        todo!()
    }

    /// The raw data contained in this chunk in bytes
    pub fn data(&self) -> &[u8] {
        todo!()
    }

    /// The CRC of this chunk
    pub fn crc(&self) -> u32 {
        todo!()
    }

    /// Returns the data stored in this chunk as a `String`. This function will return an error
    /// if the stored data is not valid UTF-8.
    pub fn data_as_string(&self) -> Result<String> {
        todo!()
    }

    /// Returns this chunk as a byte sequences described by the PNG spec.
    /// The following data is included in this byte sequence in order:
    /// 1. Length of the data *(4 bytes)*
    /// 2. Chunk type *(4 bytes)*
    /// 3. The data itself *(`length` bytes)*
    /// 4. The CRC of the chunk type and data *(4 bytes)*
    pub fn as_bytes(&self) -> Vec<u8> {
        todo!()
    }
}

impl TryFrom<&[u8]> for Chunk {
    type Error = Error;

    fn try_from(bytes: &[u8]) -> Result<Self> {
        todo!()
    }
}

impl fmt::Display for Chunk {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Chunk {{",)?;
        writeln!(f, "  Length: {}", self.length())?;
        writeln!(f, "  Type: {}", self.chunk_type())?;
        writeln!(f, "  Data: {} bytes", self.data().len())?;
        writeln!(f, "  Crc: {}", self.crc())?;
        writeln!(f, "}}",)?;
        Ok(())
    }
}
}