<commit_before>pub mod protobufs;

use address::Address;
use mio;
use network;
use std::sync::mpsc;
use std::thread;
use std::io;
use protobuf::{self, Message};

#[derive(Debug)]
struct CommMessage {
    recipient: Address,
    sender: Address,
    text: String
}

impl CommMessage {
    fn new(recipient: Address, sender: Address, text: String) -> CommMessage {
        CommMessage {
            recipient: recipient,
            sender: sender,
            text: text
        }
    }

    fn decode(data: Vec<u8>) -> CommMessage {
        use std::io::Cursor;
        let mut data = Cursor::new(data);
        let message = protobuf::parse_from_reader::<protobufs::CommMessage>(&mut data).unwrap();
        CommMessage::new(
            Address::from_str(message.get_recipient()),
            Address::from_str(message.get_sender()),
            message.get_text().to_string())
    }

    fn encode(self) -> Vec<u8> {
        let mut message = protobufs::CommMessage::new();
        message.set_recipient(self.recipient.to_str());
        message.set_sender(self.sender.to_str());
        message.set_text(self.text);
        message.write_to_bytes().unwrap()
    }
}

#[derive(Debug)]
pub enum Task {
    HandleNetworkEvent(network::Event)
}

pub struct Client {
    address: Address
}

impl Client {
    pub fn new(address: Address) -> Client {
        Client {
            address: address
        }
    }

    pub fn run(mut self, mut network: network::Network) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();
        let sender = self.address;

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel.send(Task::HandleNetworkEvent(event)).unwrap();
            }
        });

        thread::spawn(move || event_loop.run(&mut self).unwrap());

        let task_sender = network.run();

        loop {
            let mut line = String::new();
            io::stdin().read_line(&mut line).unwrap();
            let parts: Vec<&str> = line.splitn(2, ' ').collect();
            let recipient = Address::from_str(parts[0]);
            let message_text = parts[1].to_string();

            let message = CommMessage::new(recipient, sender, message_text);

            task_sender.send(network::OneshotTask::SendPacket(
                    recipient, message.encode())).unwrap();
        }
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(data) => {
                let message = CommMessage::decode(data);
                if message.recipient == self.address {
                    println!("{}: {}", message.sender, message.text);
                } else {
                    println!("should forward: {:?}", message);
                }
            }
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ();
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop)
        }
    }
}
<commit_msg>Trim newline off messages<commit_after>pub mod protobufs;

use address::Address;
use mio;
use network;
use std::sync::mpsc;
use std::thread;
use std::io;
use protobuf::{self, Message};

#[derive(Debug)]
struct CommMessage {
    recipient: Address,
    sender: Address,
    text: String
}

impl CommMessage {
    fn new(recipient: Address, sender: Address, text: String) -> CommMessage {
        CommMessage {
            recipient: recipient,
            sender: sender,
            text: text
        }
    }

    fn decode(data: Vec<u8>) -> CommMessage {
        use std::io::Cursor;
        let mut data = Cursor::new(data);
        let message = protobuf::parse_from_reader::<protobufs::CommMessage>(&mut data).unwrap();
        CommMessage::new(
            Address::from_str(message.get_recipient()),
            Address::from_str(message.get_sender()),
            message.get_text().to_string())
    }

    fn encode(self) -> Vec<u8> {
        let mut message = protobufs::CommMessage::new();
        message.set_recipient(self.recipient.to_str());
        message.set_sender(self.sender.to_str());
        message.set_text(self.text);
        message.write_to_bytes().unwrap()
    }
}

#[derive(Debug)]
pub enum Task {
    HandleNetworkEvent(network::Event)
}

pub struct Client {
    address: Address
}

impl Client {
    pub fn new(address: Address) -> Client {
        Client {
            address: address
        }
    }

    pub fn run(mut self, mut network: network::Network) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();
        let sender = self.address;

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel.send(Task::HandleNetworkEvent(event)).unwrap();
            }
        });

        thread::spawn(move || event_loop.run(&mut self).unwrap());

        let task_sender = network.run();

        loop {
            let mut line = String::new();
            io::stdin().read_line(&mut line).unwrap();
            let parts: Vec<&str> = line.splitn(2, ' ').collect();
            let recipient = Address::from_str(parts[0]);
            let message_text = parts[1].trim().to_string();

            let message = CommMessage::new(recipient, sender, message_text);

            task_sender.send(network::OneshotTask::SendPacket(
                    recipient, message.encode())).unwrap();
        }
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(data) => {
                let message = CommMessage::decode(data);
                if message.recipient == self.address {
                    println!("{}: {}", message.sender, message.text);
                } else {
                    println!("should forward: {:?}", message);
                }
            }
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ();
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop)
        }
    }
}
<|endoftext|>


<commit_before>//!  Decoding of DDS images
//!
//!  DDS (DirectDraw Surface) is a container format for storing DXT (S3TC) compressed images.
//!
//!  # Related Links
//!  * <https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide> - Description of the DDS format.

use std::io::Read;
use std::{error, fmt};

use byteorder::{LittleEndian, ReadBytesExt};

#[allow(deprecated)]
use crate::codecs::dxt::{DxtDecoder, DxtReader, DxtVariant};
use crate::color::ColorType;
use crate::error::{
    DecodingError, ImageError, ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{ImageDecoder, ImageFormat};

/// Errors that can occur during decoding and parsing a DDS image
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum DecoderError {
    /// Wrong DDS channel width
    PixelFormatSizeInvalid(u32),
    /// Wrong DDS header size
    HeaderSizeInvalid(u32),
    /// Wrong DDS header flags
    HeaderFlagsInvalid(u32),

    /// Invalid DXGI format in DX10 header
    DxgiFormatInvalid(u32),
    /// Invalid flags in DX10 header
    Dx10FlagsInvalid(u32),
    /// Invalid array size in DX10 header
    Dx10ArraySizeInvalid(u32),

    /// DDS "DDS " signature invalid or missing
    DdsSignatureInvalid,
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DecoderError::PixelFormatSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS PixelFormat size: {}", s))
            }
            DecoderError::HeaderSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS header size: {}", s))
            }
            DecoderError::HeaderFlagsInvalid(fs) => {
                f.write_fmt(format_args!("Invalid DDS header flags: {:#010X}", fs))
            }
            DecoderError::DdsSignatureInvalid => f.write_str("DDS signature not found"),
        }
    }
}

impl From<DecoderError> for ImageError {
    fn from(e: DecoderError) -> ImageError {
        ImageError::Decoding(DecodingError::new(ImageFormat::Dds.into(), e))
    }
}

impl error::Error for DecoderError {}

/// Header used by DDS image files
#[derive(Debug)]
struct Header {
    flags: u32,
    height: u32,
    width: u32,
    pitch_or_linear_size: u32,
    depth: u32,
    mipmap_count: u32,
    pixel_format: PixelFormat,
    caps: u32,
    caps2: u32,
}

/// Extended DX10 header used by some DDS image files
#[derive(Debug)]
struct DX10Header {
    dxgi_format: u32,
    resource_dimension: u32,
    misc_flag: u32,
    array_size: u32,
    misc_flags_2: u32,
}

/// DDS pixel format
#[derive(Debug)]
struct PixelFormat {
    flags: u32,
    fourcc: [u8; 4],
    rgb_bit_count: u32,
    r_bit_mask: u32,
    g_bit_mask: u32,
    b_bit_mask: u32,
    a_bit_mask: u32,
}

impl PixelFormat {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 32 {
            return Err(DecoderError::PixelFormatSizeInvalid(size).into());
        }

        Ok(Self {
            flags: r.read_u32::<LittleEndian>()?,
            fourcc: {
                let mut v = [0; 4];
                r.read_exact(&mut v)?;
                v
            },
            rgb_bit_count: r.read_u32::<LittleEndian>()?,
            r_bit_mask: r.read_u32::<LittleEndian>()?,
            g_bit_mask: r.read_u32::<LittleEndian>()?,
            b_bit_mask: r.read_u32::<LittleEndian>()?,
            a_bit_mask: r.read_u32::<LittleEndian>()?,
        })
    }
}

impl Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 124 {
            return Err(DecoderError::HeaderSizeInvalid(size).into());
        }

        const REQUIRED_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x1000;
        const VALID_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x8 | 0x1000 | 0x20000 | 0x80000 | 0x800000;
        let flags = r.read_u32::<LittleEndian>()?;
        if flags & (REQUIRED_FLAGS | !VALID_FLAGS) != REQUIRED_FLAGS {
            return Err(DecoderError::HeaderFlagsInvalid(flags).into());
        }

        let height = r.read_u32::<LittleEndian>()?;
        let width = r.read_u32::<LittleEndian>()?;
        let pitch_or_linear_size = r.read_u32::<LittleEndian>()?;
        let depth = r.read_u32::<LittleEndian>()?;
        let mipmap_count = r.read_u32::<LittleEndian>()?;
        // Skip `dwReserved1`
        {
            let mut skipped = [0; 4 * 11];
            r.read_exact(&mut skipped)?;
        }
        let pixel_format = PixelFormat::from_reader(r)?;
        let caps = r.read_u32::<LittleEndian>()?;
        let caps2 = r.read_u32::<LittleEndian>()?;
        // Skip `dwCaps3`, `dwCaps4`, `dwReserved2` (unused)
        {
            let mut skipped = [0; 4 + 4 + 4];
            r.read_exact(&mut skipped)?;
        }

        Ok(Self {
            flags,
            height,
            width,
            pitch_or_linear_size,
            depth,
            mipmap_count,
            pixel_format,
            caps,
            caps2,
        })
    }
}

