<commit_before>use crate::errors::{ParsingError, Result};

/// Try to parse the given array of bytes into an f64, by first converting
/// it to the corresponding ASCII (or even here, UTF-8) values.
pub fn parse_f64(value : &[u8]) -> Result<f64> {
    let res = std::str::from_utf8(value)?;
    let res_f64 = res.parse::<f64>()?;
    Ok(res_f64 as f64)
}

/// Try to parse the given array of bytes into an i64, by first converting
/// it to the corresponding ASCII (or even here, UTF-8) values.
pub fn parse_i64(value : &[u8]) -> Result<i64> {
    let res = std::str::from_utf8(value)?;
    let res_u64 = res.parse::<i64>()?;
    Ok(res_u64)
}

/// Try to parse the given array of bytes into an u64, by first converting
/// it to the corresponding ASCII (or even here, UTF-8) values.
pub fn parse_u64(value : &[u8]) -> Result<u64> {
    let res = std::str::from_utf8(value)?;
    let res_u64 = res.parse::<u64>()?;
    Ok(res_u64)
}

/// Try to parse the given array of bytes into an f64:
///   - INFINITY if it represents `"true"` in ASCII
///   - -INFINITY if it represents `"false"` in ASCII
///   - If it represents an integer in ASCII, returns that integer under an
///     f64 form.
///
/// Return an error in any other case.
pub fn parse_u64_or_bool(value : &[u8]) -> Result<f64> {
    match value {
        b"true" => Ok(f64::INFINITY),
        b"false" => Ok(f64::NEG_INFINITY),
        val => {
            let res_u64 = parse_u64(val)?;
            Ok(res_u64 as f64)
        }
    }
}

/// Try to parse the given array of bytes into a bool:
///   - `true` if it represents `"true"` in ASCII
///   - `false` if it represents `"false"` in ASCII
///
/// Return an error in any other case.
pub fn parse_bool(value : &[u8]) -> Result<bool> {
    match value {
        b"true" => Ok(true),
        b"false" => Ok(false),
        val => {
            let mut base_str = "Invalid boolean: ".to_owned();
            let val = std::str::from_utf8(val)?;
            base_str.push_str(val);
            Err(ParsingError(base_str))
        }
    }
}

pub fn parse_byte_range(value : &[u8]) -> Result<(f64, f64)> {
    let mut cursor = 0usize;
    let start;
    loop {
        if cursor >= value.len() {
            let e = ParsingError("Invalid byte-range: end encountered too soon".to_owned());
            return Err(e);
        }
        if value[cursor] == b'-' {
            start = parse_u64(&value[0..cursor])?;
            break;
        }
        cursor += 1;
    }

    let end = parse_u64(&value[cursor + 1..value.len()])?;
    Ok((start as f64, end as f64))
}

/// Parse ISO 8601 duration format (e.g. P5Y10M43HT22H8M3S) into the
/// corresponding seconds in a float format.
/// This code could be much simpler if it was RegExp-based but I preferred not
/// to, mainly because I didn't want to incur the size cost of importing regex
/// code in here
pub fn parse_iso_8601_duration(value : &[u8]) -> Result<f64> {
    if value[0] != b'P' {
        let err = ParsingError("Unexpected duration. Should start with \"P\"".to_owned());
        return Err(err);
    }
    let mut base = 1;
    let mut result = 0.;
    if value[1] != b'T' {
        loop {
            let (number, i) = read_next_float(value, base)?;
            if i == value.len() {
                let e = ParsingError("Invalid ISO 8601 duration: end encountered too soon".to_owned());
                return Err(e);
            }
            let factor = match value[i] {
                b'Y' => 365 * 24 * 60 * 60,
                b'M' => 30 * 24 * 60 * 60,
                b'D' => 24 * 60 * 60,
                _ => {
                    let e = ParsingError("Invalid duration: unexpected unit.".to_owned());
                    return Err(e);
                }
            };
            result += number * (factor as f64);
            base = i + 1;
            if base == value.len() {
                return Ok(result as f64);
            }
            if value[base] == b'T' {
                break;
            }
        }
    }
    base += 1;
    loop {
        let (number, i) = read_next_float(value, base)?;
        if i == value.len() {
            let e = ParsingError("Invalid ISO 8601 duration: end encountered too soon".to_owned());
            return Err(e);
        }
        let factor = match value[i] {
            b'H' => 60 * 60,
            b'M' => 60,
            b'S' => 1,
            _ => {
                let e = ParsingError("Invalid duration: unexpected unit.".to_owned());
                return Err(e);
            }
        };
        result += number * (factor as f64);
        base = i + 1;
        if base == value.len() {
            return Ok(result as f64);
        }
    }
}

/// Parse a floating point number, represented by `value` in ASCII, starting at
/// the position `base_offset`.
/// The decimal separator can either a be a point ('.') or a colon (',').
///
/// If it succeeds, returns both the floating point number as an f64 and the
/// offset coming just after that float in `value` (or the length of `value` if
/// it ended with a float).
fn read_next_float(
    value : &[u8],
    base_offset : usize
) -> Result<(f64, usize)> {
    let mut i = base_offset;
    while i < value.len() && value[i] >= b'0' && value[i] <= b'9' {
        i += 1;
    }
    if i == value.len() || (value[i] != b'.' && value[i] != b',') {
        // UNSAFE: We already checked that this string represents a valid integer
        let val_str = unsafe {
            std::str::from_utf8_unchecked(&value[base_offset..i])
        };
        let val_u64 = val_str.parse::<u64>()?;
        return Ok((val_u64 as f64, i));
    }

    i += 1;
    while i < value.len() && value[i] >= b'0' && value[i] <= b'9' {
        i += 1;
    }
    // UNSAFE: We already checked that this string represents a valid float
    let val_str = unsafe {
        std::str::from_utf8_unchecked(&value[base_offset..i])
    };
    let val_f64 = val_str.parse::<f64>()?;
    Ok((val_f64, i))
}
<commit_msg>wasm/dash: don't throw if an ISO8601 duration is empty<commit_after>use crate::errors::{ParsingError, Result};

/// Try to parse the given array of bytes into an f64, by first converting
/// it to the corresponding ASCII (or even here, UTF-8) values.
pub fn parse_f64(value : &[u8]) -> Result<f64> {
    let res = std::str::from_utf8(value)?;
    let res_f64 = res.parse::<f64>()?;
    Ok(res_f64 as f64)
}

/// Try to parse the given array of bytes into an i64, by first converting
/// it to the corresponding ASCII (or even here, UTF-8) values.
pub fn parse_i64(value : &[u8]) -> Result<i64> {
    let res = std::str::from_utf8(value)?;
    let res_u64 = res.parse::<i64>()?;
    Ok(res_u64)
}

/// Try to parse the given array of bytes into an u64, by first converting
/// it to the corresponding ASCII (or even here, UTF-8) values.
pub fn parse_u64(value : &[u8]) -> Result<u64> {
    let res = std::str::from_utf8(value)?;
    let res_u64 = res.parse::<u64>()?;
    Ok(res_u64)
}

/// Try to parse the given array of bytes into an f64:
///   - INFINITY if it represents `"true"` in ASCII
///   - -INFINITY if it represents `"false"` in ASCII
///   - If it represents an integer in ASCII, returns that integer under an
///     f64 form.
///
/// Return an error in any other case.
pub fn parse_u64_or_bool(value : &[u8]) -> Result<f64> {
    match value {
        b"true" => Ok(f64::INFINITY),
        b"false" => Ok(f64::NEG_INFINITY),
        val => {
            let res_u64 = parse_u64(val)?;
            Ok(res_u64 as f64)
        }
    }
}

/// Try to parse the given array of bytes into a bool:
///   - `true` if it represents `"true"` in ASCII
///   - `false` if it represents `"false"` in ASCII
///
/// Return an error in any other case.
pub fn parse_bool(value : &[u8]) -> Result<bool> {
    match value {
        b"true" => Ok(true),
        b"false" => Ok(false),
        val => {
            let mut base_str = "Invalid boolean: ".to_owned();
            let val = std::str::from_utf8(val)?;
            base_str.push_str(val);
            Err(ParsingError(base_str))
        }
    }
}

// TODO Is something like 5- also valid here?
// It seems to be but it's not yet handled here
// (We could use e.g. the `INFINITY` float value)
pub fn parse_byte_range(value : &[u8]) -> Result<(f64, f64)> {
    let mut cursor = 0usize;
    let start;
    loop {
        if cursor >= value.len() {
            let e = ParsingError("Invalid byte-range: end encountered too soon".to_owned());
            return Err(e);
        }
        if value[cursor] == b'-' {
            start = parse_u64(&value[0..cursor])?;
            break;
        }
        cursor += 1;
    }

    let end = parse_u64(&value[cursor + 1..value.len()])?;
    Ok((start as f64, end as f64))
}

/// Parse ISO 8601 duration format (e.g. P5Y10M43HT22H8M3S) into the
/// corresponding seconds in a float format.
/// This code could be much simpler if it was RegExp-based but I preferred not
/// to, mainly because I didn't want to incur the size cost of importing regex
/// code in here
pub fn parse_iso_8601_duration(value : &[u8]) -> Result<f64> {
    if value.is_empty() || value[0] != b'P' {
        let err = ParsingError("Unexpected duration. Should start with \"P\"".to_owned());
        return Err(err);
    }
    let mut base = 1;
    let mut result = 0.;
    if value[1] != b'T' {
        loop {
            let (number, i) = read_next_float(value, base)?;
            if i == value.len() {
                let e = ParsingError("Invalid ISO 8601 duration: end encountered too soon".to_owned());
                return Err(e);
            }
            let factor = match value[i] {
                b'Y' => 365 * 24 * 60 * 60,
                b'M' => 30 * 24 * 60 * 60,
                b'D' => 24 * 60 * 60,
                _ => {
                    let e = ParsingError("Invalid duration: unexpected unit.".to_owned());
                    return Err(e);
                }
            };
            result += number * (factor as f64);
            base = i + 1;
            if base == value.len() {
                return Ok(result as f64);
            }
            if value[base] == b'T' {
                break;
            }
        }
    }
    base += 1;
    loop {
        let (number, i) = read_next_float(value, base)?;
        if i == value.len() {
            let e = ParsingError("Invalid ISO 8601 duration: end encountered too soon".to_owned());
            return Err(e);
        }
        let factor = match value[i] {
            b'H' => 60 * 60,
            b'M' => 60,
            b'S' => 1,
            _ => {
                let e = ParsingError("Invalid duration: unexpected unit.".to_owned());
                return Err(e);
            }
        };
        result += number * (factor as f64);
        base = i + 1;
        if base == value.len() {
            return Ok(result as f64);
        }
    }
}