impl DX10Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let dxgi_format = r.read_u32::<LittleEndian>()?;
        let resource_dimension = r.read_u32::<LittleEndian>()?;
        let misc_flag = r.read_u32::<LittleEndian>()?;
        let array_size = r.read_u32::<LittleEndian>()?;
        let misc_flags_2 = r.read_u32::<LittleEndian>()?;

        let dx10_header = Self {
            dxgi_format,
            resource_dimension,
            misc_flag,
            array_size,
            misc_flags_2,
        };
        dx10_header.validate()?;

        Ok(dx10_header)
    }

    fn validate(&self) -> Result<(), ImageError> {
        // Note: see https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dds-header-dxt10 for info on valid values
        if dxgi_format < 0 || dxgi_format > 132 {
            // Invalid format
            return Err(DecoderError::DxgiFormatInvalid(dxgi_format).into());
        }

        if misc_flag != 0x4 && misc_flag != 0x4 {
            // Invalid flag
            // Only no (0x0) and DDS_RESOURCE_MISC_TEXTURECUBE (0x4) flags are allowed
            return Err(DecoderError::Dx10FlagsInvalid(misc_flag).into());
        }

        if resource_dimension == 4 && array_size != 1 {
            // Invalid array size
            // 3D textures (resource dimension == 4) must have an array size of 1
            return Err(DecoderError::Dx10ArraySizeInvalid(array_size).into());
        }

        if misc_flags_2 < 0x0 || misc_flags_2 > 0x4 {
            // Invalid alpha flags
            return Err(DecoderError::Dx10FlagsInvalid(misc_flags_2).into());
        }

        Ok(())
    }
}

/// The representation of a DDS decoder
pub struct DdsDecoder<R: Read> {
    #[allow(deprecated)]
    inner: DxtDecoder<R>,
}

impl<R: Read> DdsDecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(mut r: R) -> ImageResult<Self> {
        let mut magic = [0; 4];
        r.read_exact(&mut magic)?;
        if magic != b"DDS "[..] {
            return Err(DecoderError::DdsSignatureInvalid.into());
        }

        let header = Header::from_reader(&mut r)?;

        if header.pixel_format.flags & 0x4 != 0 {
            #[allow(deprecated)]
            let variant = match &header.pixel_format.fourcc {
                b"DXT1" => DxtVariant::DXT1,
                b"DXT3" => DxtVariant::DXT3,
                b"DXT5" => DxtVariant::DXT5,
                b"DX10" => {
                    let dx10_header = DX10Header::from_reader(&mut r)?;
                    match dx10_header.dxgi_format {
                        70 | 71 | 72 => DxtVariant::DXT1,
                        73 | 74 | 75 => DxtVariant::DXT3,
                        76 | 77 | 78 => DxtVariant::DXT5,
                        _ => {
                            return Err(ImageError::Unsupported(
                                UnsupportedError::from_format_and_kind(
                                    ImageFormat::Dds.into(),
                                    UnsupportedErrorKind::GenericFeature(format!(
                                        "DDS DXGI Format {}",
                                        dx10_header.dxgi_format
                                    )),
                                ),
                            ))
                        }
                    }
                }
                fourcc => {
                    return Err(ImageError::Unsupported(
                        UnsupportedError::from_format_and_kind(
                            ImageFormat::Dds.into(),
                            UnsupportedErrorKind::GenericFeature(format!(
                                "DDS FourCC {:?}",
                                fourcc
                            )),
                        ),
                    ))
                }
            };

            #[allow(deprecated)]
            let bytes_per_pixel = variant.color_type().bytes_per_pixel();

            if crate::utils::check_dimension_overflow(header.width, header.height, bytes_per_pixel)
            {
                return Err(ImageError::Unsupported(
                    UnsupportedError::from_format_and_kind(
                        ImageFormat::Dds.into(),
                        UnsupportedErrorKind::GenericFeature(format!(
                            "Image dimensions ({}x{}) are too large",
                            header.width, header.height
                        )),
                    ),
                ));
            }

            #[allow(deprecated)]
            let inner = DxtDecoder::new(r, header.width, header.height, variant)?;
            Ok(Self { inner })
        } else {
            // For now, supports only DXT variants
            Err(ImageError::Unsupported(
                UnsupportedError::from_format_and_kind(
                    ImageFormat::Dds.into(),
                    UnsupportedErrorKind::Format(ImageFormatHint::Name("DDS".to_string())),
                ),
            ))
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for DdsDecoder<R> {
    #[allow(deprecated)]
    type Reader = DxtReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.inner.dimensions()
    }

    fn color_type(&self) -> ColorType {
        self.inner.color_type()
    }

    fn scanline_bytes(&self) -> u64 {
        self.inner.scanline_bytes()
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        self.inner.into_reader()
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        self.inner.read_image(buf)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn dimension_overflow() {
        // A DXT1 header set to 0xFFFF_FFFC width and height (the highest u32%4 == 0)
        let header = vec![
            0x44, 0x44, 0x53, 0x20, 0x7C, 0x0, 0x0, 0x0, 0x7, 0x10, 0x8, 0x0, 0xFC, 0xFF, 0xFF,
            0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x0, 0xC0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
            0x0, 0x49, 0x4D, 0x41, 0x47, 0x45, 0x4D, 0x41, 0x47, 0x49, 0x43, 0x4B, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
            0x4, 0x0, 0x0, 0x0, 0x44, 0x58, 0x54, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        ];

        assert!(DdsDecoder::new(&header[..]).is_err());
    }
}
<commit_msg>Add comments explaining the DXGI constants<commit_after>//!  Decoding of DDS images
//!
//!  DDS (DirectDraw Surface) is a container format for storing DXT (S3TC) compressed images.
//!
//!  # Related Links
//!  * <https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide> - Description of the DDS format.

use std::io::Read;
use std::{error, fmt};

use byteorder::{LittleEndian, ReadBytesExt};

#[allow(deprecated)]
use crate::codecs::dxt::{DxtDecoder, DxtReader, DxtVariant};
use crate::color::ColorType;
use crate::error::{
    DecodingError, ImageError, ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{ImageDecoder, ImageFormat};

/// Errors that can occur during decoding and parsing a DDS image
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum DecoderError {
    /// Wrong DDS channel width
    PixelFormatSizeInvalid(u32),
    /// Wrong DDS header size
    HeaderSizeInvalid(u32),
    /// Wrong DDS header flags
    HeaderFlagsInvalid(u32),

    /// Invalid DXGI format in DX10 header
    DxgiFormatInvalid(u32),
    /// Invalid flags in DX10 header
    Dx10FlagsInvalid(u32),
    /// Invalid array size in DX10 header
    Dx10ArraySizeInvalid(u32),

    /// DDS "DDS " signature invalid or missing
    DdsSignatureInvalid,
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DecoderError::PixelFormatSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS PixelFormat size: {}", s))
            }
            DecoderError::HeaderSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS header size: {}", s))
            }
            DecoderError::HeaderFlagsInvalid(fs) => {
                f.write_fmt(format_args!("Invalid DDS header flags: {:#010X}", fs))
            }
            DecoderError::DdsSignatureInvalid => f.write_str("DDS signature not found"),
        }
    }
}

impl From<DecoderError> for ImageError {
    fn from(e: DecoderError) -> ImageError {
        ImageError::Decoding(DecodingError::new(ImageFormat::Dds.into(), e))
    }
}

impl error::Error for DecoderError {}

/// Header used by DDS image files
#[derive(Debug)]
struct Header {
    flags: u32,
    height: u32,
    width: u32,
    pitch_or_linear_size: u32,
    depth: u32,
    mipmap_count: u32,
    pixel_format: PixelFormat,
    caps: u32,
    caps2: u32,
}

/// Extended DX10 header used by some DDS image files
#[derive(Debug)]
struct DX10Header {
    dxgi_format: u32,
    resource_dimension: u32,
    misc_flag: u32,
    array_size: u32,
    misc_flags_2: u32,
}

/// DDS pixel format
#[derive(Debug)]
struct PixelFormat {
    flags: u32,
    fourcc: [u8; 4],
    rgb_bit_count: u32,
    r_bit_mask: u32,
    g_bit_mask: u32,
    b_bit_mask: u32,
    a_bit_mask: u32,
}

impl PixelFormat {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 32 {
            return Err(DecoderError::PixelFormatSizeInvalid(size).into());
        }

        Ok(Self {
            flags: r.read_u32::<LittleEndian>()?,
            fourcc: {
                let mut v = [0; 4];
                r.read_exact(&mut v)?;
                v
            },
            rgb_bit_count: r.read_u32::<LittleEndian>()?,
            r_bit_mask: r.read_u32::<LittleEndian>()?,
            g_bit_mask: r.read_u32::<LittleEndian>()?,
            b_bit_mask: r.read_u32::<LittleEndian>()?,
            a_bit_mask: r.read_u32::<LittleEndian>()?,
        })
    }
}

impl Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 124 {
            return Err(DecoderError::HeaderSizeInvalid(size).into());
        }

        const REQUIRED_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x1000;
        const VALID_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x8 | 0x1000 | 0x20000 | 0x80000 | 0x800000;
        let flags = r.read_u32::<LittleEndian>()?;
        if flags & (REQUIRED_FLAGS | !VALID_FLAGS) != REQUIRED_FLAGS {
            return Err(DecoderError::HeaderFlagsInvalid(flags).into());
        }

        let height = r.read_u32::<LittleEndian>()?;
        let width = r.read_u32::<LittleEndian>()?;
        let pitch_or_linear_size = r.read_u32::<LittleEndian>()?;
        let depth = r.read_u32::<LittleEndian>()?;
        let mipmap_count = r.read_u32::<LittleEndian>()?;
        // Skip `dwReserved1`
        {
            let mut skipped = [0; 4 * 11];
            r.read_exact(&mut skipped)?;
        }
        let pixel_format = PixelFormat::from_reader(r)?;
        let caps = r.read_u32::<LittleEndian>()?;
        let caps2 = r.read_u32::<LittleEndian>()?;
        // Skip `dwCaps3`, `dwCaps4`, `dwReserved2` (unused)
        {
            let mut skipped = [0; 4 + 4 + 4];
            r.read_exact(&mut skipped)?;
        }

        Ok(Self {
            flags,
            height,
            width,
            pitch_or_linear_size,
            depth,
            mipmap_count,
            pixel_format,
            caps,
            caps2,
        })
    }
}