/// Parse a floating point number, represented by `value` in ASCII, starting at
/// the position `base_offset`.
/// The decimal separator can either a be a point ('.') or a colon (',').
///
/// If it succeeds, returns both the floating point number as an f64 and the
/// offset coming just after that float in `value` (or the length of `value` if
/// it ended with a float).
fn read_next_float(
    value : &[u8],
    base_offset : usize
) -> Result<(f64, usize)> {
    let mut i = base_offset;
    while i < value.len() && value[i] >= b'0' && value[i] <= b'9' {
        i += 1;
    }
    if i == value.len() || (value[i] != b'.' && value[i] != b',') {
        // UNSAFE: We already checked that this string represents a valid integer
        let val_str = unsafe {
            std::str::from_utf8_unchecked(&value[base_offset..i])
        };
        let val_u64 = val_str.parse::<u64>()?;
        return Ok((val_u64 as f64, i));
    }

    i += 1;
    while i < value.len() && value[i] >= b'0' && value[i] <= b'9' {
        i += 1;
    }
    // UNSAFE: We already checked that this string represents a valid float
    let val_str = unsafe {
        std::str::from_utf8_unchecked(&value[base_offset..i])
    };
    let val_f64 = val_str.parse::<f64>()?;
    Ok((val_f64, i))
}

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

    #[test]
    fn test_parse_8601_duration() {
        assert_eq!(parse_iso_8601_duration(b"P1Y10M43DT22H8M3S").unwrap(), 61250883.);
        assert_eq!(parse_iso_8601_duration(b"P1Y10M43DT22H8M3S").unwrap(), 61250883.);
        assert_eq!(parse_iso_8601_duration(b"PT3S").unwrap(), 3.);
        assert_eq!(parse_iso_8601_duration(b"PT1M3.4S").unwrap(), 63.4);

        assert!(parse_iso_8601_duration(b"").err().is_some());
        assert!(parse_iso_8601_duration(b"3S").err().is_some());
        assert!(parse_iso_8601_duration(b"T3S").err().is_some());
        assert!(parse_iso_8601_duration(b"P3S").err().is_some());
    }

    #[test]
    fn test_parse_byte_range() {
        assert_eq!(parse_byte_range(b"1-2").unwrap(), (1., 2.));
        assert_eq!(parse_byte_range(b"100-200").unwrap(), (100., 200.));

        assert!(parse_byte_range(b"").err().is_some());
        assert!(parse_byte_range(b"A").err().is_some());
        assert!(parse_byte_range(b"15-A").err().is_some());
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use std::str::FromStr;

use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let code = "..100u32";
    let tt = TokenStream::from_str(code).unwrap();
    let expr: Expr = syn::parse2(tt.clone()).unwrap();
    let expr_range: ExprRange = syn::parse2(tt).unwrap();
    assert_eq!(expr, Expr::Range(expr_range));
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let expr = syn::parse_str::<Expr>("fut.await").unwrap();

    snapshot!(expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    // FIXME: the #[inside] attribute should go on the Expr::Path not Expr::Call
    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: ``,
            },
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "inside",
                            arguments: None,
                        },
                    ],
                },
                tokens: ``,
            },
        ],
        func: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "f",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}
<commit_msg>Update Group attrs snapshot<commit_after>#[macro_use]
mod macros;

use std::str::FromStr;

use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let code = "..100u32";
    let tt = TokenStream::from_str(code).unwrap();
    let expr: Expr = syn::parse2(tt.clone()).unwrap();
    let expr_range: ExprRange = syn::parse2(tt).unwrap();
    assert_eq!(expr, Expr::Range(expr_range));
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let expr = syn::parse_str::<Expr>("fut.await").unwrap();

    snapshot!(expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    // FIXME: the #[inside] attribute should go on the Expr::Path not Expr::Call
    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: ``,
            },
        ],
        func: Expr::Group {
            expr: Expr::Path {
                attrs: [
                    Attribute {
                        style: Outer,
                        path: Path {
                            segments: [
                                PathSegment {
                                    ident: "inside",
                                    arguments: None,
                                },
                            ],
                        },
                        tokens: ``,
                    },
                ],
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::ptr;
use smallvec::SmallVec;

use command_buffer::cb::UnsafeCommandBuffer;
use command_buffer::pool::CommandPool;
use device::Queue;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Prototype for a submission that executes command buffers.
#[derive(Debug)]
pub struct SubmitCommandBufferBuilder<'a> {
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    dest_stages: SmallVec<[vk::PipelineStageFlags; 8]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 4]>,
    fence: vk::Fence,
    marker: PhantomData<&'a ()>,
}

impl<'a> SubmitCommandBufferBuilder<'a> {
    /// Builds a new empty `SubmitCommandBufferBuilder`.
    #[inline]
    pub fn new() -> SubmitCommandBufferBuilder<'a> {
        SubmitCommandBufferBuilder {
            wait_semaphores: SmallVec::new(),
            dest_stages: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            command_buffers: SmallVec::new(),
            fence: 0,
            marker: PhantomData,
        }
    }

    /// Returns true if this builder will signal a fence when submitted.
    #[inline]
    pub fn has_fence(&self) -> bool {
        self.fence != 0
    }

    /// Adds an operation that signals a fence after this submission ends.
    ///
    /// If a fence was previously set, it will no longer be signaled.
    #[inline]
    pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) {
        self.fence = fence.internal_object()
    }

    /// Adds a semaphore to be waited upon before the command buffers are executed.
    ///
    /// Only the given `stages` of the command buffers added afterwards will wait upon
    /// the semaphore. Other stages not included in `stages` can execute before waiting.
    #[inline]
    pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore, stages: PipelineStages) {
        debug_assert!(Into::<vk::PipelineStageFlagBits>::into(stages) != 0);
        self.wait_semaphores.push(semaphore.internal_object());
        self.dest_stages.push(stages.into());
    }

    /// Adds a command buffer that is executed as part of this command.
    ///
    /// The command buffers are submitted in the order in which they are added.
    #[inline]
    pub unsafe fn add_command_buffer<P>(&mut self, command_buffer: &'a UnsafeCommandBuffer<P>)
        where P: CommandPool
    {
        self.command_buffers.push(command_buffer.internal_object());
    }

    /// Returns the number of semaphores to signal.
    #[inline]
    pub fn num_signal_semaphores(&self) -> usize {
        self.signal_semaphores.len()
    }

    /// Adds a semaphore that is going to be signaled at the end of the submission.
    #[inline]
    pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) {
        self.signal_semaphores.push(semaphore.internal_object());
    }

    /// Submits the command buffer.
    pub fn submit(mut self, queue: &Queue) -> Result<(), SubmitCommandBufferError> {
        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();

            debug_assert_eq!(self.wait_semaphores.len(), self.dest_stages.len());

            let batch = vk::SubmitInfo {
                sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
                pNext: ptr::null(),
                waitSemaphoreCount: self.wait_semaphores.len() as u32,
                pWaitSemaphores: self.wait_semaphores.as_ptr(),
                pWaitDstStageMask: self.dest_stages.as_ptr(),
                commandBufferCount: self.command_buffers.len() as u32,
                pCommandBuffers: self.command_buffers.as_ptr(),
                signalSemaphoreCount: self.signal_semaphores.len() as u32,
                pSignalSemaphores: self.signal_semaphores.as_ptr(),
            };

            try!(check_errors(vk.QueueSubmit(*queue, 1, &batch, self.fence)));
            Ok(())
        }
    }

    /// Merges this builder with another builder.
    ///
    /// # Panic
    ///
    /// Panics if both builders have a fence already set.
    pub fn merge(mut self, other: Self) -> Self {
        assert!(self.fence == 0 || other.fence == 0);

        self.wait_semaphores.extend(other.wait_semaphores);
        self.dest_stages.extend(other.dest_stages);     // TODO: meh?
        self.signal_semaphores.extend(other.signal_semaphores);
        self.command_buffers.extend(other.command_buffers);

        if self.fence == 0 {
            self.fence = other.fence;
        }

        self
    }
}

/// Error that can happen when submitting the prototype.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SubmitCommandBufferError {
    /// Not enough memory.
    OomError(OomError),

    /// The connection to the device has been lost.
    DeviceLost,
}

impl error::Error for SubmitCommandBufferError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            SubmitCommandBufferError::OomError(_) => "not enough memory",
            SubmitCommandBufferError::DeviceLost => "the connection to the device has been lost",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SubmitCommandBufferError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for SubmitCommandBufferError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for SubmitCommandBufferError {
    #[inline]
    fn from(err: Error) -> SubmitCommandBufferError {
        match err {
            err @ Error::OutOfHostMemory => SubmitCommandBufferError::OomError(OomError::from(err)),
            err @ Error::OutOfDeviceMemory => SubmitCommandBufferError::OomError(OomError::from(err)),
            Error::DeviceLost => SubmitCommandBufferError::DeviceLost,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}
<commit_msg>Add test for merging two queue submits<commit_after>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::ptr;
use smallvec::SmallVec;

use command_buffer::cb::UnsafeCommandBuffer;
use command_buffer::pool::CommandPool;
use device::Queue;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Prototype for a submission that executes command buffers.
#[derive(Debug)]
pub struct SubmitCommandBufferBuilder<'a> {
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    dest_stages: SmallVec<[vk::PipelineStageFlags; 8]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 4]>,
    fence: vk::Fence,
    marker: PhantomData<&'a ()>,
}

impl<'a> SubmitCommandBufferBuilder<'a> {
    /// Builds a new empty `SubmitCommandBufferBuilder`.
    #[inline]
    pub fn new() -> SubmitCommandBufferBuilder<'a> {
        SubmitCommandBufferBuilder {
            wait_semaphores: SmallVec::new(),
            dest_stages: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            command_buffers: SmallVec::new(),
            fence: 0,
            marker: PhantomData,
        }
    }

    /// Returns true if this builder will signal a fence when submitted.
    #[inline]
    pub fn has_fence(&self) -> bool {
        self.fence != 0
    }

    /// Adds an operation that signals a fence after this submission ends.
    ///
    /// If a fence was previously set, it will no longer be signaled.
    #[inline]
    pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) {
        self.fence = fence.internal_object()
    }

    /// Adds a semaphore to be waited upon before the command buffers are executed.
    ///
    /// Only the given `stages` of the command buffers added afterwards will wait upon
    /// the semaphore. Other stages not included in `stages` can execute before waiting.
    #[inline]
    pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore, stages: PipelineStages) {
        debug_assert!(Into::<vk::PipelineStageFlagBits>::into(stages) != 0);
        self.wait_semaphores.push(semaphore.internal_object());
        self.dest_stages.push(stages.into());
    }

    /// Adds a command buffer that is executed as part of this command.
    ///
    /// The command buffers are submitted in the order in which they are added.
    #[inline]
    pub unsafe fn add_command_buffer<P>(&mut self, command_buffer: &'a UnsafeCommandBuffer<P>)
        where P: CommandPool
    {
        self.command_buffers.push(command_buffer.internal_object());
    }

    /// Returns the number of semaphores to signal.
    #[inline]
    pub fn num_signal_semaphores(&self) -> usize {
        self.signal_semaphores.len()
    }

    /// Adds a semaphore that is going to be signaled at the end of the submission.
    #[inline]
    pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) {
        self.signal_semaphores.push(semaphore.internal_object());
    }

    /// Submits the command buffer.
    pub fn submit(mut self, queue: &Queue) -> Result<(), SubmitCommandBufferError> {
        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();

            debug_assert_eq!(self.wait_semaphores.len(), self.dest_stages.len());

            let batch = vk::SubmitInfo {
                sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
                pNext: ptr::null(),
                waitSemaphoreCount: self.wait_semaphores.len() as u32,
                pWaitSemaphores: self.wait_semaphores.as_ptr(),
                pWaitDstStageMask: self.dest_stages.as_ptr(),
                commandBufferCount: self.command_buffers.len() as u32,
                pCommandBuffers: self.command_buffers.as_ptr(),
                signalSemaphoreCount: self.signal_semaphores.len() as u32,
                pSignalSemaphores: self.signal_semaphores.as_ptr(),
            };

            try!(check_errors(vk.QueueSubmit(*queue, 1, &batch, self.fence)));
            Ok(())
        }
    }

    /// Merges this builder with another builder.
    ///
    /// # Panic
    ///
    /// Panics if both builders have a fence already set.
    pub fn merge(mut self, other: Self) -> Self {
        assert!(self.fence == 0 || other.fence == 0,
               "Can't merge two queue submits that both have a fence");

        self.wait_semaphores.extend(other.wait_semaphores);
        self.dest_stages.extend(other.dest_stages);     // TODO: meh?
        self.signal_semaphores.extend(other.signal_semaphores);
        self.command_buffers.extend(other.command_buffers);

        if self.fence == 0 {
            self.fence = other.fence;
        }

        self
    }
}

/// Error that can happen when submitting the prototype.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SubmitCommandBufferError {
    /// Not enough memory.
    OomError(OomError),

    /// The connection to the device has been lost.
    DeviceLost,
}

impl error::Error for SubmitCommandBufferError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            SubmitCommandBufferError::OomError(_) => "not enough memory",
            SubmitCommandBufferError::DeviceLost => "the connection to the device has been lost",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SubmitCommandBufferError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for SubmitCommandBufferError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for SubmitCommandBufferError {
    #[inline]
    fn from(err: Error) -> SubmitCommandBufferError {
        match err {
            err @ Error::OutOfHostMemory => SubmitCommandBufferError::OomError(OomError::from(err)),
            err @ Error::OutOfDeviceMemory => SubmitCommandBufferError::OomError(OomError::from(err)),
            Error::DeviceLost => SubmitCommandBufferError::DeviceLost,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

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

    #[test]
    #[should_panic(expected = "Can't merge two queue submits that both have a fence")]
    fn merge_both_have_fences() {
        let (device, _) = gfx_dev_and_queue!();

        let fence1 = Fence::new(device.clone()).unwrap();
        let fence2 = Fence::new(device.clone()).unwrap();

        let mut builder1 = SubmitCommandBufferBuilder::new();
        unsafe { builder1.set_fence_signal(&fence1); }
        let mut builder2 = SubmitCommandBufferBuilder::new();
        unsafe { builder2.set_fence_signal(&fence2); }

        let _ = builder1.merge(builder2);
    }
}
<|endoftext|>


<commit_before>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`] type is a smart pointer type. There can only be one owner of a
//! [`Box`], and the owner can decide to mutate the contents, which live on the
//! heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`] type is a non-threadsafe reference-counted pointer type intended
//! for sharing memory within a thread. An [`Rc`] pointer wraps a type, `T`, and
//! only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using [`Box`]) is too
//! constraining for an application, and is often paired with the [`Cell`] or
//! [`RefCell`] types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`] type is the threadsafe equivalent of the [`Rc`] type. It
//! provides all the same functionality of [`Rc`], except it requires that the
//! contained type `T` is shareable. Additionally, [`Arc<T>`][`Arc`] is itself
//! sendable while [`Rc<T>`][`Rc`] is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.
//!
//! [`Arc`]: sync
//! [`Box`]: boxed
//! [`Cell`]: core::cell
//! [`Rc`]: rc
//! [`RefCell`]: core::cell

#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
#![no_std]
#![needs_allocator]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(btree_drain_filter)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_btree_new)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
#![feature(deque_range)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(container_error_extra)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_range_pattern)]
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
#![feature(internal_uninit_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(libc)]
#![feature(map_first_last)]
#![feature(map_into_keys_values)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(new_uninit)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(optin_builtin_traits)]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(min_specialization)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
#![feature(unsized_locals)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
pub mod borrow;
pub mod collections;
pub mod fmt;
pub mod prelude;
pub mod raw_vec;
pub mod rc;
pub mod slice;
pub mod str;
pub mod string;
#[cfg(target_has_atomic = "ptr")]
pub mod sync;
#[cfg(target_has_atomic = "ptr")]
pub mod task;
#[cfg(test)]
mod tests;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops; // RangeFull
}

#[doc(hidden)]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
pub mod __export {
    pub use core::format_args;
}
<commit_msg>remove unecessary feature flag<commit_after>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`] type is a smart pointer type. There can only be one owner of a
//! [`Box`], and the owner can decide to mutate the contents, which live on the
//! heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`] type is a non-threadsafe reference-counted pointer type intended
//! for sharing memory within a thread. An [`Rc`] pointer wraps a type, `T`, and
//! only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using [`Box`]) is too
//! constraining for an application, and is often paired with the [`Cell`] or
//! [`RefCell`] types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`] type is the threadsafe equivalent of the [`Rc`] type. It
//! provides all the same functionality of [`Rc`], except it requires that the
//! contained type `T` is shareable. Additionally, [`Arc<T>`][`Arc`] is itself
//! sendable while [`Rc<T>`][`Rc`] is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.
//!
//! [`Arc`]: sync
//! [`Box`]: boxed
//! [`Cell`]: core::cell
//! [`Rc`]: rc
//! [`RefCell`]: core::cell

#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
#![no_std]
#![needs_allocator]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(btree_drain_filter)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_btree_new)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
#![feature(deque_range)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(container_error_extra)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_range_pattern)]
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
#![feature(internal_uninit_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(libc)]
#![feature(map_first_last)]
#![feature(map_into_keys_values)]
#![feature(negative_impls)]
#![feature(new_uninit)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(optin_builtin_traits)]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(min_specialization)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
#![feature(unsized_locals)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
pub mod borrow;
pub mod collections;
pub mod fmt;
pub mod prelude;
pub mod raw_vec;
pub mod rc;
pub mod slice;
pub mod str;
pub mod string;
#[cfg(target_has_atomic = "ptr")]
pub mod sync;
#[cfg(target_has_atomic = "ptr")]
pub mod task;
#[cfg(test)]
mod tests;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops; // RangeFull
}

#[doc(hidden)]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
pub mod __export {
    pub use core::format_args;
}
<|endoftext|>


<commit_before>use std::mem;
use panic::*;
use std::ptr::RawPtr;
use std::mem::{transmute, size_of};

static IDT_SIZE: uint = 256;

#[packed]
struct IDTEntry {
  offset_lower: u16, // offset bits 0..15
  selector: u16, // a code segment selector in GDT or LDT
  zero: u8,      // unused, set to 0
  type_attr: u8, // type and attributes, see below
  offset_upper: u16 // offset bits 16..31
}

impl IDTEntry {

  fn new(f: unsafe extern "C" fn() -> ()) -> IDTEntry {
    unsafe {
      let (lower, upper): (u16, u16) = transmute(f);
      IDTEntry { offset_lower: lower, selector: 0x08, zero: 0, type_attr: 0x8E, offset_upper: upper }
    }
  }

  fn no_op() -> IDTEntry {
    IDTEntry::new(test)
  }

}

extern "C" {
  fn no_op() -> ();

  fn test() -> ();

  fn register_all_callbacks(idt: &mut IDT);

  fn callback_0();

  fn debug(s: &str, u: u32) -> ();
}

#[packed]
struct IDTLayout {
  limit: u16,
  base: u32
}

// TODO(ryan) this should be allocated for two reasons:
// 1. It's really big (256 * 8 == 2 KB)
// 2. Its location in memory needs to stay the same
pub struct IDT {
  table: Vec<IDTEntry>
}

impl IDT {