impl DX10Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let dxgi_format = r.read_u32::<LittleEndian>()?;
        let resource_dimension = r.read_u32::<LittleEndian>()?;
        let misc_flag = r.read_u32::<LittleEndian>()?;
        let array_size = r.read_u32::<LittleEndian>()?;
        let misc_flags_2 = r.read_u32::<LittleEndian>()?;

        let dx10_header = Self {
            dxgi_format,
            resource_dimension,
            misc_flag,
            array_size,
            misc_flags_2,
        };
        dx10_header.validate()?;

        Ok(dx10_header)
    }

    fn validate(&self) -> Result<(), ImageError> {
        // Note: see https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dds-header-dxt10 for info on valid values
        if dxgi_format < 0 || dxgi_format > 132 {
            // Invalid format
            return Err(DecoderError::DxgiFormatInvalid(dxgi_format).into());
        }

        if misc_flag != 0x4 && misc_flag != 0x4 {
            // Invalid flag
            // Only no (0x0) and DDS_RESOURCE_MISC_TEXTURECUBE (0x4) flags are allowed
            return Err(DecoderError::Dx10FlagsInvalid(misc_flag).into());
        }

        if resource_dimension == 4 && array_size != 1 {
            // Invalid array size
            // 3D textures (resource dimension == 4) must have an array size of 1
            return Err(DecoderError::Dx10ArraySizeInvalid(array_size).into());
        }

        if misc_flags_2 < 0x0 || misc_flags_2 > 0x4 {
            // Invalid alpha flags
            return Err(DecoderError::Dx10FlagsInvalid(misc_flags_2).into());
        }

        Ok(())
    }
}

/// The representation of a DDS decoder
pub struct DdsDecoder<R: Read> {
    #[allow(deprecated)]
    inner: DxtDecoder<R>,
}

impl<R: Read> DdsDecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(mut r: R) -> ImageResult<Self> {
        let mut magic = [0; 4];
        r.read_exact(&mut magic)?;
        if magic != b"DDS "[..] {
            return Err(DecoderError::DdsSignatureInvalid.into());
        }

        let header = Header::from_reader(&mut r)?;

        if header.pixel_format.flags & 0x4 != 0 {
            #[allow(deprecated)]
            let variant = match &header.pixel_format.fourcc {
                b"DXT1" => DxtVariant::DXT1,
                b"DXT3" => DxtVariant::DXT3,
                b"DXT5" => DxtVariant::DXT5,
                b"DX10" => {
                    let dx10_header = DX10Header::from_reader(&mut r)?;
                    // Format equivalents were taken from https://docs.microsoft.com/en-us/windows/win32/direct3d11/texture-block-compression-in-direct3d-11
                    // The enum integer values were taken from https://docs.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
                    // DXT1 represents the different BC1 variants, DTX3 represents the different BC2 variants and DTX5 represents the different BC3 variants
                    match dx10_header.dxgi_format {
                        70 | 71 | 72 => DxtVariant::DXT1, // DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM or DXGI_FORMAT_BC1_UNORM_SRGB
                        73 | 74 | 75 => DxtVariant::DXT3, // DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM or DXGI_FORMAT_BC2_UNORM_SRGB
                        76 | 77 | 78 => DxtVariant::DXT5, // DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM or DXGI_FORMAT_BC3_UNORM_SRGB
                        _ => {
                            return Err(ImageError::Unsupported(
                                UnsupportedError::from_format_and_kind(
                                    ImageFormat::Dds.into(),
                                    UnsupportedErrorKind::GenericFeature(format!(
                                        "DDS DXGI Format {}",
                                        dx10_header.dxgi_format
                                    )),
                                ),
                            ))
                        }
                    }
                }
                fourcc => {
                    return Err(ImageError::Unsupported(
                        UnsupportedError::from_format_and_kind(
                            ImageFormat::Dds.into(),
                            UnsupportedErrorKind::GenericFeature(format!(
                                "DDS FourCC {:?}",
                                fourcc
                            )),
                        ),
                    ))
                }
            };

            #[allow(deprecated)]
            let bytes_per_pixel = variant.color_type().bytes_per_pixel();

            if crate::utils::check_dimension_overflow(header.width, header.height, bytes_per_pixel)
            {
                return Err(ImageError::Unsupported(
                    UnsupportedError::from_format_and_kind(
                        ImageFormat::Dds.into(),
                        UnsupportedErrorKind::GenericFeature(format!(
                            "Image dimensions ({}x{}) are too large",
                            header.width, header.height
                        )),
                    ),
                ));
            }

            #[allow(deprecated)]
            let inner = DxtDecoder::new(r, header.width, header.height, variant)?;
            Ok(Self { inner })
        } else {
            // For now, supports only DXT variants
            Err(ImageError::Unsupported(
                UnsupportedError::from_format_and_kind(
                    ImageFormat::Dds.into(),
                    UnsupportedErrorKind::Format(ImageFormatHint::Name("DDS".to_string())),
                ),
            ))
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for DdsDecoder<R> {
    #[allow(deprecated)]
    type Reader = DxtReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.inner.dimensions()
    }

    fn color_type(&self) -> ColorType {
        self.inner.color_type()
    }

    fn scanline_bytes(&self) -> u64 {
        self.inner.scanline_bytes()
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        self.inner.into_reader()
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        self.inner.read_image(buf)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn dimension_overflow() {
        // A DXT1 header set to 0xFFFF_FFFC width and height (the highest u32%4 == 0)
        let header = vec![
            0x44, 0x44, 0x53, 0x20, 0x7C, 0x0, 0x0, 0x0, 0x7, 0x10, 0x8, 0x0, 0xFC, 0xFF, 0xFF,
            0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x0, 0xC0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
            0x0, 0x49, 0x4D, 0x41, 0x47, 0x45, 0x4D, 0x41, 0x47, 0x49, 0x43, 0x4B, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
            0x4, 0x0, 0x0, 0x0, 0x44, 0x58, 0x54, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        ];

        assert!(DdsDecoder::new(&header[..]).is_err());
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, non_camel_case_types)]
#[macro_use]
extern crate derive_more;

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    Sum,
    IndexMut,
    AddAssign,
    MulAssign,
    Deref,
    DerefMut,
    IntoIterator,
    Constructor
)]
#[deref(forward)]
#[deref_mut(forward)]
#[into_iterator(owned, ref, ref_mut)]
struct Wrapped<T: Clone>(T);

#[derive(Deref, DerefMut)]
struct Wrapped2<T: Clone>(T);

#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)]
struct WrappedDouble<T: Clone, U: Clone>(T, U);

#[derive(From)]
#[from(forward)]
struct WrappedDouble2<T: Clone, U: Clone>(T, U);

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    Sum,
    IndexMut,
    AddAssign,
    MulAssign,
    Deref,
    DerefMut,
    IntoIterator,
    Constructor
)]
struct WrappedWithConst<T, const C: u32>(T);

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    IndexMut,
    AddAssign,
    MulAssign,
    Deref,
    DerefMut,
    IntoIterator,
    Constructor,
    Sum
)]
#[deref(forward)]
#[deref_mut(forward)]
#[into_iterator(owned, ref, ref_mut)]
struct Struct<T: Clone> {
    t: T,
}

#[derive(Deref, DerefMut)]
struct Struct2<T: Clone> {
    t: T,
}

#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)]
struct DoubleStruct<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From)]
#[from(forward)]
struct DoubleStruct2<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From, Not, Add)]
enum TupleEnum<T: Clone, U: Clone> {
    Tuple(T),
    DoubleTuple(T, U),
}

#[derive(From)]
#[from(forward)]
enum TupleEnum2<T: Clone, U: Clone, X: Clone> {
    DoubleTuple(T, U),
    TripleTuple(T, U, X),
}

#[derive(From, Not, Add)]
enum StructEnum<T: Clone, U: Clone> {
    Struct { t: T },
    DoubleStruct { t: T, u: U },
}

#[derive(From)]
#[from(forward)]
enum StructEnum2<T: Clone, U: Clone, X: Clone> {
    DoubleStruct { t: T, u: U },
    TripleStruct { t: T, u: U, x: X },
}
<commit_msg>Only run const generic tests on nightly<commit_after>#![allow(dead_code, non_camel_case_types)]
#[macro_use]
extern crate derive_more;

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    Sum,
    IndexMut,
    AddAssign,
    MulAssign,
    Deref,
    DerefMut,
    IntoIterator,
    Constructor
)]
#[deref(forward)]
#[deref_mut(forward)]
#[into_iterator(owned, ref, ref_mut)]
struct Wrapped<T: Clone>(T);

#[derive(Deref, DerefMut)]
struct Wrapped2<T: Clone>(T);

#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)]
struct WrappedDouble<T: Clone, U: Clone>(T, U);

#[derive(From)]
#[from(forward)]
struct WrappedDouble2<T: Clone, U: Clone>(T, U);

#[cfg(feature = "nightly")]
#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    Sum,
    IndexMut,
    AddAssign,
    MulAssign,
    Deref,
    DerefMut,
    IntoIterator,
    Constructor
)]
struct WrappedWithConst<T, const C: u32>(T);

#[derive(
    From,
    FromStr,
    Display,
    Index,
    Not,
    Add,
    Mul,
    IndexMut,
    AddAssign,
    MulAssign,
    Deref,
    DerefMut,
    IntoIterator,
    Constructor,
    Sum
)]
#[deref(forward)]
#[deref_mut(forward)]
#[into_iterator(owned, ref, ref_mut)]
struct Struct<T: Clone> {
    t: T,
}

#[derive(Deref, DerefMut)]
struct Struct2<T: Clone> {
    t: T,
}