  pub fn new() -> IDT {
    let mut me = IDT { table: Vec::from_fn(IDT_SIZE, |_| IDTEntry::no_op() ) };
    /*unsafe {
      raw =
      register_all_callbacks(&mut me.table.);

    }*/
    me
  }

  pub fn add_entry(&mut self, index: u32, f: unsafe extern "C" fn() -> ()) {
    *self.table.get_mut(index as uint) =  IDTEntry::new(f);
  }

  pub unsafe fn enable(&mut self) {
    let (base, _): (u32, u32) = transmute(self.table.as_slice());
    let limit: u16 = (self.table.len() * size_of::<IDTEntry>()) as u16;
    let layout = IDTLayout { base: base, limit: limit};
    asm!("lidt ($0)"
	:
	:"{eax}"(&layout)
	:
	:
	:"volatile");
  }

  pub fn disable_interrupts() {
    unsafe { asm!("cli" :::: "volatile"); }
  }

  pub unsafe fn enable_interrupts() {
    asm!("sti" :::: "volatile");
  }

  pub fn len(&self) -> uint {
    return self.table.len();
  }

}
<commit_msg>~ fullways to making IDT use dynamic memory allocation via Vec<commit_after>use std::mem;
use panic::*;
use std::ptr::RawPtr;
use std::mem::{transmute, size_of};

static IDT_SIZE: uint = 256;

#[packed]
struct IDTEntry {
  offset_lower: u16, // offset bits 0..15
  selector: u16, // a code segment selector in GDT or LDT
  zero: u8,      // unused, set to 0
  type_attr: u8, // type and attributes, see below
  offset_upper: u16 // offset bits 16..31
}

impl IDTEntry {

  fn new(f: unsafe extern "C" fn() -> ()) -> IDTEntry {
    unsafe {
      let (lower, upper): (u16, u16) = transmute(f);
      IDTEntry { offset_lower: lower, selector: 0x08, zero: 0, type_attr: 0x8E, offset_upper: upper }
    }
  }

  fn no_op() -> IDTEntry {
    IDTEntry::new(test)
  }

}

extern "C" {
  fn no_op() -> ();

  fn test() -> ();

  fn register_all_callbacks(idt: &mut IDT);

  fn callback_0();

  fn debug(s: &str, u: u32) -> ();
}

#[packed]
struct IDTLayout {
  limit: u16,
  base: u32
}

// TODO(ryan) this should be allocated for two reasons:
// 1. It's really big (256 * 8 == 2 KB)
// 2. Its location in memory needs to stay the same
pub struct IDT {
  table: Vec<IDTEntry>
}

impl IDT {

  pub fn new() -> IDT {
    let mut me = IDT { table: Vec::from_fn(IDT_SIZE, |_| IDTEntry::no_op() ) };
    unsafe {
      register_all_callbacks(&mut me);
    }
    me
  }

  pub fn add_entry(&mut self, index: u32, f: unsafe extern "C" fn() -> ()) {
    *self.table.get_mut(index as uint) =  IDTEntry::new(f);
  }

  pub unsafe fn enable(&mut self) {
    let (base, _): (u32, u32) = transmute(self.table.as_slice());
    let limit: u16 = (self.table.len() * size_of::<IDTEntry>()) as u16;
    let layout = IDTLayout { base: base, limit: limit};
    asm!("lidt ($0)"
	:
	:"{eax}"(&layout)
	:
	:
	:"volatile");
  }

  pub fn disable_interrupts() {
    unsafe { asm!("cli" :::: "volatile"); }
  }

  pub unsafe fn enable_interrupts() {
    asm!("sti" :::: "volatile");
  }

  pub fn len(&self) -> uint {
    return self.table.len();
  }

}
<|endoftext|>


<commit_before>//! Encoding and decoding of little-endian format.
//!
//! This was created out of fustration with the `byteorder` crate, which I felt had a heavy API, so
//! I created this crate.

#![feature(i128_type)]

/// Read an integer from a buffer.
///
/// This writes `buf` through the methods in `T`'s implementation of `Decode`.
pub fn read<T: Decode>(buf: &[u8]) -> T {
    T::read_le(buf)
}

/// Write some integer into a buffer.
///
/// This writes `from` into `buf` through the methods in `T`'s implementation of `Encode`.
pub fn write<T: Encode>(buf: &mut [u8], from: T) {
    from.write_le(buf)
}

/// An encodable type.
pub trait Encode {
    /// Write an integer in little-endian format.
    ///
    /// This writes `self` into the first n bytes (depending on the size of `Self`) of `into` in
    /// little-endian format (least significant byte first).
    ///
    /// # Panics
    ///
    /// This will potentially panic if `into` is not large enough.
    fn write_le(self, into: &mut [u8]);
}

/// A decodable type.
pub trait Decode {
    /// Read an integer in little-endian format.
    ///
    /// This reads the first n bytes (depending on the size of `Self`) of `from` in little-endian
    /// (least significant byte first).
    ///
    /// # Panics
    ///
    /// This will potentially panic if `from` is not large enough.
    fn read_le(from: &[u8]) -> Self;
}

impl Decode for u8 {
    fn read_le(from: &[u8]) -> u8 {
        from[0]
    }
}
impl Encode for u8 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self;
    }
}

impl Decode for u16 {
    fn read_le(from: &[u8]) -> u16 {
        from[0] as u16
            | (from[1] as u16) << 8
    }
}
impl Encode for u16 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
    }
}

impl Decode for u32 {
    fn read_le(from: &[u8]) -> u32 {
        from[0] as u32
            | (from[1] as u32) << 8
            | (from[2] as u32) << 16
            | (from[3] as u32) << 24
    }
}
impl Encode for u32 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
        into[2] = (self >> 16) as u8;
        into[3] = (self >> 24) as u8;
    }
}

impl Decode for u64 {
    fn read_le(from: &[u8]) -> u64 {
        from[0] as u64
            | (from[1] as u64) << 8
            | (from[2] as u64) << 16
            | (from[3] as u64) << 24
            | (from[4] as u64) << 32
            | (from[5] as u64) << 40
            | (from[6] as u64) << 48
            | (from[7] as u64) << 56
    }
}
impl Encode for u64 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
        into[2] = (self >> 16) as u8;
        into[3] = (self >> 24) as u8;
        into[4] = (self >> 32) as u8;
        into[5] = (self >> 40) as u8;
        into[6] = (self >> 48) as u8;
        into[7] = (self >> 56) as u8;
    }
}

impl Decode for u128 {
    fn read_le(from: &[u8]) -> u128 {
        from[0] as u128
            | (from[1] as u128) << 8
            | (from[2] as u128) << 16
            | (from[3] as u128) << 24
            | (from[4] as u128) << 32
            | (from[5] as u128) << 40
            | (from[6] as u128) << 48
            | (from[7] as u128) << 56
            | (from[8] as u128) << 64
            | (from[9] as u128) << 72
            | (from[10] as u128) << 80
            | (from[11] as u128) << 88
            | (from[12] as u128) << 96
            | (from[13] as u128) << 104
            | (from[14] as u128) << 112
            | (from[15] as u128) << 120
    }
}
impl Encode for u128 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
        into[2] = (self >> 16) as u8;
        into[3] = (self >> 24) as u8;
        into[4] = (self >> 32) as u8;
        into[5] = (self >> 40) as u8;
        into[6] = (self >> 48) as u8;
        into[7] = (self >> 56) as u8;
        into[8] = (self >> 64) as u8;
        into[9] = (self >> 72) as u8;
        into[10] = (self >> 80) as u8;
        into[11] = (self >> 88) as u8;
        into[12] = (self >> 96) as u8;
        into[13] = (self >> 104) as u8;
        into[14] = (self >> 112) as u8;
        into[15] = (self >> 120) as u8;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::{ops, mem, fmt};

    fn test_int<T>(n: T)
    where T: Encode + Decode + Copy + PartialEq + From<u8> + fmt::Debug
        + ops::BitAnd<T, Output = T> + ops::Shr<T, Output = T>,
    {
        let len = mem::size_of::<T>();
        let mut buf = [0; 32];
        write(&mut buf, n);

        for i in 0..len {
            assert_eq!(T::from(buf[i]), (n >> T::from(i as u8 * 8)) & T::from(0xFF));
        }

        assert_eq!(read::<T>(&buf), n);
    }

    #[test]
    fn u8() {
        test_int(12u8);
        test_int(1u8);
        test_int(0u8);
    }

    #[test]
    fn u16() {
        test_int::<u16>(0xAB);
        test_int::<u16>(0xBA);
        test_int::<u16>(0);
    }

    #[test]
    fn u32() {
        test_int::<u32>(0xABCD);
        test_int::<u32>(0xDCBA);
        test_int::<u32>(0);
    }

    #[test]
    fn u64() {
        test_int::<u64>(0xABCDEF0);
        test_int::<u64>(0x0FEDCBA);
        test_int::<u64>(0);
    }

    #[test]
    fn u128() {
        test_int::<u128>(0xABCDEF012345678);
        test_int::<u128>(0x876543210FEDCBA);
        test_int::<u128>(0);
    }
}
<commit_msg>- Added little-endian tests for each unsigned integer max value.<commit_after>//! Encoding and decoding of little-endian format.
//!
//! This was created out of fustration with the `byteorder` crate, which I felt had a heavy API, so
//! I created this crate.

#![feature(i128_type)]

/// Read an integer from a buffer.
///
/// This writes `buf` through the methods in `T`'s implementation of `Decode`.
pub fn read<T: Decode>(buf: &[u8]) -> T {
    T::read_le(buf)
}

/// Write some integer into a buffer.
///
/// This writes `from` into `buf` through the methods in `T`'s implementation of `Encode`.
pub fn write<T: Encode>(buf: &mut [u8], from: T) {
    from.write_le(buf)
}

/// An encodable type.
pub trait Encode {
    /// Write an integer in little-endian format.
    ///
    /// This writes `self` into the first n bytes (depending on the size of `Self`) of `into` in
    /// little-endian format (least significant byte first).
    ///
    /// # Panics
    ///
    /// This will potentially panic if `into` is not large enough.
    fn write_le(self, into: &mut [u8]);
}

/// A decodable type.
pub trait Decode {
    /// Read an integer in little-endian format.
    ///
    /// This reads the first n bytes (depending on the size of `Self`) of `from` in little-endian
    /// (least significant byte first).
    ///
    /// # Panics
    ///
    /// This will potentially panic if `from` is not large enough.
    fn read_le(from: &[u8]) -> Self;
}

impl Decode for u8 {
    fn read_le(from: &[u8]) -> u8 {
        from[0]
    }
}
impl Encode for u8 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self;
    }
}

impl Decode for u16 {
    fn read_le(from: &[u8]) -> u16 {
        from[0] as u16
            | (from[1] as u16) << 8
    }
}
impl Encode for u16 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
    }
}

impl Decode for u32 {
    fn read_le(from: &[u8]) -> u32 {
        from[0] as u32
            | (from[1] as u32) << 8
            | (from[2] as u32) << 16
            | (from[3] as u32) << 24
    }
}
impl Encode for u32 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
        into[2] = (self >> 16) as u8;
        into[3] = (self >> 24) as u8;
    }
}

impl Decode for u64 {
    fn read_le(from: &[u8]) -> u64 {
        from[0] as u64
            | (from[1] as u64) << 8
            | (from[2] as u64) << 16
            | (from[3] as u64) << 24
            | (from[4] as u64) << 32
            | (from[5] as u64) << 40
            | (from[6] as u64) << 48
            | (from[7] as u64) << 56
    }
}
impl Encode for u64 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
        into[2] = (self >> 16) as u8;
        into[3] = (self >> 24) as u8;
        into[4] = (self >> 32) as u8;
        into[5] = (self >> 40) as u8;
        into[6] = (self >> 48) as u8;
        into[7] = (self >> 56) as u8;
    }
}