#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)]
struct DoubleStruct<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From)]
#[from(forward)]
struct DoubleStruct2<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From, Not, Add)]
enum TupleEnum<T: Clone, U: Clone> {
    Tuple(T),
    DoubleTuple(T, U),
}

#[derive(From)]
#[from(forward)]
enum TupleEnum2<T: Clone, U: Clone, X: Clone> {
    DoubleTuple(T, U),
    TripleTuple(T, U, X),
}

#[derive(From, Not, Add)]
enum StructEnum<T: Clone, U: Clone> {
    Struct { t: T },
    DoubleStruct { t: T, u: U },
}

#[derive(From)]
#[from(forward)]
enum StructEnum2<T: Clone, U: Clone, X: Clone> {
    DoubleStruct { t: T, u: U },
    TripleStruct { t: T, u: U, x: X },
}
<|endoftext|>


<commit_before>extern crate direct2d;

use direct2d::Factory;
use direct2d::geometry::{Geometry, FillMode, FigureBegin, FigureEnd};
use direct2d::math::*;

const EPSILON: f32 = 0.0001;

#[test]
fn rectangle_area() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    let area = rectangle.compute_area(None).unwrap();
    assert!((area - 1.0).abs() <= EPSILON);
}

#[test]
fn rectangle_length() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    let area = rectangle.compute_length(None).unwrap();
    assert!((area - 4.0).abs() <= EPSILON);
}

#[test]
fn combined_area() {
    let factory = Factory::create().unwrap();

    let rect1 = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle1 = factory.create_rectangle_geometry(&rect1).unwrap();

    let rect2 = RectF::new(0.0, 1.0, 1.0, 2.0);
    let rectangle2 = factory.create_rectangle_geometry(&rect2).unwrap();

    let combined = factory.create_geometry_group(FillMode::Winding, &[&rectangle1, &rectangle2]).unwrap();

    let area = combined.compute_area(None).unwrap();
    assert!((area - 2.0).abs() <= EPSILON);
}

#[test]
fn transformed_area() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    for x in 1..5 {
        for y in 1..5 {
            for t in -10..10 {
                let x = x as f32;
                let y = y as f32;
                let t = t as f32;
                let real_area = x * y;

                let transform = Matrix3x2F::new([
                    [  x, 0.0], // Scale along the X axis by `x`
                    [0.0,   y], // Scale along the Y axis by `y`
                    [  t,  -t], // this value shouldn't affect area (translation component)
                ]);

                // Apply the transformation to get the area
                let area = rectangle.compute_area(Some(&transform)).unwrap();
                assert!((area - real_area).abs() <= EPSILON);

                // Create a permanently transformed geometry and test its base area
                let transformed = rectangle.transformed(&transform).unwrap();
                let area = transformed.compute_area(None).unwrap();
                assert!((area - real_area).abs() <= EPSILON);

                // Double-transform
                let area = transformed.compute_area(Some(&transform)).unwrap();
                assert!((area - real_area*real_area).abs() <= EPSILON);
            }
        }
    }
}

#[test]
fn path_geometry() {
    let factory = Factory::create().unwrap();

    let mut path = factory.create_path_geometry().unwrap();
    path.open().unwrap()
        .begin_figure(Point2F::new(0.0, 0.0), FigureBegin::Filled, FigureEnd::Closed)
            .add_line(Point2F::new(1.0, 0.0))
            .add_line(Point2F::new(1.0, 1.0))
            .add_line(Point2F::new(0.5, 1.5))
            .add_line(Point2F::new(0.0, 1.0))
            .end()
        .close();
}

<commit_msg>Test the path<commit_after>extern crate direct2d;

use direct2d::Factory;
use direct2d::geometry::{Geometry, FillMode, FigureBegin, FigureEnd};
use direct2d::math::*;

const EPSILON: f32 = 0.0001;

#[test]
fn rectangle_area() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    let area = rectangle.compute_area(None).unwrap();
    assert!((area - 1.0).abs() <= EPSILON);
}

#[test]
fn rectangle_length() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    let area = rectangle.compute_length(None).unwrap();
    assert!((area - 4.0).abs() <= EPSILON);
}

#[test]
fn combined_area() {
    let factory = Factory::create().unwrap();

    let rect1 = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle1 = factory.create_rectangle_geometry(&rect1).unwrap();

    let rect2 = RectF::new(0.0, 1.0, 1.0, 2.0);
    let rectangle2 = factory.create_rectangle_geometry(&rect2).unwrap();

    let combined = factory.create_geometry_group(FillMode::Winding, &[&rectangle1, &rectangle2]).unwrap();

    let area = combined.compute_area(None).unwrap();
    assert!((area - 2.0).abs() <= EPSILON);
}

#[test]
fn transformed_area() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    for x in 1..5 {
        for y in 1..5 {
            for t in -10..10 {
                let x = x as f32;
                let y = y as f32;
                let t = t as f32;
                let real_area = x * y;

                let transform = Matrix3x2F::new([
                    [  x, 0.0], // Scale along the X axis by `x`
                    [0.0,   y], // Scale along the Y axis by `y`
                    [  t,  -t], // this value shouldn't affect area (translation component)
                ]);

                // Apply the transformation to get the area
                let area = rectangle.compute_area(Some(&transform)).unwrap();
                assert!((area - real_area).abs() <= EPSILON);

                // Create a permanently transformed geometry and test its base area
                let transformed = rectangle.transformed(&transform).unwrap();
                let area = transformed.compute_area(None).unwrap();
                assert!((area - real_area).abs() <= EPSILON);

                // Double-transform
                let area = transformed.compute_area(Some(&transform)).unwrap();
                assert!((area - real_area*real_area).abs() <= EPSILON);
            }
        }
    }
}

#[test]
fn path_geometry() {
    let factory = Factory::create().unwrap();

    let mut path = factory.create_path_geometry().unwrap();
    path.open().unwrap()
        .begin_figure(Point2F::new(0.0, 0.0), FigureBegin::Filled, FigureEnd::Closed)
            .add_line(Point2F::new(1.0, 0.0))
            .add_line(Point2F::new(1.0, 1.0))
            .add_line(Point2F::new(0.5, 1.5))
            .add_line(Point2F::new(0.0, 1.0))
        .end()
    .close();

    let real_area = 1.25;
    let area = path.compute_area(None).unwrap();
    assert!((area - real_area).abs() <= EPSILON);
}

<|endoftext|>


<commit_before>use message::{Message};
use MiliSec;
use state::State;

const FIRST_OPENS_DEFAULT: bool = false;
const LAST_CLOSES_DEFAULT: bool = false;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Conditions {
    pub timeout: MiliSec,
    pub renew_timeout: Option<MiliSec>,
    pub first_opens: Option<bool>,
    pub last_closes: Option<bool>,
    pub max_size: Option<usize>,
    pub patterns: Vec<String>
}

impl Conditions {
    fn new(timeout: MiliSec) -> Conditions {
        Conditions {
            timeout: timeout,
            renew_timeout: None,
            first_opens: None,
            last_closes: None,
            max_size: None,
            patterns: Vec::new()
        }
    }

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens.unwrap_or(FIRST_OPENS_DEFAULT) {
            self.patterns.first().unwrap() == message.uuid()
        } else {
            true
        }
    }

    pub fn is_closing(&self, state: &State) -> bool {
        self.is_max_size_reached(state) || self.is_closing_message(state) || self.is_any_timer_expired(state)
    }

    fn is_max_size_reached(&self, state: &State) -> bool {
        self.max_size.map_or(false, |max_size| state.messages().len() >= max_size)
    }

    fn is_closing_message(&self, state: &State) -> bool {
        if self.last_closes.unwrap_or(LAST_CLOSES_DEFAULT) {
            self.patterns.last().unwrap() == state.messages().last().unwrap().uuid()
        } else {
            false
        }
    }

    fn is_any_timer_expired(&self, state: &State) -> bool {
        self.is_timeout_expired(state) || self.is_renew_timeout_expired(state)
    }

    fn is_timeout_expired(&self, state: &State) -> bool {
        state.elapsed_time() >= self.timeout
    }

    fn is_renew_timeout_expired(&self, state: &State) -> bool {
        self.renew_timeout.map_or(false, |renew_timeout| {
            state.elapsed_time_since_last_message() >= renew_timeout
        })
    }
}

pub struct Builder {
    conditions: Conditions
}

impl Builder {
    pub fn new(timeout: MiliSec) -> Builder {
        Builder{
            conditions: Conditions::new(timeout)
        }
    }

    pub fn renew_timeout(&mut self, timeout: MiliSec) -> &mut Builder {
        self.conditions.renew_timeout = Some(timeout);
        self
    }

    pub fn first_opens(&mut self, first_opens: bool) -> &mut Builder {
        self.conditions.first_opens = Some(first_opens);
        self
    }

    pub fn last_closes(&mut self, last_closes: bool) -> &mut Builder {
        self.conditions.last_closes = Some(last_closes);
        self
    }
    pub fn max_size(&mut self, max_size: usize) -> &mut Builder {
        self.conditions.max_size = Some(max_size);
        self
    }

    pub fn patterns(&mut self, patterns: Vec<String>) -> &mut Builder {
        self.conditions.patterns = patterns;
        self
    }

    pub fn build(&mut self) -> Conditions {
        self.conditions.clone()
    }
}

#[cfg(test)]
mod test {
    use serde_json::from_str;
    use super::Conditions;
    use std::rc::Rc;