impl Decode for u128 {
    fn read_le(from: &[u8]) -> u128 {
        from[0] as u128
            | (from[1] as u128) << 8
            | (from[2] as u128) << 16
            | (from[3] as u128) << 24
            | (from[4] as u128) << 32
            | (from[5] as u128) << 40
            | (from[6] as u128) << 48
            | (from[7] as u128) << 56
            | (from[8] as u128) << 64
            | (from[9] as u128) << 72
            | (from[10] as u128) << 80
            | (from[11] as u128) << 88
            | (from[12] as u128) << 96
            | (from[13] as u128) << 104
            | (from[14] as u128) << 112
            | (from[15] as u128) << 120
    }
}
impl Encode for u128 {
    fn write_le(self, into: &mut [u8]) {
        into[0] = self as u8;
        into[1] = (self >> 8) as u8;
        into[2] = (self >> 16) as u8;
        into[3] = (self >> 24) as u8;
        into[4] = (self >> 32) as u8;
        into[5] = (self >> 40) as u8;
        into[6] = (self >> 48) as u8;
        into[7] = (self >> 56) as u8;
        into[8] = (self >> 64) as u8;
        into[9] = (self >> 72) as u8;
        into[10] = (self >> 80) as u8;
        into[11] = (self >> 88) as u8;
        into[12] = (self >> 96) as u8;
        into[13] = (self >> 104) as u8;
        into[14] = (self >> 112) as u8;
        into[15] = (self >> 120) as u8;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::{ops, mem, fmt};

    fn test_int<T>(n: T)
    where T: Encode + Decode + Copy + PartialEq + From<u8> + fmt::Debug
        + ops::BitAnd<T, Output = T> + ops::Shr<T, Output = T>,
    {
        let len = mem::size_of::<T>();
        let mut buf = [0; 32];
        write(&mut buf, n);

        for i in 0..len {
            assert_eq!(T::from(buf[i]), (n >> T::from(i as u8 * 8)) & T::from(0xFF));
        }

        assert_eq!(read::<T>(&buf), n);
    }

    #[test]
    fn u8() {
        test_int(255u8);
        test_int(130u8);
        test_int(12u8);
        test_int(1u8);
        test_int(0u8);
    }

    #[test]
    fn u16() {
        test_int::<u16>(0xFFFF);
        test_int::<u16>(0xABCD);
        test_int::<u16>(0xAB);
        test_int::<u16>(0xBA);
        test_int::<u16>(0);
    }

    #[test]
    fn u32() {
        test_int::<u32>(0xFFFFFFFF);
        test_int::<u32>(0xABCDEF01);
        test_int::<u32>(0xABCD);
        test_int::<u32>(0xDCBA);
        test_int::<u32>(0);
    }

    #[test]
    fn u64() {
        test_int::<u64>(0xFFFFFFFFFFFFFFFF);
        test_int::<u64>(0xABCDEF0123456789);
        test_int::<u64>(0xABCDEF0);
        test_int::<u64>(0x0FEDCBA);
        test_int::<u64>(0);
    }

    #[test]
    fn u128() {
        test_int::<u128>(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        test_int::<u128>(0xABCDEF0123456789ABCDEF0123456789);
        test_int::<u128>(0xABCDEF012345678);
        test_int::<u128>(0x876543210FEDCBA);
        test_int::<u128>(0);
    }
}
<|endoftext|>


<commit_before>use types::*;

use serde_json::Value;

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPValue {
    Boolean(Boolean),
    ShortShortInt(ShortShortInt),
    ShortShortUInt(ShortShortUInt),
    ShortInt(ShortInt),
    ShortUInt(ShortUInt),
    LongInt(LongInt),
    LongUInt(LongUInt),
    LongLongInt(LongLongInt),
    LongLongUInt(LongLongUInt),
    Float(Float),
    Double(Double),
    DecimalValue(DecimalValue),
    ShortString(ShortString),
    LongString(LongString),
    FieldArray(FieldArray),
    Timestamp(Timestamp),
    FieldTable(FieldTable),
    Void,
}

impl AMQPValue {
    pub fn get_type(&self) -> AMQPType {
        match *self {
            AMQPValue::Boolean(_)        => AMQPType::Boolean,
            AMQPValue::ShortShortInt(_)  => AMQPType::ShortShortInt,
            AMQPValue::ShortShortUInt(_) => AMQPType::ShortShortUInt,
            AMQPValue::ShortInt(_)       => AMQPType::ShortInt,
            AMQPValue::ShortUInt(_)      => AMQPType::ShortUInt,
            AMQPValue::LongInt(_)        => AMQPType::LongInt,
            AMQPValue::LongUInt(_)       => AMQPType::LongUInt,
            AMQPValue::LongLongInt(_)    => AMQPType::LongLongInt,
            AMQPValue::LongLongUInt(_)   => AMQPType::LongLongUInt,
            AMQPValue::Float(_)          => AMQPType::Float,
            AMQPValue::Double(_)         => AMQPType::Double,
            AMQPValue::DecimalValue(_)   => AMQPType::DecimalValue,
            AMQPValue::ShortString(_)    => AMQPType::ShortString,
            AMQPValue::LongString(_)     => AMQPType::LongString,
            AMQPValue::FieldArray(_)     => AMQPType::FieldArray,
            AMQPValue::Timestamp(_)      => AMQPType::Timestamp,
            AMQPValue::FieldTable(_)     => AMQPType::FieldTable,
            AMQPValue::Void              => AMQPType::Void,
        }
    }
}

impl From<Value> for AMQPValue {
    fn from(v: Value) -> AMQPValue {
        From::from(&v)
    }
}

impl<'a> From<&'a Value> for AMQPValue {
    fn from(v: &Value) -> AMQPValue {
        match *v {
            Value::Bool(ref b)   => AMQPValue::Boolean(*b),
            Value::Number(ref n) => {
                if n.is_u64() {
                    AMQPValue::LongLongUInt(n.as_u64().unwrap())
                } else if n.is_i64() {
                    AMQPValue::LongLongInt(n.as_i64().unwrap())
                } else {
                    AMQPValue::Double(n.as_f64().unwrap())
                }
            },
            Value::String(ref s) => AMQPValue::LongString(s.clone()),
            Value::Array(ref v)  => AMQPValue::FieldArray(v.iter().map(From::from).collect()),
            Value::Object(ref o) => AMQPValue::FieldTable(o.iter().fold(FieldTable::new(), |mut table, (k, v)| {
                table.insert(k.clone(), From::from(v));
                table
            })),
            Value::Null          => AMQPValue::Void,
        }
    }
}
<commit_msg>types: add tests for value to AMQPValue conversion<commit_after>use types::*;

use serde_json::Value;

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum AMQPValue {
    Boolean(Boolean),
    ShortShortInt(ShortShortInt),
    ShortShortUInt(ShortShortUInt),
    ShortInt(ShortInt),
    ShortUInt(ShortUInt),
    LongInt(LongInt),
    LongUInt(LongUInt),
    LongLongInt(LongLongInt),
    LongLongUInt(LongLongUInt),
    Float(Float),
    Double(Double),
    DecimalValue(DecimalValue),
    ShortString(ShortString),
    LongString(LongString),
    FieldArray(FieldArray),
    Timestamp(Timestamp),
    FieldTable(FieldTable),
    Void,
}

impl AMQPValue {
    pub fn get_type(&self) -> AMQPType {
        match *self {
            AMQPValue::Boolean(_)        => AMQPType::Boolean,
            AMQPValue::ShortShortInt(_)  => AMQPType::ShortShortInt,
            AMQPValue::ShortShortUInt(_) => AMQPType::ShortShortUInt,
            AMQPValue::ShortInt(_)       => AMQPType::ShortInt,
            AMQPValue::ShortUInt(_)      => AMQPType::ShortUInt,
            AMQPValue::LongInt(_)        => AMQPType::LongInt,
            AMQPValue::LongUInt(_)       => AMQPType::LongUInt,
            AMQPValue::LongLongInt(_)    => AMQPType::LongLongInt,
            AMQPValue::LongLongUInt(_)   => AMQPType::LongLongUInt,
            AMQPValue::Float(_)          => AMQPType::Float,
            AMQPValue::Double(_)         => AMQPType::Double,
            AMQPValue::DecimalValue(_)   => AMQPType::DecimalValue,
            AMQPValue::ShortString(_)    => AMQPType::ShortString,
            AMQPValue::LongString(_)     => AMQPType::LongString,
            AMQPValue::FieldArray(_)     => AMQPType::FieldArray,
            AMQPValue::Timestamp(_)      => AMQPType::Timestamp,
            AMQPValue::FieldTable(_)     => AMQPType::FieldTable,
            AMQPValue::Void              => AMQPType::Void,
        }
    }
}

impl From<Value> for AMQPValue {
    fn from(v: Value) -> AMQPValue {
        From::from(&v)
    }
}

impl<'a> From<&'a Value> for AMQPValue {
    fn from(v: &Value) -> AMQPValue {
        match *v {
            Value::Bool(ref b)   => AMQPValue::Boolean(*b),
            Value::Number(ref n) => {
                if n.is_u64() {
                    AMQPValue::LongLongUInt(n.as_u64().unwrap())
                } else if n.is_i64() {
                    AMQPValue::LongLongInt(n.as_i64().unwrap())
                } else {
                    AMQPValue::Double(n.as_f64().unwrap())
                }
            },
            Value::String(ref s) => AMQPValue::LongString(s.clone()),
            Value::Array(ref v)  => AMQPValue::FieldArray(v.iter().map(From::from).collect()),
            Value::Object(ref o) => AMQPValue::FieldTable(o.iter().fold(FieldTable::new(), |mut table, (k, v)| {
                table.insert(k.clone(), From::from(v));
                table
            })),
            Value::Null          => AMQPValue::Void,
        }
    }
}

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

    use serde_json::{map, Number};

    #[test]
    fn test_from_bool_value() {
        assert_eq!(AMQPValue::from(Value::Bool(false)), AMQPValue::Boolean(false));
        assert_eq!(AMQPValue::from(Value::Bool(true)),  AMQPValue::Boolean(true));
    }

    #[test]
    fn test_from_number_value() {
        assert_eq!(AMQPValue::from(Value::Number(Number::from(42))),                 AMQPValue::LongLongUInt(42));
        assert_eq!(AMQPValue::from(Value::Number(Number::from(-42))),                AMQPValue::LongLongInt(-42));
        assert_eq!(AMQPValue::from(Value::Number(Number::from_f64(42.42).unwrap())), AMQPValue::Double(42.42));
    }

    #[test]
    fn test_from_string_value() {
        assert_eq!(AMQPValue::from(Value::String(String::new())),      AMQPValue::LongString(String::new()));
        assert_eq!(AMQPValue::from(Value::String("test".to_string())), AMQPValue::LongString("test".to_string()));
    }

    #[test]
    fn test_from_array_value() {
        assert_eq!(AMQPValue::from(Value::Array(Vec::new())),        AMQPValue::FieldArray(FieldArray::new()));
        assert_eq!(AMQPValue::from(Value::Array(vec![Value::Null])), AMQPValue::FieldArray(vec![AMQPValue::Void]));
    }

    #[test]
    fn test_from_object_value() {
        let mut value_map = map::Map::new();
        let mut table     = FieldTable::new();

        value_map.insert("test".to_string(), Value::Null);
        table.insert("test".to_string(), AMQPValue::Void);

        assert_eq!(AMQPValue::from(Value::Object(map::Map::new())), AMQPValue::FieldTable(FieldTable::new()));
        assert_eq!(AMQPValue::from(Value::Object(value_map)),       AMQPValue::FieldTable(table));
    }

    #[test]
    fn test_from_null_value() {
        assert_eq!(AMQPValue::from(Value::Null), AMQPValue::Void);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use std;
use std::io;
use std::sync::Arc;
use std::time::Duration;

use futures::{Async, Future, Poll, Stream};
use openssl::pkcs12::ParsedPkcs12;
use openssl::ssl;
use openssl::ssl::{SslAcceptorBuilder, SslMethod};
use tokio_core;
use tokio_core::reactor::Core;
use tokio_openssl::SslAcceptorExt;

use trust_dns::udp::UdpStream;
use trust_dns::tcp::TcpStream;
use trust_dns::tls::TlsStream;

use server::{Request, RequestHandler, RequestStream, ResponseHandle, TimeoutStream};
use authority::Catalog;

// TODO, would be nice to have a Slab for buffers here...

/// A Futures based implementation of a DNS catalog server
pub struct ServerFuture {
    io_loop: Core,
    catalog: Arc<Catalog>, // should the catalog just be static?
}

impl ServerFuture {
    /// Creates a new ServerFuture with the specified Catalog of Zones.
    pub fn new(catalog: Catalog) -> io::Result<ServerFuture> {
        Ok(ServerFuture {
               io_loop: try!(Core::new()),
               catalog: Arc::new(catalog),
           })
    }

    /// Register a UDP socket. Should be bound before calling this function.
    pub fn register_socket(&self, socket: std::net::UdpSocket) {
        debug!("registered udp: {:?}", socket);

        // create the new UdpStream
        let (buf_stream, stream_handle) = UdpStream::with_bound(socket, self.io_loop.handle());
        let request_stream = RequestStream::new(buf_stream, stream_handle);
        let catalog = self.catalog.clone();

        // this spawns a ForEach future which handles all the requests into a Catalog.
        self.io_loop
            .handle()
            .spawn(// TODO dedup with below into generic func
                   request_stream
                       .for_each(move |(request, response_handle)| {
                                     Self::handle_request(request, response_handle, catalog.clone())
                                 })
                       .map_err(|e| debug!("error in UDP request_stream handler: {}", e)));
    }

    /// Register a TcpListener to the Server. This should already be bound to either an IPv6 or an
    ///  IPv4 address.
    ///
    /// To make the server more resilient to DOS issues, there is a timeout. Care should be taken
    ///  to not make this too low depending on use cases.
    ///
    /// # Arguments
    /// * `listener` - a bound TCP socket
    /// * `timeout` - timeout duration of incoming requests, any connection that does not send
    ///               requests within this time period will be closed. In the future it should be
    ///               possible to create long-lived queries, but these should be from trusted sources
    ///               only, this would require some type of whitelisting.
    pub fn register_listener(&self,
                             listener: std::net::TcpListener,
                             timeout: Duration)
                             -> io::Result<()> {
        let handle = self.io_loop.handle();
        let catalog = self.catalog.clone();
        // TODO: this is an awkward interface with socketaddr...
        let addr = try!(listener.local_addr());
        let listener = tokio_core::net::TcpListener::from_listener(listener, &addr, &handle)
            .expect("could not register listener");
        debug!("registered tcp: {:?}", listener);

        // for each incoming request...
        self.io_loop
            .handle()
            .spawn(listener
                       .incoming()
                       .for_each(move |(tcp_stream, src_addr)| {
                debug!("accepted request from: {}", src_addr);
                // take the created stream...
                let (buf_stream, stream_handle) = TcpStream::from_stream(tcp_stream, src_addr);
                let timeout_stream = try!(TimeoutStream::new(buf_stream, timeout, handle.clone()));
                let request_stream = RequestStream::new(timeout_stream, stream_handle);
                let catalog = catalog.clone();

                // and spawn to the io_loop
                handle.spawn(request_stream.for_each(move |(request, response_handle)| {
                        Self::handle_request(request, response_handle, catalog.clone())
                    })
                    .map_err(move |e| {
                        debug!("error in TCP request_stream src: {:?} error: {}",
                               src_addr,
                               e)
                    }));

                Ok(())
            })
                       .map_err(|e| debug!("error in inbound tcp_stream: {}", e)));

        Ok(())
    }

    /// Register a TlsListener to the Server. The TlsListener should already be bound to either an
    /// IPv6 or an IPv4 address.
    ///
    /// To make the server more resilient to DOS issues, there is a timeout. Care should be taken
    ///  to not make this too low depending on use cases.
    ///
    /// # Arguments
    /// * `listener` - a bound TCP (needs to be on a different port from standard TCP connections) socket
    /// * `timeout` - timeout duration of incoming requests, any connection that does not send
    ///               requests within this time period will be closed. In the future it should be
    ///               possible to create long-lived queries, but these should be from trusted sources
    ///               only, this would require some type of whitelisting.
    /// * `pkcs12` - certificate used to announce to clients
    pub fn register_tls_listener(&self,
                                 listener: std::net::TcpListener,
                                 timeout: Duration,
                                 pkcs12: ParsedPkcs12)
                                 -> io::Result<()> {
        let handle = self.io_loop.handle();
        let catalog = self.catalog.clone();
        // TODO: this is an awkward interface with socketaddr...
        let addr = listener.local_addr().expect("listener is not bound?");
        let listener = tokio_core::net::TcpListener::from_listener(listener, &addr, &handle)
            .expect("could not register listener");
        debug!("registered tcp: {:?}", listener);

        let mut builder = try!(SslAcceptorBuilder::mozilla_modern(SslMethod::tls(),
                                                                  &pkcs12.pkey,
                                                                  &pkcs12.cert,
                                                                  &pkcs12.chain)
                                       .map_err(|e| {
                                                    io::Error::new(io::ErrorKind::ConnectionRefused,
                                                                   format!("tls error: {}", e))
                                                }));

        // mut block
        {
            let ssl_context_bldr = builder.builder_mut();

            ssl_context_bldr.set_options(ssl::SSL_OP_NO_SSLV2 | ssl::SSL_OP_NO_SSLV3 |
                                         ssl::SSL_OP_NO_TLSV1 |
                                         ssl::SSL_OP_NO_TLSV1_1);
        }

        let tls_acceptor = builder.build();

        // for each incoming request...
        self.io_loop.handle().spawn(
        listener.incoming()
                .for_each(move |(tcp_stream, src_addr)| {
                  debug!("accepted request from: {}", src_addr);
                  let timeout = timeout.clone();
                  let handle = handle.clone();
                  let catalog = catalog.clone();

                  // take the created stream...
                  tls_acceptor.accept_async(tcp_stream)
                              .map_err(|e| io::Error::new(io::ErrorKind::ConnectionRefused, format!("tls error: {}", e)))
                              .and_then(move |tls_stream| {
                                  let (buf_stream, stream_handle) = TlsStream::from_stream(tls_stream, src_addr.clone());
                                  let timeout_stream = try!(TimeoutStream::new(buf_stream, timeout, handle.clone()));
                                  let request_stream = RequestStream::new(timeout_stream, stream_handle);
                                  let catalog = catalog.clone();

                                  // and spawn to the io_loop
                                  handle.spawn(
                                  request_stream.for_each(move |(request, response_handle)| {
                                      Self::handle_request(request, response_handle, catalog.clone())
                                  })
                              .map_err(move |e| debug!("error in TCP request_stream src: {:?} error: {}", src_addr, e))
                              );

                              Ok(())
                            })
                            //.map_err(move |e| debug!("error TLS handshake: {:?} error: {:?}", src_addr, e))
              })
              .map_err(|e| debug!("error in inbound tcp_stream: {}", e))
    );

        Ok(())
    }

    /// TODO how to do threads? should we do a bunch of listener threads and then query threads?
    /// Ideally the processing would be n-threads for recieving, which hand off to m-threads for
    ///  request handling. It would generally be the case that n <= m.
    pub fn listen(&mut self) -> io::Result<()> {
        info!("Server starting up");
        try!(self.io_loop.run(Forever));

        Err(io::Error::new(io::ErrorKind::Interrupted,
                           "Server stopping due to interruption"))
    }

    /// Returns a reference to the tokio core loop driving this Server instance
    pub fn tokio_core(&mut self) -> &mut Core {
        &mut self.io_loop
    }

    fn handle_request(request: Request,
                      mut response_handle: ResponseHandle,
                      catalog: Arc<Catalog>)
                      -> io::Result<()> {
        let response = catalog.handle_request(&request);
        response_handle.send(response)
    }
}

struct Forever;

impl Future for Forever {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // run forever...
        Ok(Async::NotReady)
    }
}
<commit_msg>Make ServerFuture generic over T: RequestHandler.<commit_after>// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use std;
use std::io;
use std::sync::Arc;
use std::time::Duration;

use futures::{Async, Future, Poll, Stream};
use openssl::pkcs12::ParsedPkcs12;
use openssl::ssl;
use openssl::ssl::{SslAcceptorBuilder, SslMethod};
use tokio_core;
use tokio_core::reactor::Core;
use tokio_openssl::SslAcceptorExt;

use trust_dns::udp::UdpStream;
use trust_dns::tcp::TcpStream;
use trust_dns::tls::TlsStream;

use server::{Request, RequestHandler, RequestStream, ResponseHandle, TimeoutStream};

// TODO, would be nice to have a Slab for buffers here...

/// A Futures based implementation of a DNS server
pub struct ServerFuture<T: RequestHandler + 'static> {
    io_loop: Core,
    handler: Arc<T>
}

impl <T: RequestHandler> ServerFuture <T> {
    /// Creates a new ServerFuture with the specified Handler.
    pub fn new(handler: T) -> io::Result<ServerFuture<T>> {
        Ok(ServerFuture {
               io_loop: try!(Core::new()),
               handler: Arc::new(handler),
           })
    }