    use message;
    use state::State;
    use super::Builder;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
        ];
        let condition = Builder::new(timeout).patterns(patterns).first_opens(true).build();
        let msg_which_should_not_be_ignored = message::Builder::new(&msg_id1).build();
        let msg_which_should_be_ignored = message::Builder::new(&msg_id2).build();
        assert_false!(condition.is_opening(&msg_which_should_be_ignored));
        assert_true!(condition.is_opening(&msg_which_should_not_be_ignored));
    }

    #[test]
    fn test_given_condition_when_a_closing_message_is_received_then_the_state_becomes_closed() {
        let timeout = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
            msg_id2.clone(),
        ];
        let mut state = State::new();
        let condition = Builder::new(timeout).patterns(patterns).last_closes(true).build();
        let msg_1 = message::Builder::new(&msg_id1).build();
        let msg_closing = Rc::new(message::Builder::new(&msg_id2).build());
        assert_true!(condition.is_opening(&msg_1));
        state.open();
        state.add_message(msg_closing);
        assert_true!(condition.is_closing(&mut state));
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_only_the_required_ones_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100
        }
        "#;

        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions struct with only a timeout field");
        assert_eq!(conditions.timeout, 100);
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_all_fields_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100,
            "renew_timeout": 50,
            "first_opens": true,
            "last_closes": false,
            "max_size": 42,
            "patterns": [
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "PATTERN_NAME"
            ]
        }
        "#;

        let expected_patterns = vec![
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "PATTERN_NAME".to_string(),
        ];
        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions struct");
        assert_eq!(conditions.timeout, 100);
        assert_eq!(conditions.renew_timeout, Some(50));
        assert_eq!(conditions.first_opens, Some(true));
        assert_eq!(conditions.last_closes, Some(false));
        assert_eq!(conditions.max_size, Some(42));
        assert_eq!(conditions.patterns, expected_patterns);
    }
}

mod deser {
    use MiliSec;
    use super::Conditions;
    use serde;
    use serde::de::Deserialize;

    impl serde::Deserialize for Conditions {
        fn deserialize<D>(deserializer: &mut D) -> Result<Conditions, D::Error>
            where D: serde::de::Deserializer
        {
            deserializer.visit_struct("Conditions", &[], ConditionsVisitor)
        }
    }

    enum Field {
        Timeout,
        RenewTimeout,
        FirstOpens,
        LastCloses,
        MaxSize,
        Patterns,
    }

    impl serde::Deserialize for Field {
        fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
            where D: serde::de::Deserializer
        {
            struct FieldVisitor;

            impl serde::de::Visitor for FieldVisitor {
                type Value = Field;

                fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                    where E: serde::de::Error
                {
                    match value {
                        "timeout" => Ok(Field::Timeout),
                        "renew_timeout" => Ok(Field::RenewTimeout),
                        "first_opens" => Ok(Field::FirstOpens),
                        "last_closes" => Ok(Field::LastCloses),
                        "max_size" => Ok(Field::MaxSize),
                        "patterns" => Ok(Field::Patterns),
                        name @ _ => Err(serde::de::Error::syntax(&format!("Unexpected field: {}", name))),
                    }
                }
            }

            deserializer.visit(FieldVisitor)
        }
    }

    struct ConditionsVisitor;

    impl serde::de::Visitor for ConditionsVisitor {
        type Value = Conditions;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Conditions, V::Error>
            where V: serde::de::MapVisitor
        {
            let mut timeout: Option<MiliSec> = None;
            let mut renew_timeout = None;
            let mut first_opens = None;
            let mut last_closes = None;
            let mut max_size = None;
            let mut patterns = None;

            loop {
                match try!(visitor.visit_key()) {
                    Some(Field::Timeout) => { timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::RenewTimeout) => { renew_timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::FirstOpens) => { first_opens = Some(try!(visitor.visit_value())); }
                    Some(Field::LastCloses) => { last_closes = Some(try!(visitor.visit_value())); }
                    Some(Field::MaxSize) => { max_size = Some(try!(visitor.visit_value())); }
                    Some(Field::Patterns) => { patterns = Some(try!(visitor.visit_value())); }
                    None => { break; }
                }
            }

            let timeout: MiliSec = match timeout {
                Some(timeout) => timeout,
                None => return visitor.missing_field("timeout"),
            };

            try!(visitor.end());

            Ok(
                Conditions {
                    timeout: timeout,
                    renew_timeout: renew_timeout,
                    first_opens: first_opens,
                    last_closes: last_closes,
                    max_size: max_size,
                    patterns: patterns.unwrap_or(Vec::new())
                }
            )
        }
    }
}
<commit_msg>conditions: import serde traits<commit_after>use message::{Message};
use MiliSec;
use state::State;

const FIRST_OPENS_DEFAULT: bool = false;
const LAST_CLOSES_DEFAULT: bool = false;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Conditions {
    pub timeout: MiliSec,
    pub renew_timeout: Option<MiliSec>,
    pub first_opens: Option<bool>,
    pub last_closes: Option<bool>,
    pub max_size: Option<usize>,
    pub patterns: Vec<String>
}

impl Conditions {
    fn new(timeout: MiliSec) -> Conditions {
        Conditions {
            timeout: timeout,
            renew_timeout: None,
            first_opens: None,
            last_closes: None,
            max_size: None,
            patterns: Vec::new()
        }
    }

    pub fn is_opening(&self, message: &Message) -> bool {
        if self.first_opens.unwrap_or(FIRST_OPENS_DEFAULT) {
            self.patterns.first().unwrap() == message.uuid()
        } else {
            true
        }
    }

    pub fn is_closing(&self, state: &State) -> bool {
        self.is_max_size_reached(state) || self.is_closing_message(state) || self.is_any_timer_expired(state)
    }

    fn is_max_size_reached(&self, state: &State) -> bool {
        self.max_size.map_or(false, |max_size| state.messages().len() >= max_size)
    }

    fn is_closing_message(&self, state: &State) -> bool {
        if self.last_closes.unwrap_or(LAST_CLOSES_DEFAULT) {
            self.patterns.last().unwrap() == state.messages().last().unwrap().uuid()
        } else {
            false
        }
    }

    fn is_any_timer_expired(&self, state: &State) -> bool {
        self.is_timeout_expired(state) || self.is_renew_timeout_expired(state)
    }

    fn is_timeout_expired(&self, state: &State) -> bool {
        state.elapsed_time() >= self.timeout
    }

    fn is_renew_timeout_expired(&self, state: &State) -> bool {
        self.renew_timeout.map_or(false, |renew_timeout| {
            state.elapsed_time_since_last_message() >= renew_timeout
        })
    }
}

pub struct Builder {
    conditions: Conditions
}

impl Builder {
    pub fn new(timeout: MiliSec) -> Builder {
        Builder{
            conditions: Conditions::new(timeout)
        }
    }

    pub fn renew_timeout(&mut self, timeout: MiliSec) -> &mut Builder {
        self.conditions.renew_timeout = Some(timeout);
        self
    }

    pub fn first_opens(&mut self, first_opens: bool) -> &mut Builder {
        self.conditions.first_opens = Some(first_opens);
        self
    }

    pub fn last_closes(&mut self, last_closes: bool) -> &mut Builder {
        self.conditions.last_closes = Some(last_closes);
        self
    }
    pub fn max_size(&mut self, max_size: usize) -> &mut Builder {
        self.conditions.max_size = Some(max_size);
        self
    }

    pub fn patterns(&mut self, patterns: Vec<String>) -> &mut Builder {
        self.conditions.patterns = patterns;
        self
    }

    pub fn build(&mut self) -> Conditions {
        self.conditions.clone()
    }
}

#[cfg(test)]
mod test {
    use serde_json::from_str;
    use super::Conditions;
    use std::rc::Rc;

    use message;
    use state::State;
    use super::Builder;

    #[test]
    fn test_given_condition_when_an_opening_message_is_received_then_the_state_becomes_opened() {
        let timeout = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
        ];
        let condition = Builder::new(timeout).patterns(patterns).first_opens(true).build();
        let msg_which_should_not_be_ignored = message::Builder::new(&msg_id1).build();
        let msg_which_should_be_ignored = message::Builder::new(&msg_id2).build();
        assert_false!(condition.is_opening(&msg_which_should_be_ignored));
        assert_true!(condition.is_opening(&msg_which_should_not_be_ignored));
    }

    #[test]
    fn test_given_condition_when_a_closing_message_is_received_then_the_state_becomes_closed() {
        let timeout = 100;
        let msg_id1 = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let msg_id2 = "21eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id1.clone(),
            msg_id2.clone(),
        ];
        let mut state = State::new();
        let condition = Builder::new(timeout).patterns(patterns).last_closes(true).build();
        let msg_1 = message::Builder::new(&msg_id1).build();
        let msg_closing = Rc::new(message::Builder::new(&msg_id2).build());
        assert_true!(condition.is_opening(&msg_1));
        state.open();
        state.add_message(msg_closing);
        assert_true!(condition.is_closing(&mut state));
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_only_the_required_ones_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100
        }
        "#;

        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions struct with only a timeout field");
        assert_eq!(conditions.timeout, 100);
    }

    #[test]
    fn test_given_conditions_in_json_when_we_have_all_fields_then_we_get_the_expected_result() {
        let json = r#"
        {
            "timeout": 100,
            "renew_timeout": 50,
            "first_opens": true,
            "last_closes": false,
            "max_size": 42,
            "patterns": [
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5",
                "PATTERN_NAME"
            ]
        }
        "#;

        let expected_patterns = vec![
                "1f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "2f78c9f1-cd33-4f83-bbcd-9d59f73094d5".to_string(),
                "PATTERN_NAME".to_string(),
        ];
        let conditions = from_str(json);
        println!("{:?}", &conditions);
        let conditions: Conditions = conditions.ok().expect("Failed to deserialize a Conditions struct");
        assert_eq!(conditions.timeout, 100);
        assert_eq!(conditions.renew_timeout, Some(50));
        assert_eq!(conditions.first_opens, Some(true));
        assert_eq!(conditions.last_closes, Some(false));
        assert_eq!(conditions.max_size, Some(42));
        assert_eq!(conditions.patterns, expected_patterns);
    }
}

mod deser {
    use MiliSec;
    use super::Conditions;
    use serde::de::{
        Deserialize,
        Deserializer,
        Error,
        MapVisitor,
        Visitor
    };

    impl Deserialize for Conditions {
        fn deserialize<D>(deserializer: &mut D) -> Result<Conditions, D::Error>
            where D: Deserializer
        {
            deserializer.visit_struct("Conditions", &[], ConditionsVisitor)
        }
    }

    enum Field {
        Timeout,
        RenewTimeout,
        FirstOpens,
        LastCloses,
        MaxSize,
        Patterns,
    }

    impl Deserialize for Field {
        fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
            where D: Deserializer
        {
            struct FieldVisitor;

            impl Visitor for FieldVisitor {
                type Value = Field;

                fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                    where E: Error
                {
                    match value {
                        "timeout" => Ok(Field::Timeout),
                        "renew_timeout" => Ok(Field::RenewTimeout),
                        "first_opens" => Ok(Field::FirstOpens),
                        "last_closes" => Ok(Field::LastCloses),
                        "max_size" => Ok(Field::MaxSize),
                        "patterns" => Ok(Field::Patterns),
                        name @ _ => Err(Error::syntax(&format!("Unexpected field: {}", name))),
                    }
                }
            }

            deserializer.visit(FieldVisitor)
        }
    }

    struct ConditionsVisitor;

    impl Visitor for ConditionsVisitor {
        type Value = Conditions;

        fn visit_map<V>(&mut self, mut visitor: V) -> Result<Conditions, V::Error>
            where V: MapVisitor
        {
            let mut timeout: Option<MiliSec> = None;
            let mut renew_timeout = None;
            let mut first_opens = None;
            let mut last_closes = None;
            let mut max_size = None;
            let mut patterns = None;

            loop {
                match try!(visitor.visit_key()) {
                    Some(Field::Timeout) => { timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::RenewTimeout) => { renew_timeout = Some(try!(visitor.visit_value())); }
                    Some(Field::FirstOpens) => { first_opens = Some(try!(visitor.visit_value())); }
                    Some(Field::LastCloses) => { last_closes = Some(try!(visitor.visit_value())); }
                    Some(Field::MaxSize) => { max_size = Some(try!(visitor.visit_value())); }
                    Some(Field::Patterns) => { patterns = Some(try!(visitor.visit_value())); }
                    None => { break; }
                }
            }

            let timeout: MiliSec = match timeout {
                Some(timeout) => timeout,
                None => return visitor.missing_field("timeout"),
            };

            try!(visitor.end());

            Ok(
                Conditions {
                    timeout: timeout,
                    renew_timeout: renew_timeout,
                    first_opens: first_opens,
                    last_closes: last_closes,
                    max_size: max_size,
                    patterns: patterns.unwrap_or(Vec::new())
                }
            )
        }
    }
}
<|endoftext|>


<commit_before>use pulldown_cmark::{html, Options, Parser};
use std::fs;

mod paths;
mod printing;

fn main() {
    printing::heading("Creating the build directory for my website.");

    printing::subheading("Cleaning the build directory.");
    paths::remove_dir(&paths::build());

    printing::subheading("Generating the build directory.");
    paths::create_dir(&paths::build());
    generate_pages();

    printing::subheading("Configuring the build directory.");
    // Adds a CNAME file for the host (GitHub Pages) and registrar (Hover) to use my custom domain name (trevordmiller.com)
    paths::create_file(&paths::build().join("CNAME"), "trevordmiller.com");
}