    /// Register a UDP socket. Should be bound before calling this function.
    pub fn register_socket(&self, socket: std::net::UdpSocket) {
        debug!("registered udp: {:?}", socket);

        // create the new UdpStream
        let (buf_stream, stream_handle) = UdpStream::with_bound(socket, self.io_loop.handle());
        let request_stream = RequestStream::new(buf_stream, stream_handle);
        let handler = self.handler.clone();

        // this spawns a ForEach future which handles all the requests into a Handler.
        self.io_loop
            .handle()
            .spawn(// TODO dedup with below into generic func
                   request_stream
                       .for_each(move |(request, response_handle)| {
                                     Self::handle_request(request, response_handle, handler.clone())
                                 })
                       .map_err(|e| debug!("error in UDP request_stream handler: {}", e)));
    }

    /// Register a TcpListener to the Server. This should already be bound to either an IPv6 or an
    ///  IPv4 address.
    ///
    /// To make the server more resilient to DOS issues, there is a timeout. Care should be taken
    ///  to not make this too low depending on use cases.
    ///
    /// # Arguments
    /// * `listener` - a bound TCP socket
    /// * `timeout` - timeout duration of incoming requests, any connection that does not send
    ///               requests within this time period will be closed. In the future it should be
    ///               possible to create long-lived queries, but these should be from trusted sources
    ///               only, this would require some type of whitelisting.
    pub fn register_listener(&self,
                             listener: std::net::TcpListener,
                             timeout: Duration)
                             -> io::Result<()> {
        let handle = self.io_loop.handle();
        let handler = self.handler.clone();
        // TODO: this is an awkward interface with socketaddr...
        let addr = try!(listener.local_addr());
        let listener = tokio_core::net::TcpListener::from_listener(listener, &addr, &handle)
            .expect("could not register listener");
        debug!("registered tcp: {:?}", listener);

        // for each incoming request...
        self.io_loop
            .handle()
            .spawn(listener
                       .incoming()
                       .for_each(move |(tcp_stream, src_addr)| {
                debug!("accepted request from: {}", src_addr);
                // take the created stream...
                let (buf_stream, stream_handle) = TcpStream::from_stream(tcp_stream, src_addr);
                let timeout_stream = try!(TimeoutStream::new(buf_stream, timeout, handle.clone()));
                let request_stream = RequestStream::new(timeout_stream, stream_handle);
                let handler = handler.clone();

                // and spawn to the io_loop
                handle.spawn(request_stream.for_each(move |(request, response_handle)| {
                        Self::handle_request(request, response_handle, handler.clone())
                    })
                    .map_err(move |e| {
                        debug!("error in TCP request_stream src: {:?} error: {}",
                               src_addr,
                               e)
                    }));

                Ok(())
            })
                       .map_err(|e| debug!("error in inbound tcp_stream: {}", e)));

        Ok(())
    }

    /// Register a TlsListener to the Server. The TlsListener should already be bound to either an
    /// IPv6 or an IPv4 address.
    ///
    /// To make the server more resilient to DOS issues, there is a timeout. Care should be taken
    ///  to not make this too low depending on use cases.
    ///
    /// # Arguments
    /// * `listener` - a bound TCP (needs to be on a different port from standard TCP connections) socket
    /// * `timeout` - timeout duration of incoming requests, any connection that does not send
    ///               requests within this time period will be closed. In the future it should be
    ///               possible to create long-lived queries, but these should be from trusted sources
    ///               only, this would require some type of whitelisting.
    /// * `pkcs12` - certificate used to announce to clients
    pub fn register_tls_listener(&self,
                                 listener: std::net::TcpListener,
                                 timeout: Duration,
                                 pkcs12: ParsedPkcs12)
                                 -> io::Result<()> {
        let handle = self.io_loop.handle();
        let handler = self.handler.clone();
        // TODO: this is an awkward interface with socketaddr...
        let addr = listener.local_addr().expect("listener is not bound?");
        let listener = tokio_core::net::TcpListener::from_listener(listener, &addr, &handle)
            .expect("could not register listener");
        debug!("registered tcp: {:?}", listener);

        let mut builder = try!(SslAcceptorBuilder::mozilla_modern(SslMethod::tls(),
                                                                  &pkcs12.pkey,
                                                                  &pkcs12.cert,
                                                                  &pkcs12.chain)
                                       .map_err(|e| {
                                                    io::Error::new(io::ErrorKind::ConnectionRefused,
                                                                   format!("tls error: {}", e))
                                                }));

        // mut block
        {
            let ssl_context_bldr = builder.builder_mut();

            ssl_context_bldr.set_options(ssl::SSL_OP_NO_SSLV2 | ssl::SSL_OP_NO_SSLV3 |
                                         ssl::SSL_OP_NO_TLSV1 |
                                         ssl::SSL_OP_NO_TLSV1_1);
        }

        let tls_acceptor = builder.build();

        // for each incoming request...
        self.io_loop.handle().spawn(
        listener.incoming()
                .for_each(move |(tcp_stream, src_addr)| {
                  debug!("accepted request from: {}", src_addr);
                  let timeout = timeout.clone();
                  let handle = handle.clone();
                  let handler = handler.clone();

                  // take the created stream...
                  tls_acceptor.accept_async(tcp_stream)
                              .map_err(|e| io::Error::new(io::ErrorKind::ConnectionRefused, format!("tls error: {}", e)))
                              .and_then(move |tls_stream| {
                                  let (buf_stream, stream_handle) = TlsStream::from_stream(tls_stream, src_addr.clone());
                                  let timeout_stream = try!(TimeoutStream::new(buf_stream, timeout, handle.clone()));
                                  let request_stream = RequestStream::new(timeout_stream, stream_handle);
                                  let handler = handler.clone();

                                  // and spawn to the io_loop
                                  handle.spawn(
                                  request_stream.for_each(move |(request, response_handle)| {
                                      Self::handle_request(request, response_handle, handler.clone())
                                  })
                              .map_err(move |e| debug!("error in TCP request_stream src: {:?} error: {}", src_addr, e))
                              );

                              Ok(())
                            })
                            //.map_err(move |e| debug!("error TLS handshake: {:?} error: {:?}", src_addr, e))
              })
              .map_err(|e| debug!("error in inbound tcp_stream: {}", e))
    );

        Ok(())
    }

    /// TODO how to do threads? should we do a bunch of listener threads and then query threads?
    /// Ideally the processing would be n-threads for recieving, which hand off to m-threads for
    ///  request handling. It would generally be the case that n <= m.
    pub fn listen(&mut self) -> io::Result<()> {
        info!("Server starting up");
        try!(self.io_loop.run(Forever));

        Err(io::Error::new(io::ErrorKind::Interrupted,
                           "Server stopping due to interruption"))
    }

    /// Returns a reference to the tokio core loop driving this Server instance
    pub fn tokio_core(&mut self) -> &mut Core {
        &mut self.io_loop
    }

    fn handle_request(request: Request,
                      mut response_handle: ResponseHandle,
                      handler: Arc<T>)
                      -> io::Result<()> {
        let response = handler.handle_request(&request);
        response_handle.send(response)
    }
}

struct Forever;

impl Future for Forever {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // run forever...
        Ok(Async::NotReady)
    }
}
<|endoftext|>


<commit_before>use crate::error::*;
use crate::pdu::reader::*;
use crate::pdu::writer::*;
use crate::pdu::*;
use byteordered::byteorder::WriteBytesExt;
use matches::matches;
use std::io::Cursor;

#[test]
fn can_write_chunks_with_preceding_u32_length() -> Result<()> {
    let mut bytes = vec![0u8; 0];
    write_chunk_u32(&mut bytes, |writer| {
        writer.write_u8(0x02)?;
        write_chunk_u32(writer, |writer| {
            writer.write_u8(0x03)?;
            Ok(())
        })?;
        Ok(())
    })?;

    assert_eq!(bytes.len(), 10);
    assert_eq!(bytes, &[0, 0, 0, 6, 2, 0, 0, 0, 1, 3]);

    Ok(())
}

#[test]
fn can_write_chunks_with_preceding_u16_length() -> Result<()> {
    let mut bytes = vec![0u8; 0];
    write_chunk_u16(&mut bytes, |writer| {
        writer.write_u8(0x02)?;
        write_chunk_u16(writer, |writer| {
            writer.write_u8(0x03)?;
            Ok(())
        })?;
        Ok(())
    })?;

    assert_eq!(bytes.len(), 6);
    assert_eq!(bytes, &[0, 4, 2, 0, 1, 3]);

    Ok(())
}

#[test]
fn can_read_write_associate_rq() -> Result<()> {
    let association_rq = Pdu::AssociationRQ {
        protocol_version: 2,
        calling_ae_title: "calling ae".to_string(),
        called_ae_title: "called ae".to_string(),
        application_context_name: "application context name".to_string(),
        presentation_contexts: vec![
            PresentationContextProposed {
                id: 1,
                abstract_syntax: "abstract 1".to_string(),
                transfer_syntaxes: vec!["transfer 1".to_string(), "transfer 2".to_string()],
            },
            PresentationContextProposed {
                id: 3,
                abstract_syntax: "abstract 2".to_string(),
                transfer_syntaxes: vec!["transfer 3".to_string(), "transfer 4".to_string()],
            },
        ],
        user_variables: vec![
            UserVariableItem::ImplementationClassUID("class uid".to_string()),
            UserVariableItem::ImplementationVersionName("version name".to_string()),
            UserVariableItem::MaxLength(23),
        ],
    };

    let mut bytes = vec![0u8; 0];
    write_pdu(&mut bytes, &association_rq)?;

    let result = read_pdu(&mut Cursor::new(&bytes), DEFAULT_MAX_PDU)?;

    if let Pdu::AssociationRQ {
        protocol_version,
        calling_ae_title,
        called_ae_title,
        application_context_name,
        presentation_contexts,
        user_variables,
    } = result
    {
        assert_eq!(protocol_version, 2);
        assert_eq!(calling_ae_title, "calling ae");
        assert_eq!(called_ae_title, "called ae");
        assert_eq!(
            application_context_name,
            "application context name".to_string()
        );
        assert_eq!(presentation_contexts.len(), 2);
        assert_eq!(presentation_contexts[0].abstract_syntax, "abstract 1");
        assert_eq!(presentation_contexts[0].transfer_syntaxes.len(), 2);
        assert_eq!(presentation_contexts[0].transfer_syntaxes[0], "transfer 1");
        assert_eq!(presentation_contexts[0].transfer_syntaxes[1], "transfer 2");
        assert_eq!(presentation_contexts[1].abstract_syntax, "abstract 2");
        assert_eq!(presentation_contexts[1].transfer_syntaxes.len(), 2);
        assert_eq!(presentation_contexts[1].transfer_syntaxes[0], "transfer 3");
        assert_eq!(presentation_contexts[1].transfer_syntaxes[1], "transfer 4");
        assert_eq!(user_variables.len(), 3);
        matches!(
            user_variables[0],
            UserVariableItem::ImplementationClassUID(_)
        );
        matches!(
            user_variables[1],
            UserVariableItem::ImplementationVersionName(_)
        );
        matches!(user_variables[2], UserVariableItem::MaxLength(_));
    } else {
        assert!(false, "invalid pdu type");
    }

    Ok(())
}

#[test]
fn can_read_write_pdata() -> Result<()> {
    let pdata_rq = Pdu::PData {
        data: vec![PDataValue {
            presentation_context_id: 3,
            value_type: PDataValueType::Command,
            is_last: true,
            data: vec![0, 0, 0, 0],
        }],
    };

    let mut bytes = vec![0u8; 0];
    write_pdu(&mut bytes, &pdata_rq)?;

    let result = read_pdu(&mut Cursor::new(&bytes), DEFAULT_MAX_PDU)?;

    if let Pdu::PData { data } = result {
        assert_eq!(data.len(), 1);
        assert_eq!(data[0].presentation_context_id, 3);
        matches!(data[0].value_type, PDataValueType::Command);
        matches!(data[0].is_last, true);
        assert_eq!(data[0].data, vec![0, 0, 0, 0])
    } else {
        assert!(false, "invalid pdu type");
    }

    Ok(())
}
<commit_msg>Update ul/src/pdu/test.rs<commit_after>use crate::error::*;
use crate::pdu::reader::*;
use crate::pdu::writer::*;
use crate::pdu::*;
use byteordered::byteorder::WriteBytesExt;
use matches::matches;
use std::io::Cursor;

#[test]
fn can_write_chunks_with_preceding_u32_length() -> Result<()> {
    let mut bytes = vec![0u8; 0];
    write_chunk_u32(&mut bytes, |writer| {
        writer.write_u8(0x02)?;
        write_chunk_u32(writer, |writer| {
            writer.write_u8(0x03)?;
            Ok(())
        })?;
        Ok(())
    })?;

    assert_eq!(bytes.len(), 10);
    assert_eq!(bytes, &[0, 0, 0, 6, 2, 0, 0, 0, 1, 3]);

    Ok(())
}

#[test]
fn can_write_chunks_with_preceding_u16_length() -> Result<()> {
    let mut bytes = vec![0u8; 0];
    write_chunk_u16(&mut bytes, |writer| {
        writer.write_u8(0x02)?;
        write_chunk_u16(writer, |writer| {
            writer.write_u8(0x03)?;
            Ok(())
        })?;
        Ok(())
    })?;

    assert_eq!(bytes.len(), 6);
    assert_eq!(bytes, &[0, 4, 2, 0, 1, 3]);

    Ok(())
}

#[test]
fn can_read_write_associate_rq() -> Result<()> {
    let association_rq = Pdu::AssociationRQ {
        protocol_version: 2,
        calling_ae_title: "calling ae".to_string(),
        called_ae_title: "called ae".to_string(),
        application_context_name: "application context name".to_string(),
        presentation_contexts: vec![
            PresentationContextProposed {
                id: 1,
                abstract_syntax: "abstract 1".to_string(),
                transfer_syntaxes: vec!["transfer 1".to_string(), "transfer 2".to_string()],
            },
            PresentationContextProposed {
                id: 3,
                abstract_syntax: "abstract 2".to_string(),
                transfer_syntaxes: vec!["transfer 3".to_string(), "transfer 4".to_string()],
            },
        ],
        user_variables: vec![
            UserVariableItem::ImplementationClassUID("class uid".to_string()),
            UserVariableItem::ImplementationVersionName("version name".to_string()),
            UserVariableItem::MaxLength(23),
        ],
    };

    let mut bytes = vec![0u8; 0];
    write_pdu(&mut bytes, &association_rq)?;

    let result = read_pdu(&mut Cursor::new(&bytes), DEFAULT_MAX_PDU)?;

    if let Pdu::AssociationRQ {
        protocol_version,
        calling_ae_title,
        called_ae_title,
        application_context_name,
        presentation_contexts,
        user_variables,
    } = result
    {
        assert_eq!(protocol_version, 2);
        assert_eq!(calling_ae_title, "calling ae");
        assert_eq!(called_ae_title, "called ae");
        assert_eq!(
            application_context_name,
            "application context name".to_string()
        );
        assert_eq!(presentation_contexts.len(), 2);
        assert_eq!(presentation_contexts[0].abstract_syntax, "abstract 1");
        assert_eq!(presentation_contexts[0].transfer_syntaxes.len(), 2);
        assert_eq!(presentation_contexts[0].transfer_syntaxes[0], "transfer 1");
        assert_eq!(presentation_contexts[0].transfer_syntaxes[1], "transfer 2");
        assert_eq!(presentation_contexts[1].abstract_syntax, "abstract 2");
        assert_eq!(presentation_contexts[1].transfer_syntaxes.len(), 2);
        assert_eq!(presentation_contexts[1].transfer_syntaxes[0], "transfer 3");
        assert_eq!(presentation_contexts[1].transfer_syntaxes[1], "transfer 4");
        assert_eq!(user_variables.len(), 3);
        matches!(
            user_variables[0],
            UserVariableItem::ImplementationClassUID(_)
        );
        matches!(
            user_variables[1],
            UserVariableItem::ImplementationVersionName(_)
        );
        matches!(user_variables[2], UserVariableItem::MaxLength(_));
    } else {
        assert!(false, "invalid pdu type");
    }

    Ok(())
}

#[test]
fn can_read_write_pdata() -> Result<()> {
    let pdata_rq = Pdu::PData {
        data: vec![PDataValue {
            presentation_context_id: 3,
            value_type: PDataValueType::Command,
            is_last: true,
            data: vec![0, 0, 0, 0],
        }],
    };

    let mut bytes = Vec::new();
    write_pdu(&mut bytes, &pdata_rq)?;

    let result = read_pdu(&mut Cursor::new(&bytes), DEFAULT_MAX_PDU)?;

    if let Pdu::PData { data } = result {
        assert_eq!(data.len(), 1);
        assert_eq!(data[0].presentation_context_id, 3);
        matches!(data[0].value_type, PDataValueType::Command);
        matches!(data[0].is_last, true);
        assert_eq!(data[0].data, vec![0, 0, 0, 0])
    } else {
        assert!(false, "invalid pdu type");
    }

    Ok(())
}
<|endoftext|>