fn generate_pages() {
    match fs::read_dir(&paths::pages()) {
        Ok(markdown_files) => {
            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);

                let title = match markdown_file_contents.lines().next() {
                    Some(title) => &title[2..],
                    None => panic!("Cannot find a title in {}.", &route),
                };

                if route == "index" {
                    paths::create_file(
                        &paths::build().join("index.html"),
                        &markdown_to_html(&markdown_file_contents, &title),
                    );
                } else {
                    paths::create_dir(&paths::build().join(route));
                    paths::create_file(
                        &paths::build().join(route).join("index.html"),
                        &markdown_to_html(&markdown_file_contents, &title),
                    );
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };
}

fn markdown_to_html(markdown: &str, title: &str) -> std::string::String {
    let css = r#"
        body {
            max-width: 80ch;
            margin: 0 auto;
            padding: 1rem 1rem 2rem 1rem;
            font-family: "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif;
            color: #333333;
        }
        code {
            overflow: auto;
            display: block;
            background: #f5f5f5;
        }
        nav a, li, code {
            padding: 0.5rem;
        }
        header, code {
            font-family: "Courier New", Courier, monospace;
        }
        main {
            padding: 1rem 0 2rem 0;
            margin: 1rem 0 0 0;
            border-top: 1px solid #d3d3d3;
        }
        header, nav {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
        }
        header::before {
            content: ">";
            margin: 0 1ch 0 0;
        }
        header::after {
            content: "";
            margin: 0 0 0 1ch;
            display: inline-block;
            background: #333333;
            width: 1ch;
            height: 1em;
            animation: cursor 800ms infinite;
        }
        @keyframes cursor {
            0% {
                opacity: 0;
            }
            50% {
                opacity: 1;
            }
            to {
                opacity: 0;
            }
        }
    "#;

    let parser = Parser::new_ext(markdown, Options::empty());
    let mut html = String::new();
    html::push_html(&mut html, parser);

    format!("
        <!DOCTYPE html>

                <title>trevordmiller | {}</title>
                <meta name='author' content='Trevor D. Miller'>
                <meta name='description' content='Personal website.'>
                <meta charset='utf-8'>
                <meta name='viewport' content='width=device-width, initial-scale=1'>

                trevordmiller

                    Articles
                    About
                    Resume
                    Projects

                    {}

    ",
        &title,
        &css,
        &html
    )
}
<commit_msg>Set document description from source contents<commit_after>use pulldown_cmark::{html, Options, Parser};
use std::fs;

mod paths;
mod printing;

fn main() {
    printing::heading("Creating the build directory for my website.");

    printing::subheading("Cleaning the build directory.");
    paths::remove_dir(&paths::build());

    printing::subheading("Generating the build directory.");
    paths::create_dir(&paths::build());
    generate_pages();

    printing::subheading("Configuring the build directory.");
    // Adds a CNAME file for the host (GitHub Pages) and registrar (Hover) to use my custom domain name (trevordmiller.com)
    paths::create_file(&paths::build().join("CNAME"), "trevordmiller.com");
}

fn generate_pages() {
    match fs::read_dir(&paths::pages()) {
        Ok(markdown_files) => {
            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);

                let mut lines = markdown_file_contents.lines();

                let title = match lines.next() {
                    Some(title) => title.replace("# ", ""),
                    None => panic!("Cannot find a title in {}.", &route),
                };

                match lines.next() {
                    Some(_) => (),
                    None => panic!("Cannot find a break between title and description in {}.", &route),
                };

                let description = match lines.next() {
                    Some(description) => description.replace("_", ""),
                    None => panic!("Cannot find a description in {}.", &route),
                };

                if route == "index" {
                    paths::create_file(
                        &paths::build().join("index.html"),
                        &markdown_to_html(&markdown_file_contents, &title, &description),
                    );
                } else {
                    paths::create_dir(&paths::build().join(route));
                    paths::create_file(
                        &paths::build().join(route).join("index.html"),
                        &markdown_to_html(&markdown_file_contents, &title, &description),
                    );
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };
}

fn markdown_to_html(markdown: &str, title: &str, description: &str) -> std::string::String {
    let css = r#"
        body {
            max-width: 80ch;
            margin: 0 auto;
            padding: 1rem 1rem 2rem 1rem;
            font-family: "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif;
            color: #333333;
        }
        code {
            overflow: auto;
            display: block;
            background: #f5f5f5;
        }
        nav a, li, code {
            padding: 0.5rem;
        }
        header, code {
            font-family: "Courier New", Courier, monospace;
        }
        main {
            margin-top: 1rem;
            border-top: 1px solid #d3d3d3;
        }
        header, nav {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
        }
        header::before {
            content: ">";
            margin: 0 1ch 0 0;
        }
        header::after {
            content: "";
            margin: 0 0 0 1ch;
            display: inline-block;
            background: #333333;
            width: 1ch;
            height: 1em;
            animation: cursor 800ms infinite;
        }
        @keyframes cursor {
            0% {
                opacity: 0;
            }
            50% {
                opacity: 1;
            }
            to {
                opacity: 0;
            }
        }
    "#;

    let parser = Parser::new_ext(markdown, Options::empty());
    let mut html = String::new();
    html::push_html(&mut html, parser);

    format!("
        <!DOCTYPE html>

                <title>trevordmiller | {}</title>
                <meta name='description' content='{}'>
                <meta name='author' content='Trevor D. Miller'>
                <meta charset='utf-8'>
                <meta name='viewport' content='width=device-width, initial-scale=1'>

                trevordmiller

                    Articles
                    About
                    Resume
                    Projects

                    {}

    ",
        &title,
        &description,
        &css,
        &html
    )
}
<|endoftext|>


<commit_before>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use super::*;
use maplit::hashmap;
use oak_abi::{label::Label, proto::oak::application::ApplicationConfiguration};
use std::{fs, thread};

#[tokio::test]
// Might be unstable when running from `run-ci`. So it is ignored for now.
async fn test_low_level_server_node() {
    let configuration = ApplicationConfiguration {
        wasm_modules: hashmap! {},
        initial_node_configuration: None,
    };
    let signature_table = crate::SignatureTable::default();
    info!("Create runtime for test");
    let runtime = crate::RuntimeProxy::create_runtime(
        &configuration,
        &crate::SecureServerConfiguration::default(),
        &signature_table,
    );

    let (init_receiver, invocation_receiver) = create_communication_channel(&runtime);
    let tls_config = crate::tls::TlsConfig::new(
        "../examples/certs/local/local.pem",
        "../examples/certs/local/local.key",
    )
    .expect("Could not create TLS config from local certs.");

    // Create http server node
    let server_node = Box::new(
        HttpServerNode::new(
            "test-node",
            HttpServerConfiguration {
                address: "[::]:2525".to_string(),
            },
            tls_config,
        )
        .expect("Could not create server node"),
    );

    // Start the server node
    let (notify_sender, notify_receiver) = tokio::sync::oneshot::channel::<()>();
    let runtime_proxy = runtime.clone();
    // TODO(#1186): Use tokio instead of spawning a thread.
    let server_node_thread =
        std::thread::spawn(move || server_node.run(runtime_proxy, init_receiver, notify_receiver));

    // Simulate an Oak node that responds with 200 (OK) to every request it receives
    // TODO(#1186): Use tokio instead of spawning a thread.
    let runtime_proxy = runtime.clone();
    let oak_node_simulator_thread = thread::Builder::new()
        .name("Oak node simulator".to_string())
        .spawn(move || {
            oak_node_simulator(&runtime_proxy, invocation_receiver);
        })
        .expect("Error when spawning the thread.");

    // Send a request, and await on the response
    let resp = send_request().await;

    assert_eq!(resp.status(), http::status::StatusCode::OK.as_u16());

    notify_sender.send(()).unwrap_or_else(|()| {
        debug!("Test node already dropped `notify_receiver`.");
    });
    let _ = server_node_thread.join();
    let _ = oak_node_simulator_thread.join();

    // Clean up - stop the runtime ans any servers it is running
    runtime.runtime.stop();
}

fn create_communication_channel(runtime: &RuntimeProxy) -> (oak_abi::Handle, oak_abi::Handle) {
    // create channel: one end to server_node::run; the other to the Oak node.
    let (init_sender, init_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");

    // At the start the HTTP server pseudo-Node expects to receive an invocation channel, with
    // exactly one handle in it.
    //
    // Create a channel for receiving invocations to pass to the HTTP server pseudo-Node.
    let (invocation_sender, invocation_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");
    let message = crate::NodeMessage {
        bytes: vec![],
        handles: vec![invocation_sender],
    };

    let _ = runtime
        .channel_write(init_sender, message)
        .map_err(|err| panic!("Could not write to the `init_sender` channel: {}", err));
    let _ = runtime
        .channel_close(init_sender)
        .map_err(|err| panic!("Could not close the `init_sender` channel: {}.", err));

    (init_receiver, invocation_receiver)
}

fn oak_node_simulator(runtime: &RuntimeProxy, invocation_receiver: oak_abi::Handle) {
    // Get invocation message that contains the response_writer handle.
    let read_status = runtime
        .wait_on_channels(&[invocation_receiver])
        .expect("Error while waiting on invocation_receiver");
    if read_status[0] == ChannelReadStatus::ReadReady {
        if let Ok(Some(msg)) = runtime.channel_read(invocation_receiver) {
            // Prepare the response
            let resp = HttpResponse {
                body: vec![],
                status: http::status::StatusCode::OK.as_u16() as i32,
                headers: hashmap! {},
            };
            let mut message = crate::NodeMessage {
                bytes: vec![],
                handles: vec![],
            };
            let _ = resp.encode(&mut message.bytes);

            // Send the response over the response_writer channel
            let response_writer_handle = msg.handles[1];
            let _ = runtime.channel_write(response_writer_handle, message);
        }
    } else {
        panic!("Error while waiting for message on invocation_receiver");
    }
}

async fn send_request() -> http::response::Response<hyper::Body> {
    // Send a request, and wait for the response
    let label = oak_abi::label::Label::public_untrusted();
    let mut label_bytes = vec![];
    let _ = label.encode(&mut label_bytes);

    let path = "../examples/certs/local/ca.pem";
    let ca_file = fs::File::open(path).unwrap_or_else(|e| panic!("failed to open {}: {}", path, e));
    let mut ca = io::BufReader::new(ca_file);

    // Build an HTTP connector which supports HTTPS too.
    let mut http = hyper::client::HttpConnector::new();
    http.enforce_http(false);
    // Build a TLS client, using the custom CA store for lookups.
    let mut tls = rustls::ClientConfig::new();
    tls.root_store
        .add_pem_file(&mut ca)
        .expect("failed to load custom CA store");
    // Join the above part into an HTTPS connector.
    let https = hyper_rustls::HttpsConnector::from((http, tls));

    let client: hyper::client::Client<_, hyper::Body> =
        hyper::client::Client::builder().build(https);

    let request = hyper::Request::builder()
        .method("get")
        .uri("https://localhost:2525")
        .header(oak_abi::OAK_LABEL_HTTP_KEY, label_bytes)
        .body(hyper::Body::empty())
        .unwrap();

    client
        .request(request)
        .await
        .expect("Error while awaiting response")
}
<commit_msg>Add a test to check that HTTP server node rejects unsecure requests (#1397)<commit_after>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use super::*;
use maplit::hashmap;
use oak_abi::{label::Label, proto::oak::application::ApplicationConfiguration};
use std::{fs, option::Option, thread::JoinHandle};

struct HttpServerTester {
    runtime: RuntimeProxy,
    server_node_thread_handle: Option<JoinHandle<()>>,
    oak_node_simulator_thread_handle: Option<JoinHandle<()>>,
    notify_sender: Option<tokio::sync::oneshot::Sender<()>>,
}

impl HttpServerTester {
    fn new(port: u32, with_simulator_thread: bool) -> HttpServerTester {
        let runtime = create_runtime();
        let server_node = create_server_node(port);
        let (init_receiver, invocation_receiver) = create_communication_channel(&runtime);

        // Start the server node
        let (notify_sender, notify_receiver) = tokio::sync::oneshot::channel::<()>();
        let runtime_proxy = runtime.clone();
        // TODO(#1186): Use tokio instead of spawning a thread.
        let server_node_thread = std::thread::spawn(move || {
            server_node.run(runtime_proxy, init_receiver, notify_receiver)
        });

        // Simulate an Oak node that responds with 200 (OK) to every request it receives
        // TODO(#1186): Use tokio instead of spawning a thread.
        let mut oak_node_simulator_thread = None;
        if with_simulator_thread {
            let runtime_proxy = runtime.clone();
            oak_node_simulator_thread = Some(std::thread::spawn(move || {
                oak_node_simulator(&runtime_proxy, invocation_receiver);
            }));
        }

        HttpServerTester {
            runtime,
            server_node_thread_handle: Some(server_node_thread),
            oak_node_simulator_thread_handle: oak_node_simulator_thread,
            notify_sender: Some(notify_sender),
        }
    }

    fn cleanup(&mut self) {
        if let Some(sender) = self.notify_sender.take() {
            sender.send(()).unwrap_or_else(|()| {
                debug!("Test node already dropped `notify_receiver`.");
            })
        }
        let _ = self.server_node_thread_handle.take().map(JoinHandle::join);
        let _ = self
            .oak_node_simulator_thread_handle
            .take()
            .map(JoinHandle::join);

        // stop the runtime and any servers it is running
        self.runtime.runtime.stop();
    }
}

#[tokio::test]
async fn test_https_server_can_serve_https_requests() {
    // Start a runtime with an HTTP server node, and a thread simulating an Oak node to respond to
    // HTTP requests.
    let mut http_server_tester = HttpServerTester::new(2525, true);
    // Send an HTTPS request, and check that response has StatusCode::OK
    let resp = send_request("https://localhost:2525").await;
    assert!(resp.is_ok());
    assert_eq!(
        resp.unwrap().status(),
        http::status::StatusCode::OK.as_u16()
    );
    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

#[tokio::test]
async fn test_https_server_cannot_serve_http_requests() {
    // Start a runtime with an HTTP server node. The HTTP server in this case rejects the requests,
    // and would not send anything to the Oak node. Creating a thread to simulate the Oak node will
    // result in the thread being blocked for ever. So, we set up the test without an
    // oak-node-simulator thread.
    let mut http_server_tester = HttpServerTester::new(2526, false);
    // Send an HTTP request, and check that the server responds with an error
    let resp = send_request("http://localhost:2526").await;
    assert!(resp.is_err());
    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

fn create_runtime() -> RuntimeProxy {
    let configuration = ApplicationConfiguration {
        wasm_modules: hashmap! {},
        initial_node_configuration: None,
    };
    let signature_table = crate::SignatureTable::default();
    info!("Create runtime for test");

    crate::RuntimeProxy::create_runtime(
        &configuration,
        &crate::SecureServerConfiguration::default(),
        &signature_table,
    )
}

fn create_server_node(port: u32) -> Box<HttpServerNode> {
    let tls_config = crate::tls::TlsConfig::new(
        "../examples/certs/local/local.pem",
        "../examples/certs/local/local.key",
    )
    .expect("Could not create TLS config from local certs.");

    // Create http server node
    Box::new(
        HttpServerNode::new(
            "test-node",
            HttpServerConfiguration {
                address: format!("[::]:{}", port),
            },
            tls_config,
        )
        .expect("Could not create server node"),
    )
}

fn create_communication_channel(runtime: &RuntimeProxy) -> (oak_abi::Handle, oak_abi::Handle) {
    // create channel: one end to server_node::run; the other to the Oak node.
    let (init_sender, init_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");

    // At the start the HTTP server pseudo-Node expects to receive an invocation channel, with
    // exactly one handle in it.
    //
    // Create a channel for receiving invocations to pass to the HTTP server pseudo-Node.
    let (invocation_sender, invocation_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");
    let message = crate::NodeMessage {
        bytes: vec![],
        handles: vec![invocation_sender],
    };

    let _ = runtime
        .channel_write(init_sender, message)
        .map_err(|err| panic!("Could not write to the `init_sender` channel: {}", err));
    let _ = runtime
        .channel_close(init_sender)
        .map_err(|err| panic!("Could not close the `init_sender` channel: {}.", err));

    (init_receiver, invocation_receiver)
}

fn oak_node_simulator(runtime: &RuntimeProxy, invocation_receiver: oak_abi::Handle) {
    // Get invocation message that contains the response_writer handle.
    let read_status = runtime
        .wait_on_channels(&[invocation_receiver])
        .expect("Error while waiting on invocation_receiver");
    if read_status[0] == ChannelReadStatus::ReadReady {
        if let Ok(Some(msg)) = runtime.channel_read(invocation_receiver) {
            // Prepare the response
            let resp = HttpResponse {
                body: vec![],
                status: http::status::StatusCode::OK.as_u16() as i32,
                headers: hashmap! {},
            };
            let mut message = crate::NodeMessage {
                bytes: vec![],
                handles: vec![],
            };
            resp.encode(&mut message.bytes)
                .expect("could not serialize response to bytes");

            // Send the response over the response_writer channel
            let response_writer_handle = msg.handles[1];
            let _ = runtime.channel_write(response_writer_handle, message);
        }
    } else {
        panic!("Error while waiting for message on invocation_receiver");
    }
}

async fn send_request(uri: &str) -> Result<http::response::Response<hyper::Body>, hyper::Error> {
    // Send a request, and wait for the response
    let label = oak_abi::label::Label::public_untrusted();
    let mut label_bytes = vec![];
    let _ = label.encode(&mut label_bytes);

    let path = "../examples/certs/local/ca.pem";
    let ca_file = fs::File::open(path).unwrap_or_else(|e| panic!("failed to open {}: {}", path, e));
    let mut ca = io::BufReader::new(ca_file);

    // Build an HTTP connector which supports HTTPS too.
    let mut http = hyper::client::HttpConnector::new();
    http.enforce_http(false);
    // Build a TLS client, using the custom CA store for lookups.
    let mut tls = rustls::ClientConfig::new();
    tls.root_store
        .add_pem_file(&mut ca)
        .expect("failed to load custom CA store");
    // Join the above part into an HTTPS connector.
    let https = hyper_rustls::HttpsConnector::from((http, tls));

    let client: hyper::client::Client<_, hyper::Body> =
        hyper::client::Client::builder().build(https);

    let request = hyper::Request::builder()
        .method("get")
        .uri(uri)
        .header(oak_abi::OAK_LABEL_HTTP_KEY, label_bytes)
        .body(hyper::Body::empty())
        .unwrap();

    client.request(request).await
}
<|endoftext|>


<commit_before>use pact_consumer::prelude::*;
use pact_consumer::{json_pattern, json_pattern_internal};
use std::{
  io::prelude::*,
  env,
  path::Path,
  fs
};
use expectest::prelude::*;
use expectest::expect;
use reqwest::blocking::Client;
use pact_matching::models::Pact;

/// This is supposed to be a doctest in lib.rs, but it's breaking there, so
/// we have an executable copy here.
#[test]
fn mock_server_passing_validation() {
    use expectest::*;

    let _ = env_logger::init();

    let output_dir = Path::new("target/pact_dir");
    fs::remove_dir_all(output_dir).unwrap_or(());

    env::set_var("PACT_OUTPUT_DIR", &output_dir);

    {
      // Define the Pact for the test, specify the names of the consuming
      // application and the provider application.
      let alice_service = PactBuilder::new("Consumer", "Alice Service")
        // Start a new interaction. We can add as many interactions as we want.
        .interaction("a retrieve Mallory request", |i| {
          // Defines a provider state. It is optional.
          i.given("there is some good mallory");
          // Define the request, a GET (default) request to '/mallory'.
          i.request.path("/mallory");
          // Define the response we want returned.
          i.response
            .ok()
            .content_type("text/plain")
            .body("That is some good Mallory.");
        })
        .start_mock_server();

      // You would use your actual client code here.
      let mallory_url = alice_service.path("/mallory");
      let mut response = reqwest::blocking::get(mallory_url).expect("could not fetch URL");
      let mut body = String::new();
      response.read_to_string(&mut body).expect("could not read response body");
      assert_eq!(body, "That is some good Mallory.");
    }

    // When your test has finished running, all verifications will be performed
    // automatically, and an error will be thrown if any have failed.

    env::remove_var("PACT_OUTPUT_DIR");

    let path_file = Path::new("target/pact_dir/Consumer-Alice Service.json");
    expect!(path_file.exists()).to(be_true());
}

#[test]
#[should_panic]
fn mock_server_failing_validation() {
    let _ = env_logger::init();

    let hello_service = PactBuilder::new("Hello CLI", "Hello Server")
        .interaction("request a greeting", |i| {
            i.request.path("/hello");
            i.response.body("Hello!");
        })
        .start_mock_server();
    // Call with the wrong URL, which should lead to a panic at the end of
    // the function.
    let url = hello_service.path("/goodbye");
    let _ = reqwest::blocking::get(url);
}

#[test]
fn duplicate_interactions() {
  let _ = env_logger::init();

  let output_dir = Path::new("/tmp/duplicate_interactions");
  fs::remove_dir_all(output_dir).unwrap_or(());

  env::set_var("PACT_OUTPUT_DIR", &output_dir);

  for _ in 1..3 {
    let mock_service = PactBuilder::new("consumer 1", "provider 1")
      .interaction("tricky test", |interaction| {
        interaction
          .request
          .put()
          .json_body(pact_consumer::json_pattern!({
                          "name": pact_consumer::like!("mai"),
                          "street": pact_consumer::like!("5th"),
                          "state": pact_consumer::like!("VA"),
                      }))
          .path("/rolex.html");
        interaction.response.body("TrixR4Kidz");
      })
      .build()
      .start_mock_server();

    let mock_url = mock_service.url().as_ref();

    assert_eq!(
      Client::new()
        .put(&format!("{}rolex.html", mock_url))
        .json(&serde_json::json!({
                      "name": "mai",
                      "street": "5th",
                      "state": "VA",
                  }))
        .send()
        .unwrap()
        .text()
        .unwrap(),
      "TrixR4Kidz",
    );
  }

  env::remove_var("PACT_OUTPUT_DIR");

  let path = output_dir.join("consumer 1-provider 1.json");
  let written_pact = Pact::read_pact(path.as_path()).unwrap();
  expect!(written_pact.interactions.len()).to(be_equal_to(1));
}
<commit_msg>fix: ignore flakey test<commit_after>use pact_consumer::prelude::*;
use pact_consumer::{json_pattern, json_pattern_internal};
use std::{
  io::prelude::*,
  env,
  path::Path,
  fs
};
use expectest::prelude::*;
use expectest::expect;
use reqwest::blocking::Client;
use pact_matching::models::Pact;

/// This is supposed to be a doctest in lib.rs, but it's breaking there, so
/// we have an executable copy here.
#[test]
#[ignore]
fn mock_server_passing_validation() {
    use expectest::*;

    let _ = env_logger::init();

    let output_dir = Path::new("target/pact_dir");
    fs::remove_dir_all(output_dir).unwrap_or(());

    env::set_var("PACT_OUTPUT_DIR", &output_dir);

    {
      // Define the Pact for the test, specify the names of the consuming
      // application and the provider application.
      let alice_service = PactBuilder::new("Consumer", "Alice Service")
        // Start a new interaction. We can add as many interactions as we want.
        .interaction("a retrieve Mallory request", |i| {
          // Defines a provider state. It is optional.
          i.given("there is some good mallory");
          // Define the request, a GET (default) request to '/mallory'.
          i.request.path("/mallory");
          // Define the response we want returned.
          i.response
            .ok()
            .content_type("text/plain")
            .body("That is some good Mallory.");
        })
        .start_mock_server();

      // You would use your actual client code here.
      let mallory_url = alice_service.path("/mallory");
      let mut response = reqwest::blocking::get(mallory_url).expect("could not fetch URL");
      let mut body = String::new();
      response.read_to_string(&mut body).expect("could not read response body");
      assert_eq!(body, "That is some good Mallory.");
    }

    // When your test has finished running, all verifications will be performed
    // automatically, and an error will be thrown if any have failed.

    env::remove_var("PACT_OUTPUT_DIR");

    let path_file = Path::new("target/pact_dir/Consumer-Alice Service.json");
    expect!(path_file.exists()).to(be_true());
}

#[test]
#[should_panic]
fn mock_server_failing_validation() {
    let _ = env_logger::init();

    let hello_service = PactBuilder::new("Hello CLI", "Hello Server")
        .interaction("request a greeting", |i| {
            i.request.path("/hello");
            i.response.body("Hello!");
        })
        .start_mock_server();
    // Call with the wrong URL, which should lead to a panic at the end of
    // the function.
    let url = hello_service.path("/goodbye");
    let _ = reqwest::blocking::get(url);
}

#[test]
fn duplicate_interactions() {
  let _ = env_logger::init();

  let output_dir = Path::new("/tmp/duplicate_interactions");
  fs::remove_dir_all(output_dir).unwrap_or(());

  env::set_var("PACT_OUTPUT_DIR", &output_dir);

  for _ in 1..3 {
    let mock_service = PactBuilder::new("consumer 1", "provider 1")
      .interaction("tricky test", |interaction| {
        interaction
          .request
          .put()
          .json_body(pact_consumer::json_pattern!({
                          "name": pact_consumer::like!("mai"),
                          "street": pact_consumer::like!("5th"),
                          "state": pact_consumer::like!("VA"),
                      }))
          .path("/rolex.html");
        interaction.response.body("TrixR4Kidz");
      })
      .build()
      .start_mock_server();

    let mock_url = mock_service.url().as_ref();

    assert_eq!(
      Client::new()
        .put(&format!("{}rolex.html", mock_url))
        .json(&serde_json::json!({
                      "name": "mai",
                      "street": "5th",
                      "state": "VA",
                  }))
        .send()
        .unwrap()
        .text()
        .unwrap(),
      "TrixR4Kidz",
    );
  }

  env::remove_var("PACT_OUTPUT_DIR");

  let path = output_dir.join("consumer 1-provider 1.json");
  let written_pact = Pact::read_pact(path.as_path()).unwrap();
  expect!(written_pact.interactions.len()).to(be_equal_to(1));
}
<|endoftext|>