<commit_before>use serde::{Deserialize, Serialize};

use de::Deserializer;
use ser::Serializer;
use token::Token;

use std::fmt::Debug;

/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Serialize + Deserialize<'de> + PartialEq + Debug,
{
    assert_ser_tokens(value, tokens);
    assert_de_tokens(value, tokens);
}

/// Asserts that `value` serializes to the given `tokens`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_ser_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_ser_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => {}
        Err(err) => panic!("value failed to serialize: {}", err),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that `value` serializes to the given `tokens`, and then yields
/// `error`.
///
/// ```edition2018
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// use serde::Serialize;
/// use serde_test::{assert_ser_tokens_error, Token};
///
/// #[derive(Serialize)]
/// struct Example {
///     lock: Arc<Mutex<u32>>,
/// }
///
/// fn main() {
///     let example = Example { lock: Arc::new(Mutex::new(0)) };
///     let lock = example.lock.clone();
///
///     let _ = thread::spawn(move || {
///         // This thread will acquire the mutex first, unwrapping the result
///         // of `lock` because the lock has not been poisoned.
///         let _guard = lock.lock().unwrap();
///
///         // This panic while holding the lock (`_guard` is in scope) will
///         // poison the mutex.
///         panic!()
///     }).join();
///
///     let expected = &[
///         Token::Struct { name: "Example", len: 1 },
///         Token::Str("lock"),
///     ];
///     let error = "lock poison error while serializing";
///     assert_ser_tokens_error(&example, expected, error);
/// }
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: &str)
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => panic!("value serialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that the given `tokens` deserialize into `value`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_de_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_de_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Deserialize<'de> + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens);
    let mut deserialized_val = match T::deserialize(&mut de) {
        Ok(v) => {
            assert_eq!(v, *value);
            v
        }
        Err(e) => panic!("tokens failed to deserialize: {}", e),
    };
    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }

    // Do the same thing for deserialize_in_place. This isn't *great* because a
    // no-op impl of deserialize_in_place can technically succeed here. Still,
    // this should catch a lot of junk.
    let mut de = Deserializer::new(tokens);
    match T::deserialize_in_place(&mut de, &mut deserialized_val) {
        Ok(()) => {
            assert_eq!(deserialized_val, *value);
        }
        Err(e) => panic!("tokens failed to deserialize_in_place: {}", e),
    }
    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}

/// Asserts that the given `tokens` yield `error` when deserializing.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_de_tokens_error, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// #[serde(deny_unknown_fields)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// assert_de_tokens_error::<S>(
///     &[
///         Token::Struct { name: "S", len: 2 },
///         Token::Str("x"),
///     ],
///     "unknown field `x`, expected `a` or `b`",
/// );
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
where
    T: Deserialize<'de>,
{
    let mut de = Deserializer::new(tokens);
    match T::deserialize(&mut de) {
        Ok(_) => panic!("tokens deserialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    // There may be one token left if a peek caused the error
    de.next_token_opt();

    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}
<commit_msg>Accept ?Sized references in assert_ser_tokens<commit_after>use serde::{Deserialize, Serialize};

use de::Deserializer;
use ser::Serializer;
use token::Token;

use std::fmt::Debug;

/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Serialize + Deserialize<'de> + PartialEq + Debug,
{
    assert_ser_tokens(value, tokens);
    assert_de_tokens(value, tokens);
}

/// Asserts that `value` serializes to the given `tokens`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_ser_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_ser_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_ser_tokens<T: ?Sized>(value: &T, tokens: &[Token])
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => {}
        Err(err) => panic!("value failed to serialize: {}", err),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that `value` serializes to the given `tokens`, and then yields
/// `error`.
///
/// ```edition2018
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// use serde::Serialize;
/// use serde_test::{assert_ser_tokens_error, Token};
///
/// #[derive(Serialize)]
/// struct Example {
///     lock: Arc<Mutex<u32>>,
/// }
///
/// fn main() {
///     let example = Example { lock: Arc::new(Mutex::new(0)) };
///     let lock = example.lock.clone();
///
///     let _ = thread::spawn(move || {
///         // This thread will acquire the mutex first, unwrapping the result
///         // of `lock` because the lock has not been poisoned.
///         let _guard = lock.lock().unwrap();
///
///         // This panic while holding the lock (`_guard` is in scope) will
///         // poison the mutex.
///         panic!()
///     }).join();
///
///     let expected = &[
///         Token::Struct { name: "Example", len: 1 },
///         Token::Str("lock"),
///     ];
///     let error = "lock poison error while serializing";
///     assert_ser_tokens_error(&example, expected, error);
/// }
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_ser_tokens_error<T: ?Sized>(value: &T, tokens: &[Token], error: &str)
where
    T: Serialize,
{
    let mut ser = Serializer::new(tokens);
    match value.serialize(&mut ser) {
        Ok(_) => panic!("value serialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    if ser.remaining() > 0 {
        panic!("{} remaining tokens", ser.remaining());
    }
}

/// Asserts that the given `tokens` deserialize into `value`.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_de_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_de_tokens(&s, &[
///     Token::Struct { name: "S", len: 2 },
///     Token::Str("a"),
///     Token::U8(0),
///     Token::Str("b"),
///     Token::U8(0),
///     Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
    T: Deserialize<'de> + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens);
    let mut deserialized_val = match T::deserialize(&mut de) {
        Ok(v) => {
            assert_eq!(v, *value);
            v
        }
        Err(e) => panic!("tokens failed to deserialize: {}", e),
    };
    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }

    // Do the same thing for deserialize_in_place. This isn't *great* because a
    // no-op impl of deserialize_in_place can technically succeed here. Still,
    // this should catch a lot of junk.
    let mut de = Deserializer::new(tokens);
    match T::deserialize_in_place(&mut de, &mut deserialized_val) {
        Ok(()) => {
            assert_eq!(deserialized_val, *value);
        }
        Err(e) => panic!("tokens failed to deserialize_in_place: {}", e),
    }
    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}

/// Asserts that the given `tokens` yield `error` when deserializing.
///
/// ```edition2018
/// # use serde::{Serialize, Deserialize};
/// # use serde_test::{assert_de_tokens_error, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// #[serde(deny_unknown_fields)]
/// struct S {
///     a: u8,
///     b: u8,
/// }
///
/// assert_de_tokens_error::<S>(
///     &[
///         Token::Struct { name: "S", len: 2 },
///         Token::Str("x"),
///     ],
///     "unknown field `x`, expected `a` or `b`",
/// );
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
where
    T: Deserialize<'de>,
{
    let mut de = Deserializer::new(tokens);
    match T::deserialize(&mut de) {
        Ok(_) => panic!("tokens deserialized successfully"),
        Err(e) => assert_eq!(e, *error),
    }

    // There may be one token left if a peek caused the error
    de.next_token_opt();

    if de.remaining() > 0 {
        panic!("{} remaining tokens", de.remaining());
    }
}
<|endoftext|>


<commit_before>//use core::fmt::Display;
use std::fmt;
use List::{Cons, Nil};

enum List<T> {
  Cons(T, Box<List<T>>),
  Nil
}

impl<T> fmt::Display for List<T> where T : fmt::Display {//TがDisplay traitを実装していることを保証したい
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Cons(ref head, ref tail) =>
        {
          write!(f, "{head} :: ", head = head);
          write!(f, "{tail} ", tail = tail)
        }
      Nil => write!(f, "Nil")
    }
  }
}

fn new_list<T>(args: Vec<T>) -> Box<List<T>> where T: Copy {
  let mut vec = args;
  let mut x: Box<List<T>> = Box::new(Nil);
  while vec.len() > 0 {
    match vec.pop() {
      Some(e) => x = Box::new(Cons(e, x)),
      None => {}
    }
  }
  x
}

fn main() {
  let list = new_list(vec!["A", "B", "C"]);
  println!("Hello, {rust}", rust=list);
}
<commit_msg>Delete comment<commit_after>use std::fmt;
use List::{Cons, Nil};

enum List<T> {
  Cons(T, Box<List<T>>),
  Nil
}

impl<T> fmt::Display for List<T> where T : fmt::Display {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Cons(ref head, ref tail) =>
        {
          write!(f, "{head} :: ", head = head);
          write!(f, "{tail} ", tail = tail)
        }
      Nil => write!(f, "Nil")
    }
  }
}

fn new_list<T>(args: Vec<T>) -> Box<List<T>> where T: Copy {
  let mut vec = args;
  let mut x: Box<List<T>> = Box::new(Nil);
  while vec.len() > 0 {
    match vec.pop() {
      Some(e) => x = Box::new(Cons(e, x)),
      None => {}
    }
  }
  x
}

fn main() {
  let list = new_list(vec!["A", "B", "C"]);
  println!("Hello, {rust}", rust=list);
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::fmt::Debug;
use quickcheck::quickcheck;

struct Unspecialized<I>(I);
impl<I> Iterator for Unspecialized<I>
where
    I: Iterator,
{
    type Item = I::Item;

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

fn check_specialized<'a, V, IterItem, Iter, F>(iterator: &Iter, mapper: F)
where
    V: Eq + Debug,
    Iter: Iterator<Item = IterItem> + Clone + 'a,
    F: Fn(Box<dyn Iterator<Item = IterItem> + 'a>) -> V,
{
    assert_eq!(
        mapper(Box::new(Unspecialized(iterator.clone()))),
        mapper(Box::new(iterator.clone()))
    )
}

fn test_specializations<IterItem, Iter>(
    it: &Iter,
) where
    IterItem: Eq + Debug + Clone,
    Iter: Iterator<Item = IterItem> + Clone,
{
    check_specialized(it, |i| i.count());
    check_specialized(it, |i| i.last());
    check_specialized(it, |i| i.collect::<Vec<_>>());
    check_specialized(it, |i| {
        let mut parameters_from_fold = vec![];
        let fold_result = i.fold(vec![], |mut acc, v: IterItem| {
            parameters_from_fold.push((acc.clone(), v.clone()));
            acc.push(v);
            acc
        });
        (parameters_from_fold, fold_result)
    });
    check_specialized(it, |mut i| {
        let mut parameters_from_all = vec![];
        let first = i.next();
        let all_result = i.all(|x| {
            parameters_from_all.push(x.clone());
            Some(x)==first
        });
        (parameters_from_all, all_result)
    });
    let size = it.clone().count();
    for n in 0..size + 2 {
        check_specialized(it, |mut i| i.nth(n));
    }
    // size_hint is a bit harder to check
    let mut it_sh = it.clone();
    for n in 0..size + 2 {
        let len = it_sh.clone().count();
        let (min, max) = it_sh.size_hint();
        assert_eq!(size - n.min(size), len);
        assert!(min <= len);
        if let Some(max) = max {
            assert!(len <= max);
        }
        it_sh.next();
    }
}

quickcheck! {
    fn intersperse(v: Vec<u8>) -> () {
        test_specializations(&v.into_iter().intersperse(0));
    }
}

quickcheck! {
    fn put_back_qc(test_vec: Vec<i32>) -> () {
        test_specializations(&itertools::put_back(test_vec.iter()));
        let mut pb = itertools::put_back(test_vec.into_iter());
        pb.put_back(1);
        test_specializations(&pb);
    }
}

quickcheck! {
    fn merge_join_by_qc(i1: Vec<usize>, i2: Vec<usize>) -> () {
        test_specializations(&i1.into_iter().merge_join_by(i2.into_iter(), std::cmp::Ord::cmp));
    }
}

quickcheck! {
    fn map_into(v: Vec<u8>) -> () {
        test_specializations(&v.into_iter().map_into::<u32>());
    }
}

quickcheck! {
    fn map_ok(v: Vec<Result<u8, char>>) -> () {
        test_specializations(&v.into_iter().map_ok(|u| u.checked_add(1)));
    }
}
<commit_msg>Make specializations tests actually test specialized methods<commit_after>use itertools::Itertools;
use std::fmt::Debug;
use quickcheck::quickcheck;

struct Unspecialized<I>(I);
impl<I> Iterator for Unspecialized<I>
where
    I: Iterator,
{
    type Item = I::Item;

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

macro_rules! check_specialized {
    ($src:expr, |$it:pat| $closure:expr) => {
        let $it = $src.clone();
        let v1 = $closure;

        let $it = Unspecialized($src.clone());
        let v2 = $closure;

        assert_eq!(v1, v2);
    }
}

fn test_specializations<IterItem, Iter>(
    it: &Iter,
) where
    IterItem: Eq + Debug + Clone,
    Iter: Iterator<Item = IterItem> + Clone,
{
    check_specialized!(it, |i| i.count());
    check_specialized!(it, |i| i.last());
    check_specialized!(it, |i| i.collect::<Vec<_>>());
    check_specialized!(it, |i| {
        let mut parameters_from_fold = vec![];
        let fold_result = i.fold(vec![], |mut acc, v: IterItem| {
            parameters_from_fold.push((acc.clone(), v.clone()));
            acc.push(v);
            acc
        });
        (parameters_from_fold, fold_result)
    });
    check_specialized!(it, |mut i| {
        let mut parameters_from_all = vec![];
        let first = i.next();
        let all_result = i.all(|x| {
            parameters_from_all.push(x.clone());
            Some(x)==first
        });
        (parameters_from_all, all_result)
    });
    let size = it.clone().count();
    for n in 0..size + 2 {
        check_specialized!(it, |mut i| i.nth(n));
    }
    // size_hint is a bit harder to check
    let mut it_sh = it.clone();
    for n in 0..size + 2 {
        let len = it_sh.clone().count();
        let (min, max) = it_sh.size_hint();
        assert_eq!(size - n.min(size), len);
        assert!(min <= len);
        if let Some(max) = max {
            assert!(len <= max);
        }
        it_sh.next();
    }
}

quickcheck! {
    fn intersperse(v: Vec<u8>) -> () {
        test_specializations(&v.into_iter().intersperse(0));
    }
}

quickcheck! {
    fn put_back_qc(test_vec: Vec<i32>) -> () {
        test_specializations(&itertools::put_back(test_vec.iter()));
        let mut pb = itertools::put_back(test_vec.into_iter());
        pb.put_back(1);
        test_specializations(&pb);
    }
}

quickcheck! {
    fn merge_join_by_qc(i1: Vec<usize>, i2: Vec<usize>) -> () {
        test_specializations(&i1.into_iter().merge_join_by(i2.into_iter(), std::cmp::Ord::cmp));
    }
}

quickcheck! {
    fn map_into(v: Vec<u8>) -> () {
        test_specializations(&v.into_iter().map_into::<u32>());
    }
}

quickcheck! {
    fn map_ok(v: Vec<Result<u8, char>>) -> () {
        test_specializations(&v.into_iter().map_ok(|u| u.checked_add(1)));
    }
}
<|endoftext|>


<commit_before>extern mod core_foundation;
extern mod io_surface;
extern mod opengles;

use mod opengles::cgl;
use mod opengles::gl2;

use core_foundation::base::CFTypeOps;
use core::cast::transmute;
use core::ptr::{null, to_unsafe_ptr};
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight};
use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth};
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext, CGLLockContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER, FRAMEBUFFER_COMPLETE};
use opengles::gl2::{GLenum, GLint, GLsizei, GLuint, LINEAR, NEAREST, RGBA, TEXTURE_MAG_FILTER};
use opengles::gl2::{TEXTURE_MIN_FILTER, TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};

use base::ShareContext;

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

pub type Context = MacContext;

pub struct MacContext {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> CGLContextObj {
    // FIXME: We should expose some higher-level, safe abstractions inside the CGL module.
    unsafe {
        // Choose a pixel format.
        let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
        let pixel_format = null();
        let pixel_format_count = 1;
        let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                            to_unsafe_ptr(&pixel_format),
                                            to_unsafe_ptr(&pixel_format_count));
        assert gl_error == kCGLNoError;

        // Create the context.
        let cgl_context = null();
        let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
        assert gl_error == kCGLNoError;

        // Set the context.
        let gl_error = CGLSetCurrentContext(cgl_context);
        assert gl_error == kCGLNoError;

        // Lock the context.
        let gl_error = CGLLockContext(cgl_context);
        assert gl_error == kCGLNoError;

        return cgl_context;
    }
}

pub fn init_surface(+size: Size2D<int>) -> IOSurface {
    use number = core_foundation::number::CFNumber::new_number;
    use string = core_foundation::string::CFString::wrap;
    use true_value = core_foundation::boolean::CFBoolean::true_value;

    IOSurface::new_io_surface(&core_foundation::dictionary::CFDictionary::new_dictionary([
        (string(kIOSurfaceWidth),           number(size.width as i32).as_type()),
        (string(kIOSurfaceHeight),          number(size.height as i32).as_type()),
        (string(kIOSurfaceBytesPerRow),     number(size.width as i32 * 4).as_type()),
        (string(kIOSurfaceBytesPerElement), number(4i32).as_type()),
        (string(kIOSurfaceIsGlobal),        true_value().as_type())
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &CGLContextObj, surface: &IOSurface, +size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let gl_error = CGLTexImageIOSurface2D(*context,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(copy surface.obj),
                                              0);
        assert gl_error == kCGLNoError;
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE;
}

impl MacContext : ShareContext {
    static fn new(size: Size2D<int>) -> MacContext {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(copy size);

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        MacContext {
            surface: move surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id() -> int {
        self.surface.get_id() as int
    }
}

<commit_msg>Update to new CG bindings.<commit_after>extern mod core_foundation;
extern mod io_surface;
extern mod opengles;

use mod opengles::cgl;
use mod opengles::gl2;

use core_foundation::base::CFTypeOps;
use core::cast::transmute;
use core::ptr::{null, to_unsafe_ptr};
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight};
use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth};
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext, CGLLockContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER, FRAMEBUFFER_COMPLETE};
use opengles::gl2::{GLenum, GLint, GLsizei, GLuint, LINEAR, NEAREST, RGBA, TEXTURE_MAG_FILTER};
use opengles::gl2::{TEXTURE_MIN_FILTER, TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};

use base::ShareContext;

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

pub type Context = MacContext;

pub struct MacContext {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> CGLContextObj {
    // FIXME: We should expose some higher-level, safe abstractions inside the CGL module.
    unsafe {
        // Choose a pixel format.
        let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
        let pixel_format = null();
        let pixel_format_count = 1;
        let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                            to_unsafe_ptr(&pixel_format),
                                            to_unsafe_ptr(&pixel_format_count));
        assert gl_error == kCGLNoError;

        // Create the context.
        let cgl_context = null();
        let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
        assert gl_error == kCGLNoError;

        // Set the context.
        let gl_error = CGLSetCurrentContext(cgl_context);
        assert gl_error == kCGLNoError;

        // Lock the context.
        let gl_error = CGLLockContext(cgl_context);
        assert gl_error == kCGLNoError;

        return cgl_context;
    }
}

pub fn init_surface(+size: Size2D<int>) -> IOSurface {
    use cf = core_foundation;
    use number = cf::number::CFNumber::new;
    use string = cf::string::CFString::wrap;
    use true_value = cf::boolean::CFBoolean::true_value;

    IOSurface::new_io_surface(&cf::dictionary::CFDictionary::new([
        (string(kIOSurfaceWidth),           number(size.width as i32).as_type()),
        (string(kIOSurfaceHeight),          number(size.height as i32).as_type()),
        (string(kIOSurfaceBytesPerRow),     number(size.width as i32 * 4).as_type()),
        (string(kIOSurfaceBytesPerElement), number(4i32).as_type()),
        (string(kIOSurfaceIsGlobal),        true_value().as_type())
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &CGLContextObj, surface: &IOSurface, +size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let gl_error = CGLTexImageIOSurface2D(*context,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(copy surface.obj),
                                              0);
        assert gl_error == kCGLNoError;
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE;
}

impl MacContext : ShareContext {
    static fn new(size: Size2D<int>) -> MacContext {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(copy size);

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        MacContext {
            surface: move surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id() -> int {
        self.surface.get_id() as int
    }
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cookie as cookie_rs;

use net::cookie::Cookie;
use net::cookie_storage::CookieStorage;
use net_traits::CookieSource;

#[test]
fn test_domain_match() {
    assert!(Cookie::domain_match("foo.com", "foo.com"));
    assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
    assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));

    assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
    assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
    assert!(!Cookie::domain_match("foo.com", "bar.com"));

    assert!(!Cookie::domain_match("bar.com", "bbar.com"));
    assert!(Cookie::domain_match("235.132.2.3", "235.132.2.3"));
    assert!(!Cookie::domain_match("235.132.2.3", "1.1.1.1"));
    assert!(!Cookie::domain_match("235.132.2.3", ".2.3"));
}

#[test]
fn test_path_match() {
    assert!(Cookie::path_match("/", "/"));
    assert!(Cookie::path_match("/index.html", "/"));
    assert!(Cookie::path_match("/w/index.html", "/"));
    assert!(Cookie::path_match("/w/index.html", "/w/index.html"));
    assert!(Cookie::path_match("/w/index.html", "/w/"));
    assert!(Cookie::path_match("/w/index.html", "/w"));

    assert!(!Cookie::path_match("/", "/w/"));
    assert!(!Cookie::path_match("/a", "/w/"));
    assert!(!Cookie::path_match("/", "/w"));
    assert!(!Cookie::path_match("/w/index.html", "/w/index"));
    assert!(!Cookie::path_match("/windex.html", "/w/"));
    assert!(!Cookie::path_match("/windex.html", "/w"));
}

#[test]
fn test_default_path() {
    assert!(&*Cookie::default_path("/foo/bar/baz/") == "/foo/bar/baz");
    assert!(&*Cookie::default_path("/foo/bar/baz") == "/foo/bar");
    assert!(&*Cookie::default_path("/foo/") == "/foo");
    assert!(&*Cookie::default_path("/foo") == "/");
    assert!(&*Cookie::default_path("/") == "/");
    assert!(&*Cookie::default_path("") == "/");
    assert!(&*Cookie::default_path("foo") == "/");
}

#[test]
fn fn_cookie_constructor() {
    use net_traits::CookieSource;

    let url = &url!("http://example.com/foo");

    let gov_url = &url!("http://gov.ac/foo");
    // cookie name/value test
    assert!(cookie_rs::Cookie::parse(" baz ").is_err());
    assert!(cookie_rs::Cookie::parse(" = bar  ").is_err());
    assert!(cookie_rs::Cookie::parse(" baz = ").is_ok());

    // cookie domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  ").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_some());
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(&**cookie.cookie.domain.as_ref().unwrap() == "example.com");

    // cookie public domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  gov.ac").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_none());
    assert!(Cookie::new_wrapped(cookie, gov_url, CookieSource::HTTP).is_some());

    // cookie domain matching test
    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Domain = bazample.com").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; HttpOnly").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::NonHTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(cookie.cookie.value == "bar");
    assert!(cookie.cookie.name == "baz");
    assert!(cookie.cookie.secure);
    assert!(&cookie.cookie.path.as_ref().unwrap()[..] == "/foo/bar/");
    assert!(&cookie.cookie.domain.as_ref().unwrap()[..] == "example.com");
    assert!(cookie.host_only);

    let u = &url!("http://example.com/foobar");
    let cookie = cookie_rs::Cookie::parse("foobar=value;path=/").unwrap();
    assert!(Cookie::new_wrapped(cookie, u, CookieSource::HTTP).is_some());
}

#[test]
fn test_sort_order() {
    use std::cmp::Ordering;

    let url = &url!("http://example.com/foo");
    let a_wrapped = cookie_rs::Cookie::parse("baz=bar; Path=/foo/bar/").unwrap();
    let a = Cookie::new_wrapped(a_wrapped.clone(), url, CookieSource::HTTP).unwrap();
    let a_prime = Cookie::new_wrapped(a_wrapped, url, CookieSource::HTTP).unwrap();
    let b = cookie_rs::Cookie::parse("baz=bar;Path=/foo/bar/baz/").unwrap();
    let b = Cookie::new_wrapped(b, url, CookieSource::HTTP).unwrap();

    assert!(b.cookie.path.as_ref().unwrap().len() > a.cookie.path.as_ref().unwrap().len());
    assert!(CookieStorage::cookie_comparator(&a, &b) == Ordering::Greater);
    assert!(CookieStorage::cookie_comparator(&b, &a) == Ordering::Less);
    assert!(CookieStorage::cookie_comparator(&a, &a_prime) == Ordering::Less);
    assert!(CookieStorage::cookie_comparator(&a_prime, &a) == Ordering::Greater);
    assert!(CookieStorage::cookie_comparator(&a, &a) == Ordering::Equal);
}
<commit_msg>Make cookie comparator test pass on Windows.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cookie as cookie_rs;

use net::cookie::Cookie;
use net::cookie_storage::CookieStorage;
use net_traits::CookieSource;

#[test]
fn test_domain_match() {
    assert!(Cookie::domain_match("foo.com", "foo.com"));
    assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
    assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));

    assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
    assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
    assert!(!Cookie::domain_match("foo.com", "bar.com"));

    assert!(!Cookie::domain_match("bar.com", "bbar.com"));
    assert!(Cookie::domain_match("235.132.2.3", "235.132.2.3"));
    assert!(!Cookie::domain_match("235.132.2.3", "1.1.1.1"));
    assert!(!Cookie::domain_match("235.132.2.3", ".2.3"));
}

#[test]
fn test_path_match() {
    assert!(Cookie::path_match("/", "/"));
    assert!(Cookie::path_match("/index.html", "/"));
    assert!(Cookie::path_match("/w/index.html", "/"));
    assert!(Cookie::path_match("/w/index.html", "/w/index.html"));
    assert!(Cookie::path_match("/w/index.html", "/w/"));
    assert!(Cookie::path_match("/w/index.html", "/w"));

    assert!(!Cookie::path_match("/", "/w/"));
    assert!(!Cookie::path_match("/a", "/w/"));
    assert!(!Cookie::path_match("/", "/w"));
    assert!(!Cookie::path_match("/w/index.html", "/w/index"));
    assert!(!Cookie::path_match("/windex.html", "/w/"));
    assert!(!Cookie::path_match("/windex.html", "/w"));
}

#[test]
fn test_default_path() {
    assert!(&*Cookie::default_path("/foo/bar/baz/") == "/foo/bar/baz");
    assert!(&*Cookie::default_path("/foo/bar/baz") == "/foo/bar");
    assert!(&*Cookie::default_path("/foo/") == "/foo");
    assert!(&*Cookie::default_path("/foo") == "/");
    assert!(&*Cookie::default_path("/") == "/");
    assert!(&*Cookie::default_path("") == "/");
    assert!(&*Cookie::default_path("foo") == "/");
}

#[test]
fn fn_cookie_constructor() {
    use net_traits::CookieSource;

    let url = &url!("http://example.com/foo");

    let gov_url = &url!("http://gov.ac/foo");
    // cookie name/value test
    assert!(cookie_rs::Cookie::parse(" baz ").is_err());
    assert!(cookie_rs::Cookie::parse(" = bar  ").is_err());
    assert!(cookie_rs::Cookie::parse(" baz = ").is_ok());

    // cookie domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  ").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_some());
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(&**cookie.cookie.domain.as_ref().unwrap() == "example.com");

    // cookie public domains test
    let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain =  gov.ac").unwrap();
    assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_none());
    assert!(Cookie::new_wrapped(cookie, gov_url, CookieSource::HTTP).is_some());

    // cookie domain matching test
    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Domain = bazample.com").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; HttpOnly").unwrap();
    assert!(Cookie::new_wrapped(cookie, url, CookieSource::NonHTTP).is_none());

    let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
    let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
    assert!(cookie.cookie.value == "bar");
    assert!(cookie.cookie.name == "baz");
    assert!(cookie.cookie.secure);
    assert!(&cookie.cookie.path.as_ref().unwrap()[..] == "/foo/bar/");
    assert!(&cookie.cookie.domain.as_ref().unwrap()[..] == "example.com");
    assert!(cookie.host_only);

    let u = &url!("http://example.com/foobar");
    let cookie = cookie_rs::Cookie::parse("foobar=value;path=/").unwrap();
    assert!(Cookie::new_wrapped(cookie, u, CookieSource::HTTP).is_some());
}

#[cfg(target_os = "windows")]
fn delay_to_ensure_different_timestamp() {
    use std::thread;
    use std::time::Duration;

    // time::now()'s resolution on some platforms isn't granular enought to ensure
    // that two back-to-back calls to Cookie::new_wrapped generate different timestamps .
    thread::sleep(Duration::from_millis(500));
}

#[cfg(not(target_os = "windows"))]
fn delay_to_ensure_different_timestamp() {
}

#[test]
fn test_sort_order() {
    use std::cmp::Ordering;

    let url = &url!("http://example.com/foo");
    let a_wrapped = cookie_rs::Cookie::parse("baz=bar; Path=/foo/bar/").unwrap();
    let a = Cookie::new_wrapped(a_wrapped.clone(), url, CookieSource::HTTP).unwrap();
    delay_to_ensure_different_timestamp();
    let a_prime = Cookie::new_wrapped(a_wrapped, url, CookieSource::HTTP).unwrap();
    let b = cookie_rs::Cookie::parse("baz=bar;Path=/foo/bar/baz/").unwrap();
    let b = Cookie::new_wrapped(b, url, CookieSource::HTTP).unwrap();

    assert!(b.cookie.path.as_ref().unwrap().len() > a.cookie.path.as_ref().unwrap().len());
    assert!(CookieStorage::cookie_comparator(&a, &b) == Ordering::Greater);
    assert!(CookieStorage::cookie_comparator(&b, &a) == Ordering::Less);
    assert!(CookieStorage::cookie_comparator(&a, &a_prime) == Ordering::Less);
    assert!(CookieStorage::cookie_comparator(&a_prime, &a) == Ordering::Greater);
    assert!(CookieStorage::cookie_comparator(&a, &a) == Ordering::Equal);
}
<|endoftext|>


<commit_before>// Test integration of zmq with a simple external event loop
//
// This excercises the `Socket::get_fd()` method in combination with
// `Socket::get_events()` to integrate with Unix `poll(2)` to check
// the basis for integration with external event loops works.

use log::debug;
use nix::poll::{self, PollFlags};

use super::with_connection;

test!(test_external_poll_inproc, {
    with_connection(
        "inproc://test-poll",
        zmq2::REQ,
        poll_client,
        zmq2::REP,
        poll_worker,
    );
});

test!(test_external_poll_ipc, {
    with_connection(
        "ipc:///tmp/zmq-tokio-test",
        zmq2::REQ,
        poll_client,
        zmq2::REP,
        poll_worker,
    );
});

test!(test_external_poll_tcp, {
    with_connection(
        "tcp://127.0.0.1:*",
        zmq2::REQ,
        poll_client,
        zmq2::REP,
        poll_worker,
    );
});

fn poll_client(_ctx: &zmq2::Context, socket: &zmq2::Socket) {
    // TODO: we should use `poll::poll()` here as well.
    for i in 0..10 {
        let payload = format!("message {}", i);
        socket.send(&payload, 0).unwrap();
        let reply = socket.recv_msg(0).unwrap();
        assert_eq!(payload.as_bytes(), &reply[..]);
    }
    socket.send("", 0).unwrap();
    let last = socket.recv_msg(0).unwrap();
    assert_eq!(b"", &last[..]);
}

/// Keeps track of the polling state for the event signalling FD of a
/// single socket.
struct PollState<'a> {
    socket: &'a zmq2::Socket,
    fds: [poll::PollFd; 1],
}

impl<'a> PollState<'a> {
    fn new(socket: &'a zmq2::Socket) -> Self {
        let fd = socket.get_fd().unwrap();
        PollState {
            socket,
            fds: [poll::PollFd::new(fd, PollFlags::POLLIN)],
        }
    }

    /// Wait for one of `events` to happen.
    fn wait(&mut self, events: zmq2::PollEvents) {
        while !(self.events().intersects(events)) {
            debug!("polling");
            let fds = &mut self.fds;
            poll::poll(fds, -1).unwrap();
            debug!("poll done, events: {:?}", fds[0].revents());
            match fds[0].revents() {
                Some(events) => {
                    if !events.contains(PollFlags::POLLIN) {
                        continue;
                    }
                }
                _ => continue,
            }
        }
    }

    fn events(&self) -> zmq2::PollEvents {
        self.socket.get_events().unwrap() as zmq2::PollEvents
    }
}

fn poll_worker(_ctx: &zmq2::Context, socket: &zmq2::Socket) {
    let mut reply = None;
    let mut state = PollState::new(&socket);
    loop {
        match reply.take() {
            None => {
                state.wait(zmq2::POLLIN);
                let msg = socket.recv_msg(zmq2::DONTWAIT).unwrap();
                reply = Some(msg);
            }
            Some(msg) => {
                state.wait(zmq2::POLLOUT);
                let done = msg.len() == 0;
                socket.send(msg, zmq2::DONTWAIT).unwrap();
                if done {
                    break;
                }
            }
        }
    }
}
<commit_msg>unix clippy<commit_after>// Test integration of zmq with a simple external event loop
//
// This excercises the `Socket::get_fd()` method in combination with
// `Socket::get_events()` to integrate with Unix `poll(2)` to check
// the basis for integration with external event loops works.

use log::debug;
use nix::poll::{self, PollFlags};

use super::with_connection;

test!(test_external_poll_inproc, {
    with_connection(
        "inproc://test-poll",
        zmq2::REQ,
        poll_client,
        zmq2::REP,
        poll_worker,
    );
});

test!(test_external_poll_ipc, {
    with_connection(
        "ipc:///tmp/zmq-tokio-test",
        zmq2::REQ,
        poll_client,
        zmq2::REP,
        poll_worker,
    );
});

test!(test_external_poll_tcp, {
    with_connection(
        "tcp://127.0.0.1:*",
        zmq2::REQ,
        poll_client,
        zmq2::REP,
        poll_worker,
    );
});

fn poll_client(_ctx: &zmq2::Context, socket: &zmq2::Socket) {
    // TODO: we should use `poll::poll()` here as well.
    for i in 0..10 {
        let payload = format!("message {}", i);
        socket.send(&payload, 0).unwrap();
        let reply = socket.recv_msg(0).unwrap();
        assert_eq!(payload.as_bytes(), &reply[..]);
    }
    socket.send("", 0).unwrap();
    let last = socket.recv_msg(0).unwrap();
    assert_eq!(b"", &last[..]);
}

/// Keeps track of the polling state for the event signalling FD of a
/// single socket.
struct PollState<'a> {
    socket: &'a zmq2::Socket,
    fds: [poll::PollFd; 1],
}

impl<'a> PollState<'a> {
    fn new(socket: &'a zmq2::Socket) -> Self {
        let fd = socket.get_fd().unwrap();
        PollState {
            socket,
            fds: [poll::PollFd::new(fd, PollFlags::POLLIN)],
        }
    }

    /// Wait for one of `events` to happen.
    fn wait(&mut self, events: zmq2::PollEvents) {
        while !(self.events().intersects(events)) {
            debug!("polling");
            let fds = &mut self.fds;
            poll::poll(fds, -1).unwrap();
            debug!("poll done, events: {:?}", fds[0].revents());
            match fds[0].revents() {
                Some(events) => {
                    if !events.contains(PollFlags::POLLIN) {
                        continue;
                    }
                }
                _ => continue,
            }
        }
    }

    fn events(&self) -> zmq2::PollEvents {
        self.socket.get_events().unwrap() as zmq2::PollEvents
    }
}

fn poll_worker(_ctx: &zmq2::Context, socket: &zmq2::Socket) {
    let mut reply = None;
    let mut state = PollState::new(socket);
    loop {
        match reply.take() {
            None => {
                state.wait(zmq2::POLLIN);
                let msg = socket.recv_msg(zmq2::DONTWAIT).unwrap();
                reply = Some(msg);
            }
            Some(msg) => {
                state.wait(zmq2::POLLOUT);
                let done = msg.len() == 0;
                socket.send(msg, zmq2::DONTWAIT).unwrap();
                if done {
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>fix bugs & cleanup connect code<commit_after><|endoftext|>


<commit_before><commit_msg>Include the module struct itself when finding the highest address<commit_after><|endoftext|>


<commit_before>//! RAII wrapper for using a KataOS copyregion object.

#![no_std]
#![allow(non_camel_case_types)]

use core::mem::size_of;

use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_Default_VMAttributes;
use sel4_sys::seL4_Page_Map;
use sel4_sys::seL4_Page_Unmap;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_Word;

extern "C" {
    static SELF_VSPACE_ROOT: seL4_CPtr;
}

// Sample usage:
// let mut copy_region = CopyRegion::new(unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])}, PAGE_SIZE);
// copy_region.map(frame.cptr)?;
// copy_region.as_mut()[..].fill(0);
// let start = if index > 0 { 0 } else { vaddr - data_range.start };
// let end = cmp::min(data_range.end - vaddr, copy_region.size());
// image.read_exact(&mut copy_region.as_mut()[start..end])
//      .map_err(|_| seL4_Error::seL4_NoError)?; // XXX
// copy_region.unmap()?;

// TODO(sleffler): do we need to parameterize VM_Attributes & CapRights?
// TODO(sleffler): Mutex-wrapped & maybe RefCell-wrapped versions?

// Fn from the criterion crate that convinces the optimizer
// a value is used in order to defeat premature optimization.
fn black_box<T>(dummy: T) -> T {
    unsafe {
        let ret = core::ptr::read_volatile(&dummy);
        core::mem::forget(dummy);
        ret
    }
}

pub struct CopyRegion {
    region: *mut seL4_Word,
    size: usize,
    cur_frame: Option<seL4_CPtr>,
}
impl CopyRegion {
    pub fn new(region: *mut seL4_Word, size: usize) -> Self {
        CopyRegion {
            region,
            size,
            cur_frame: None,
        }
    }

    // Returns the region size in bytes.
    pub fn size(&self) -> usize {
        self.size
    }

    // Returns the region size if mapped, otherwise 0.
    pub fn mapped_bytes(&self) -> usize {
        if self.cur_frame.is_some() {
            self.size
        } else {
            0
        }
    }

    // Returns an immutable [u8] ref to the mapped region.
    pub fn as_ref(&mut self) -> &[u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region as _, self.size) }
    }

    // Returns a mutable [u8] ref to the mapped region.
    pub fn as_mut(&mut self) -> &mut [u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region as _, self.size) }
    }

    // Returns an immutable [seL4_Word] ref to the mapped region.
    pub fn as_word_ref(&mut self) -> &[seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Returns a mutable [seL4_Word] ref to the mapped region.
    pub fn as_word_mut(&mut self) -> &mut [seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Maps the |frame| in the SELF_VSPACE_ROOT for r/w.
    // XXX need rights + attribs?
    pub fn map(&mut self, frame: seL4_CPtr) -> seL4_Result {
        black_box(frame); // NB: compiler WAR for frame clobber
        unsafe {
            seL4_Page_Map(
                frame,
                SELF_VSPACE_ROOT,
                self.region as seL4_Word,
                // seL4_ReadWrite
                seL4_CapRights::new(
                    /*grant_reply=*/ 0, /*grant=*/ 0, /*read=*/ 1, /*write=*/ 1,
                ),
                seL4_Default_VMAttributes,
            )
        }?;
        self.cur_frame = Some(frame);
        Ok(())
    }

    // Unmaps the current frame, if any.
    pub fn unmap(&mut self) -> seL4_Result {
        if let Some(cptr) = self.cur_frame {
            #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
            unsafe { seL4_ARM_Page_Unify_Instruction(cptr, 0, self.size()) }?;

            unsafe { seL4_Page_Unmap(cptr) }?;
            self.cur_frame = None;
        }
        Ok(())
    }
}
impl Drop for CopyRegion {
    fn drop(&mut self) {
        self.unmap().expect("CopyRegion");
    }
}
<commit_msg>kata-os-model: portability fix<commit_after>//! RAII wrapper for using a KataOS copyregion object.

#![no_std]
#![allow(non_camel_case_types)]

use core::mem::size_of;

use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_Default_VMAttributes;
use sel4_sys::seL4_Page_Map;
use sel4_sys::seL4_Page_Unmap;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_Word;

extern "C" {
    static SELF_VSPACE_ROOT: seL4_CPtr;
}

// Sample usage:
// let mut copy_region = CopyRegion::new(unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])}, PAGE_SIZE);
// copy_region.map(frame.cptr)?;
// copy_region.as_mut()[..].fill(0);
// let start = if index > 0 { 0 } else { vaddr - data_range.start };
// let end = cmp::min(data_range.end - vaddr, copy_region.size());
// image.read_exact(&mut copy_region.as_mut()[start..end])
//      .map_err(|_| seL4_Error::seL4_NoError)?; // XXX
// copy_region.unmap()?;

// TODO(sleffler): do we need to parameterize VM_Attributes & CapRights?
// TODO(sleffler): Mutex-wrapped & maybe RefCell-wrapped versions?

// Fn from the criterion crate that convinces the optimizer
// a value is used in order to defeat premature optimization.
fn black_box<T>(dummy: T) -> T {
    unsafe {
        let ret = core::ptr::read_volatile(&dummy);
        core::mem::forget(dummy);
        ret
    }
}

pub struct CopyRegion {
    region: *mut seL4_Word,
    size: usize,
    cur_frame: Option<seL4_CPtr>,
}
impl CopyRegion {
    pub fn new(region: *mut seL4_Word, size: usize) -> Self {
        CopyRegion {
            region,
            size,
            cur_frame: None,
        }
    }

    // Returns the region size in bytes.
    pub fn size(&self) -> usize {
        self.size
    }

    // Returns the region size if mapped, otherwise 0.
    pub fn mapped_bytes(&self) -> usize {
        if self.cur_frame.is_some() {
            self.size
        } else {
            0
        }
    }

    // Returns an immutable [u8] ref to the mapped region.
    pub fn as_ref(&mut self) -> &[u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region as _, self.size) }
    }

    // Returns a mutable [u8] ref to the mapped region.
    pub fn as_mut(&mut self) -> &mut [u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region as _, self.size) }
    }

    // Returns an immutable [seL4_Word] ref to the mapped region.
    pub fn as_word_ref(&mut self) -> &[seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Returns a mutable [seL4_Word] ref to the mapped region.
    pub fn as_word_mut(&mut self) -> &mut [seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Maps the |frame| in the SELF_VSPACE_ROOT for r/w.
    // XXX need rights + attribs?
    pub fn map(&mut self, frame: seL4_CPtr) -> seL4_Result {
        black_box(frame); // NB: compiler WAR for frame clobber
        unsafe {
            seL4_Page_Map(
                frame,
                SELF_VSPACE_ROOT,
                self.region as seL4_Word,
                // seL4_ReadWrite
                seL4_CapRights::new(
                    /*grant_reply=*/ 0, /*grant=*/ 0, /*read=*/ 1, /*write=*/ 1,
                ),
                seL4_Default_VMAttributes,
            )
        }?;
        self.cur_frame = Some(frame);
        Ok(())
    }

    // Unmaps the current frame, if any.
    pub fn unmap(&mut self) -> seL4_Result {
        if let Some(cptr) = self.cur_frame {
            #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
            unsafe { sel4_sys::seL4_ARM_Page_Unify_Instruction(cptr, 0, self.size()) }?;

            unsafe { seL4_Page_Unmap(cptr) }?;
            self.cur_frame = None;
        }
        Ok(())
    }
}
impl Drop for CopyRegion {
    fn drop(&mut self) {
        self.unmap().expect("CopyRegion");
    }
}
<|endoftext|>


<commit_before><commit_msg>Remove unrelated comment from log plugin<commit_after><|endoftext|>


<commit_before><commit_msg>Write tests for fake session iterators.<commit_after><|endoftext|>


<commit_before>use std::{
    collections::HashMap,
    convert::TryFrom,
    fs::File,
    path::{
        Path,
        PathBuf,
    },
    str::FromStr,
};

use serde::de::DeserializeOwned;
use strum::IntoEnumIterator;
use strum_macros::{
    Display,
    EnumIter,
    EnumString,
};
use thiserror::Error;

use rnc_core::{
    grouper::Grouped::{
        self,
        Multiple,
        Optional,
        Required,
    },
    psql::JsonlIterator,
};

use super::{
    basic::Basic,
    crs::Crs,
    feedback::Feedback,
    go_annotation::GoAnnotation,
    interacting_protein::InteractingProtein,
    interacting_rna::InteractingRna,
    orf::Orf,
    precompute::Precompute,
    qa_status::QaStatus,
    r2dt::R2dt,
    raw::Raw,
    rfam_hit::RfamHit,
    so_tree,
    so_tree::SoMapping,
};

#[derive(Debug, Error)]
pub enum Error {
    #[error("Missing required file {0}")]
    MustDefineMissingFile(FileTypes),

    #[error("Not all files are in required format")]
    InvalidDataFormat,

    #[error("Missing requested SO term {0}")]
    MissingSoTrem(String),

    #[error("Cannot find expected file, from {0:?}")]
    BadFileName(PathBuf),

    #[error("Could not match path {0:?} to a possible file type")]
    UnknownFileType(PathBuf),

    #[error("Data out of sync at: {0:?}")]
    OutofSyncData(Vec<usize>),

    #[error(transparent)]
    JsonError(#[from] rnc_core::psql::Error),

    #[error(transparent)]
    Other(#[from] anyhow::Error),
}

#[derive(Debug, Display, PartialEq, Eq, Hash, EnumString, EnumIter)]
pub enum FileTypes {
    #[strum(ascii_case_insensitive)]
    Base,

    #[strum(ascii_case_insensitive)]
    Crs,

    #[strum(ascii_case_insensitive)]
    Feedback,

    #[strum(ascii_case_insensitive)]
    GoAnnotations,

    #[strum(ascii_case_insensitive)]
    InteractingProteins,

    #[strum(ascii_case_insensitive)]
    InteractingRnas,

    #[strum(ascii_case_insensitive)]
    LocusInfo,

    #[strum(ascii_case_insensitive)]
    Orfs,

    #[strum(ascii_case_insensitive)]
    Precompute,

    #[strum(ascii_case_insensitive)]
    QaStatus,

    #[strum(ascii_case_insensitive)]
    R2dtHits,

    #[strum(ascii_case_insensitive)]
    RfamHits,

    #[strum(ascii_case_insensitive)]
    SoInfo,
}

pub struct FileJoiner {
    basic: JsonlIterator<File, Grouped<Basic>>,
    crs: JsonlIterator<File, Grouped<Crs>>,
    feedback: JsonlIterator<File, Grouped<Feedback>>,
    go_annotations: JsonlIterator<File, Grouped<GoAnnotation>>,
    interacting_proteins: JsonlIterator<File, Grouped<InteractingProtein>>,
    interacting_rnas: JsonlIterator<File, Grouped<InteractingRna>>,
    orfs: JsonlIterator<File, Grouped<Orf>>,
    precompute: JsonlIterator<File, Grouped<Precompute>>,
    qa_status: JsonlIterator<File, Grouped<QaStatus>>,
    r2dt_hits: JsonlIterator<File, Grouped<R2dt>>,
    rfam_hits: JsonlIterator<File, Grouped<RfamHit>>,
    so_info: SoMapping,
}

pub struct FileJoinerBuilder {
    paths: HashMap<FileTypes, PathBuf>,
}

impl FileTypes {
    pub fn required_for_joining(&self) -> bool {
        match self {
            Self::LocusInfo => false,
            _ => true,
        }
    }
}

impl TryFrom<&Path> for FileTypes {
    type Error = Error;

    fn try_from(path: &Path) -> Result<Self, Self::Error> {
        let name = path
            .file_stem()
            .map(|s| s.to_str())
            .flatten()
            .ok_or_else(|| Error::BadFileName(PathBuf::from(path)))?;
        let name = name.replace("-", "").replace("_", "");
        Self::from_str(&name).map_err(|_| Error::UnknownFileType(PathBuf::from(path)))
    }
}

impl Default for FileJoinerBuilder {
    fn default() -> Self {
        Self {
            paths: HashMap::default(),
        }
    }
}

impl FileJoinerBuilder {
    pub fn from_files(paths: Vec<PathBuf>) -> Result<Self, Error> {
        let mut builder = Self::default();
        for path in paths {
            let file_type = FileTypes::try_from(path.as_ref())?;
            builder.file(file_type, path);
        }

        for file_type in FileTypes::iter() {
            if !builder.is_set(&file_type) && file_type.required_for_joining() {
                return Err(Error::MustDefineMissingFile(file_type));
            }
        }

        Ok(builder)
    }

    pub fn is_set(&mut self, file: &FileTypes) -> bool {
        self.paths.contains_key(file)
    }

    pub fn file(&mut self, file: FileTypes, path: PathBuf) -> &mut Self {
        self.paths.insert(file, path);
        self
    }

    fn path_for(&self, file: FileTypes) -> Result<&PathBuf, Error> {
        self.paths.get(&file).ok_or_else(|| Error::MustDefineMissingFile(file))
    }

    fn iterator_for<T: DeserializeOwned>(
        &self,
        file: FileTypes,
    ) -> Result<JsonlIterator<File, T>, Error> {
        let path = self.path_for(file)?;
        Ok(JsonlIterator::from_path(path)?)
    }

    pub fn build(&self) -> Result<FileJoiner, Error> {
        let basic = self.iterator_for(FileTypes::Base)?;
        let crs = self.iterator_for(FileTypes::Crs)?;
        let feedback = self.iterator_for(FileTypes::Feedback)?;
        let go_annotations = self.iterator_for(FileTypes::GoAnnotations)?;
        let interacting_proteins = self.iterator_for(FileTypes::InteractingProteins)?;
        let interacting_rnas = self.iterator_for(FileTypes::InteractingRnas)?;
        let orfs = self.iterator_for(FileTypes::Orfs)?;
        let precompute = self.iterator_for(FileTypes::Precompute)?;
        let qa_status = self.iterator_for(FileTypes::QaStatus)?;
        let r2dt_hits = self.iterator_for(FileTypes::R2dtHits)?;
        let rfam_hits = self.iterator_for(FileTypes::RfamHits)?;
        let so_info = so_tree::load(self.path_for(FileTypes::SoInfo)?)?;

        Ok(FileJoiner {
            basic,
            crs,
            feedback,
            go_annotations,
            interacting_proteins,
            interacting_rnas,
            orfs,
            precompute,
            qa_status,
            r2dt_hits,
            rfam_hits,
            so_info,
        })
    }
}

impl Iterator for FileJoiner {
    type Item = Result<Raw, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        let current = (
            self.basic.next(),
            self.crs.next(),
            self.feedback.next(),
            self.go_annotations.next(),
            self.interacting_proteins.next(),
            self.interacting_rnas.next(),
            self.orfs.next(),
            self.precompute.next(),
            self.qa_status.next(),
            self.r2dt_hits.next(),
            self.rfam_hits.next(),
        );

        match current {
            (None, None, None, None, None, None, None, None, None, None, None) => None,
            (
                Some(Required {
                    id: id1,
                    data: base,
                }),
                Some(Multiple {
                    id: id2,
                    data: crs,
                }),
                Some(Multiple {
                    id: id3,
                    data: feedback,
                }),
                Some(Multiple {
                    id: id4,
                    data: go_annotations,
                }),
                Some(Multiple {
                    id: id5,
                    data: interacting_proteins,
                }),
                Some(Multiple {
                    id: id6,
                    data: interacting_rnas,
                }),
                Some(Multiple {
                    id: id7,
                    data: orfs,
                }),
                Some(Required {
                    id: id8,
                    data: precompute,
                }),
                Some(Required {
                    id: id9,
                    data: qa_status,
                }),
                Some(Optional {
                    id: id10,
                    data: r2dt,
                }),
                Some(Multiple {
                    id: id11,
                    data: rfam_hits,
                }),
            ) => {
                if id1 != id2
                    || id1 != id3
                    || id1 != id4
                    || id1 != id5
                    || id1 != id6
                    || id1 != id7
                    || id1 != id8
                    || id1 != id9
                    || id1 != id10
                    || id1 != id11
                {
                    return Some(Err(Error::OutofSyncData(vec![
                        id1, id2, id3, id4, id5, id6, id7, id8, id9, id10, id11
                    ])));
                }

                let pre_so_type = precompute.so_rna_type();
                if !self.so_info.contains_key(pre_so_type) {
                    return Some(Err(Error::MissingSoTrem(pre_so_type.to_string())));
                }
                let so_tree = self.so_info[pre_so_type].clone();

                let raw = Raw::builder()
                    .id(id1)
                    .base(base)
                    .precompute(precompute)
                    .qa_status(qa_status)
                    .crs(crs)
                    .feedback(feedback)
                    .go_annotations(go_annotations)
                    .interacting_proteins(interacting_proteins)
                    .interacting_rnas(interacting_rnas)
                    .r2dt(r2dt)
                    .rfam_hits(rfam_hits)
                    .orfs(orfs)
                    .so_tree(so_tree)
                    .build();

                return Some(Ok(raw));
            },
            _ => Some(Err(Error::InvalidDataFormat)),
        }
    }
}
<commit_msg>Correct name of r2dt file type for joiner<commit_after>use std::{
    collections::HashMap,
    convert::TryFrom,
    fs::File,
    path::{
        Path,
        PathBuf,
    },
    str::FromStr,
};

use serde::de::DeserializeOwned;
use strum::IntoEnumIterator;
use strum_macros::{
    Display,
    EnumIter,
    EnumString,
};
use thiserror::Error;

use rnc_core::{
    grouper::Grouped::{
        self,
        Multiple,
        Optional,
        Required,
    },
    psql::JsonlIterator,
};

use super::{
    basic::Basic,
    crs::Crs,
    feedback::Feedback,
    go_annotation::GoAnnotation,
    interacting_protein::InteractingProtein,
    interacting_rna::InteractingRna,
    orf::Orf,
    precompute::Precompute,
    qa_status::QaStatus,
    r2dt::R2dt,
    raw::Raw,
    rfam_hit::RfamHit,
    so_tree,
    so_tree::SoMapping,
};

#[derive(Debug, Error)]
pub enum Error {
    #[error("Missing required file {0}")]
    MustDefineMissingFile(FileTypes),

    #[error("Not all files are in required format")]
    InvalidDataFormat,

    #[error("Missing requested SO term {0}")]
    MissingSoTrem(String),

    #[error("Cannot find expected file, from {0:?}")]
    BadFileName(PathBuf),

    #[error("Could not match path {0:?} to a possible file type")]
    UnknownFileType(PathBuf),

    #[error("Data out of sync at: {0:?}")]
    OutofSyncData(Vec<usize>),

    #[error(transparent)]
    JsonError(#[from] rnc_core::psql::Error),

    #[error(transparent)]
    Other(#[from] anyhow::Error),
}

#[derive(Debug, Display, PartialEq, Eq, Hash, EnumString, EnumIter)]
#[strum(ascii_case_insensitive, serialize_all = "kebab-case")]
pub enum FileTypes {
    Base,
    Crs,
    Feedback,
    GoAnnotations,
    InteractingProteins,
    InteractingRnas,
    Orfs,
    Precompute,
    QaStatus,
    R2dt,
    RfamHits,
    SoInfo,
}

pub struct FileJoiner {
    basic: JsonlIterator<File, Grouped<Basic>>,
    crs: JsonlIterator<File, Grouped<Crs>>,
    feedback: JsonlIterator<File, Grouped<Feedback>>,
    go_annotations: JsonlIterator<File, Grouped<GoAnnotation>>,
    interacting_proteins: JsonlIterator<File, Grouped<InteractingProtein>>,
    interacting_rnas: JsonlIterator<File, Grouped<InteractingRna>>,
    orfs: JsonlIterator<File, Grouped<Orf>>,
    precompute: JsonlIterator<File, Grouped<Precompute>>,
    qa_status: JsonlIterator<File, Grouped<QaStatus>>,
    r2dt_hits: JsonlIterator<File, Grouped<R2dt>>,
    rfam_hits: JsonlIterator<File, Grouped<RfamHit>>,
    so_info: SoMapping,
}

pub struct FileJoinerBuilder {
    paths: HashMap<FileTypes, PathBuf>,
}

impl TryFrom<&Path> for FileTypes {
    type Error = Error;

    fn try_from(path: &Path) -> Result<Self, Self::Error> {
        let name = path
            .file_stem()
            .map(|s| s.to_str())
            .flatten()
            .ok_or_else(|| Error::BadFileName(PathBuf::from(path)))?;
        let name = name.replace("-", "").replace("_", "");
        Self::from_str(&name).map_err(|_| Error::UnknownFileType(PathBuf::from(path)))
    }
}

impl Default for FileJoinerBuilder {
    fn default() -> Self {
        Self {
            paths: HashMap::default(),
        }
    }
}

impl FileJoinerBuilder {
    pub fn from_files(paths: Vec<PathBuf>) -> Result<Self, Error> {
        let mut builder = Self::default();
        for path in paths {
            let file_type = FileTypes::try_from(path.as_ref())?;
            builder.file(file_type, path);
        }

        for file_type in FileTypes::iter() {
            if !builder.is_set(&file_type) {
                return Err(Error::MustDefineMissingFile(file_type));
            }
        }

        Ok(builder)
    }

    pub fn is_set(&mut self, file: &FileTypes) -> bool {
        self.paths.contains_key(file)
    }

    pub fn file(&mut self, file: FileTypes, path: PathBuf) -> &mut Self {
        self.paths.insert(file, path);
        self
    }

    fn path_for(&self, file: FileTypes) -> Result<&PathBuf, Error> {
        self.paths.get(&file).ok_or_else(|| Error::MustDefineMissingFile(file))
    }

    fn iterator_for<T: DeserializeOwned>(
        &self,
        file: FileTypes,
    ) -> Result<JsonlIterator<File, T>, Error> {
        let path = self.path_for(file)?;
        Ok(JsonlIterator::from_path(path)?)
    }

    pub fn build(&self) -> Result<FileJoiner, Error> {
        let basic = self.iterator_for(FileTypes::Base)?;
        let crs = self.iterator_for(FileTypes::Crs)?;
        let feedback = self.iterator_for(FileTypes::Feedback)?;
        let go_annotations = self.iterator_for(FileTypes::GoAnnotations)?;
        let interacting_proteins = self.iterator_for(FileTypes::InteractingProteins)?;
        let interacting_rnas = self.iterator_for(FileTypes::InteractingRnas)?;
        let orfs = self.iterator_for(FileTypes::Orfs)?;
        let precompute = self.iterator_for(FileTypes::Precompute)?;
        let qa_status = self.iterator_for(FileTypes::QaStatus)?;
        let r2dt_hits = self.iterator_for(FileTypes::R2dt)?;
        let rfam_hits = self.iterator_for(FileTypes::RfamHits)?;
        let so_info = so_tree::load(self.path_for(FileTypes::SoInfo)?)?;

        Ok(FileJoiner {
            basic,
            crs,
            feedback,
            go_annotations,
            interacting_proteins,
            interacting_rnas,
            orfs,
            precompute,
            qa_status,
            r2dt_hits,
            rfam_hits,
            so_info,
        })
    }
}

impl Iterator for FileJoiner {
    type Item = Result<Raw, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        let current = (
            self.basic.next(),
            self.crs.next(),
            self.feedback.next(),
            self.go_annotations.next(),
            self.interacting_proteins.next(),
            self.interacting_rnas.next(),
            self.orfs.next(),
            self.precompute.next(),
            self.qa_status.next(),
            self.r2dt_hits.next(),
            self.rfam_hits.next(),
        );

        match current {
            (None, None, None, None, None, None, None, None, None, None, None) => None,
            (
                Some(Required {
                    id: id1,
                    data: base,
                }),
                Some(Multiple {
                    id: id2,
                    data: crs,
                }),
                Some(Multiple {
                    id: id3,
                    data: feedback,
                }),
                Some(Multiple {
                    id: id4,
                    data: go_annotations,
                }),
                Some(Multiple {
                    id: id5,
                    data: interacting_proteins,
                }),
                Some(Multiple {
                    id: id6,
                    data: interacting_rnas,
                }),
                Some(Multiple {
                    id: id7,
                    data: orfs,
                }),
                Some(Required {
                    id: id8,
                    data: precompute,
                }),
                Some(Required {
                    id: id9,
                    data: qa_status,
                }),
                Some(Optional {
                    id: id10,
                    data: r2dt,
                }),
                Some(Multiple {
                    id: id11,
                    data: rfam_hits,
                }),
            ) => {
                if id1 != id2
                    || id1 != id3
                    || id1 != id4
                    || id1 != id5
                    || id1 != id6
                    || id1 != id7
                    || id1 != id8
                    || id1 != id9
                    || id1 != id10
                    || id1 != id11
                {
                    return Some(Err(Error::OutofSyncData(vec![
                        id1, id2, id3, id4, id5, id6, id7, id8, id9, id10, id11
                    ])));
                }

                let pre_so_type = precompute.so_rna_type();
                if !self.so_info.contains_key(pre_so_type) {
                    return Some(Err(Error::MissingSoTrem(pre_so_type.to_string())));
                }
                let so_tree = self.so_info[pre_so_type].clone();

                let raw = Raw::builder()
                    .id(id1)
                    .base(base)
                    .precompute(precompute)
                    .qa_status(qa_status)
                    .crs(crs)
                    .feedback(feedback)
                    .go_annotations(go_annotations)
                    .interacting_proteins(interacting_proteins)
                    .interacting_rnas(interacting_rnas)
                    .r2dt(r2dt)
                    .rfam_hits(rfam_hits)
                    .orfs(orfs)
                    .so_tree(so_tree)
                    .build();

                return Some(Ok(raw));
            },
            _ => Some(Err(Error::InvalidDataFormat)),
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

fn main() {
    // Decide ideal limb width for arithmetic in the float parser. Refer to
    // src/lexical/math.rs for where this has an effect.
    let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    match target_arch.as_str() {
        "aarch64" | "mips64" | "powerpc64" | "x86_64" => {
            println!("cargo:rustc-cfg=limb_width_64");
        }
        _ => {
            println!("cargo:rustc-cfg=limb_width_32");
        }
    }

    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    // BTreeMap::get_key_value
    // https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html#additions-to-the-standard-library
    if minor < 40 {
        println!("cargo:rustc-cfg=no_btreemap_get_key_value");
    }

    // BTreeMap::remove_entry
    // https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html#library-changes
    if minor < 45 {
        println!("cargo:rustc-cfg=no_btreemap_remove_entry");
    }

    // BTreeMap::retain
    // https://blog.rust-lang.org/2021/06/17/Rust-1.53.0.html#library-changes
    if minor < 53 {
        println!("cargo:rustc-cfg=no_btreemap_retain");
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    let next = pieces.next()?;
    u32::from_str(next).ok()
}
<commit_msg>Update build.rs<commit_after>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

fn main() {
    // Decide ideal limb width for arithmetic in the float parser. Refer to
    // src/lexical/math.rs for where this has an effect.
    let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    match target_arch.as_str() {
        "aarch64" | "mips64" | "powerpc64" | "x86_64" => {
            println!("cargo:rustc-cfg=limb_width_64");
        }
        _ => {
            println!("cargo:rustc-cfg=limb_width_32");
        }
    }

    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    // BTreeMap::get_key_value
    // https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html#additions-to-the-standard-library
    if minor < 40 {
        println!("cargo:rustc-cfg=no_btreemap_get_key_value");
    }

    // BTreeMap::remove_entry
    // https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html#library-changes
    if minor < 45 {
        println!("cargo:rustc-cfg=no_btreemap_remove_entry");
    }

    // BTreeMap::retain
    // https://blog.rust-lang.org/2021/06/17/Rust-1.53.0.html#stabilized-apis
    if minor < 53 {
        println!("cargo:rustc-cfg=no_btreemap_retain");
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    let next = pieces.next()?;
    u32::from_str(next).ok()
}
<|endoftext|>


<commit_before>extern crate ruroonga_command as ruroonga;
use ruroonga::select::SelectCommand;
use ruroonga::selectable::drilldown::Drilldown;
use ruroonga::selectable::drilldown_builder::DrilldownBuilder;
use ruroonga::commandable::Commandable;
use ruroonga::queryable::Queryable;

fn simple_example() {
    let select = SelectCommand::new("Entries".to_string())
                 .filter("content @ \"fast\"".to_string());
    let drilldown = Drilldown::new()
                 .drilldown("tag".to_string());
    let builder = DrilldownBuilder::new(select, drilldown).build();
    println!("simple: {:?}", builder);
}

fn to_query_example() {
    let select = SelectCommand::new("Entries".to_string())
                 .filter("content @ \"fast\"".to_string());
    let drilldown = Drilldown::new()
                 .drilldown("tag".to_string());
    let builder = DrilldownBuilder::new(select, drilldown).to_query();
    println!("query: {}", builder);
}

fn to_command_example() {
    let select = SelectCommand::new("Entries".to_string())
                 .filter("content @ \"fast\"".to_string());
    let drilldown = Drilldown::new()
                 .drilldown("tag".to_string());
    let builder = DrilldownBuilder::new(select, drilldown).to_command();
    println!("command line: {}", builder);
}

fn main() {
    simple_example();
    to_query_example();
    to_command_example();
}
<commit_msg>example: Use dsl<commit_after>extern crate ruroonga_command as ruroonga;
use ruroonga::selectable::drilldown::Drilldown;
use ruroonga::selectable::drilldown_builder::DrilldownBuilder;
use ruroonga::commandable::Commandable;
use ruroonga::queryable::Queryable;
use ruroonga::dsl::*;

fn simple_example() {
    let select = select("Entries".to_string())
                 .filter("content @ \"fast\"".to_string());
    let drilldown = Drilldown::new()
                 .drilldown("tag".to_string());
    let builder = DrilldownBuilder::new(select, drilldown).build();
    println!("simple: {:?}", builder);
}

fn to_query_example() {
    let select = select("Entries".to_string())
                 .filter("content @ \"fast\"".to_string());
    let drilldown = Drilldown::new()
                 .drilldown("tag".to_string());
    let builder = DrilldownBuilder::new(select, drilldown).to_query();
    println!("query: {}", builder);
}

fn to_command_example() {
    let select = select("Entries".to_string())
                 .filter("content @ \"fast\"".to_string());
    let drilldown = Drilldown::new()
                 .drilldown("tag".to_string());
    let builder = DrilldownBuilder::new(select, drilldown).to_command();
    println!("command line: {}", builder);
}

fn main() {
    simple_example();
    to_query_example();
    to_command_example();
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use std::thread;

use data_model::{DataInit, Le64};

use ::vhost::Vsock as VhostVsockHandle;
use sys_util::{error, warn, EventFd, GuestMemory};
use virtio_sys::vhost;

use super::worker::Worker;
use super::{Error, Result};
use crate::virtio::{copy_config, Queue, VirtioDevice, TYPE_VSOCK};

const QUEUE_SIZE: u16 = 256;
const NUM_QUEUES: usize = 3;
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];

pub struct Vsock {
    worker_kill_evt: Option<EventFd>,
    kill_evt: Option<EventFd>,
    vhost_handle: Option<VhostVsockHandle>,
    cid: u64,
    interrupt: Option<EventFd>,
    avail_features: u64,
    acked_features: u64,
}

impl Vsock {
    /// Create a new virtio-vsock device with the given VM cid.
    pub fn new(cid: u64, mem: &GuestMemory) -> Result<Vsock> {
        let kill_evt = EventFd::new().map_err(Error::CreateKillEventFd)?;
        let handle = VhostVsockHandle::new(mem).map_err(Error::VhostOpen)?;

        let avail_features = 1 << vhost::VIRTIO_F_NOTIFY_ON_EMPTY
            | 1 << vhost::VIRTIO_RING_F_INDIRECT_DESC
            | 1 << vhost::VIRTIO_RING_F_EVENT_IDX
            | 1 << vhost::VHOST_F_LOG_ALL
            | 1 << vhost::VIRTIO_F_ANY_LAYOUT
            | 1 << vhost::VIRTIO_F_VERSION_1;

        Ok(Vsock {
            worker_kill_evt: Some(kill_evt.try_clone().map_err(Error::CloneKillEventFd)?),
            kill_evt: Some(kill_evt),
            vhost_handle: Some(handle),
            cid,
            interrupt: Some(EventFd::new().map_err(Error::VhostIrqCreate)?),
            avail_features,
            acked_features: 0,
        })
    }

    pub fn new_for_testing(cid: u64, features: u64) -> Vsock {
        Vsock {
            worker_kill_evt: None,
            kill_evt: None,
            vhost_handle: None,
            cid,
            interrupt: None,
            avail_features: features,
            acked_features: 0,
        }
    }

    pub fn acked_features(&self) -> u64 {
        self.acked_features
    }
}

impl Drop for Vsock {
    fn drop(&mut self) {
        // Only kill the child if it claimed its eventfd.
        if self.worker_kill_evt.is_none() {
            if let Some(kill_evt) = &self.kill_evt {
                // Ignore the result because there is nothing we can do about it.
                let _ = kill_evt.write(1);
            }
        }
    }
}

impl VirtioDevice for Vsock {
    fn keep_fds(&self) -> Vec<RawFd> {
        let mut keep_fds = Vec::new();

        if let Some(handle) = &self.vhost_handle {
            keep_fds.push(handle.as_raw_fd());
        }

        if let Some(interrupt) = &self.interrupt {
            keep_fds.push(interrupt.as_raw_fd());
        }

        if let Some(worker_kill_evt) = &self.worker_kill_evt {
            keep_fds.push(worker_kill_evt.as_raw_fd());
        }

        keep_fds
    }

    fn device_type(&self) -> u32 {
        TYPE_VSOCK
    }

    fn queue_max_sizes(&self) -> &[u16] {
        QUEUE_SIZES
    }

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let cid = Le64::from(self.cid);
        copy_config(data, 0, DataInit::as_slice(&cid), offset);
    }

    fn ack_features(&mut self, value: u64) {
        let mut v = value;

        // Check if the guest is ACK'ing a feature that we didn't claim to have.
        let unrequested_features = v & !self.avail_features;
        if unrequested_features != 0 {
            warn!("vsock: virtio-vsock got unknown feature ack: {:x}", v);

            // Don't count these features as acked.
            v &= !unrequested_features;
        }
        self.acked_features |= v;
    }

    fn activate(
        &mut self,
        _: GuestMemory,
        interrupt_evt: EventFd,
        interrupt_resample_evt: EventFd,
        status: Arc<AtomicUsize>,
        queues: Vec<Queue>,
        queue_evts: Vec<EventFd>,
    ) {
        if queues.len() != NUM_QUEUES || queue_evts.len() != NUM_QUEUES {
            error!("net: expected {} queues, got {}", NUM_QUEUES, queues.len());
            return;
        }

        if let Some(vhost_handle) = self.vhost_handle.take() {
            if let Some(interrupt) = self.interrupt.take() {
                if let Some(kill_evt) = self.worker_kill_evt.take() {
                    let acked_features = self.acked_features;
                    let cid = self.cid;
                    let worker_result = thread::Builder::new()
                        .name("vhost_vsock".to_string())
                        .spawn(move || {
                            // The third vq is an event-only vq that is not handled by the vhost
                            // subsystem (but still needs to exist).  Split it off here.
                            let vhost_queues = queues[..2].to_vec();
                            let mut worker = Worker::new(
                                vhost_queues,
                                vhost_handle,
                                interrupt,
                                status,
                                interrupt_evt,
                                interrupt_resample_evt,
                                acked_features,
                            );
                            let activate_vqs = |handle: &VhostVsockHandle| -> Result<()> {
                                handle.set_cid(cid).map_err(Error::VhostVsockSetCid)?;
                                handle.start().map_err(Error::VhostVsockStart)?;
                                Ok(())
                            };
                            let result =
                                worker.run(queue_evts, QUEUE_SIZES, kill_evt, activate_vqs);
                            if let Err(e) = result {
                                error!("vsock worker thread exited with error: {:?}", e);
                            }
                        });

                    if let Err(e) = worker_result {
                        error!("failed to spawn vhost_vsock worker: {}", e);
                        return;
                    }
                }
            }
        }
    }
}

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

    use byteorder::{ByteOrder, LittleEndian};
    #[test]
    fn ack_features() {
        let cid = 5;
        let features: u64 = (1 << 20) | (1 << 49) | (1 << 2) | (1 << 19);
        let mut acked_features: u64 = 0;
        let mut unavailable_features: u64 = 0;

        let mut vsock = Vsock::new_for_testing(cid, features);
        assert_eq!(acked_features, vsock.acked_features());

        acked_features |= 1 << 2;
        vsock.ack_features(acked_features);
        assert_eq!(acked_features, vsock.acked_features());

        acked_features |= 1 << 49;
        vsock.ack_features(acked_features);
        assert_eq!(acked_features, vsock.acked_features());

        acked_features |= 1 << 60;
        unavailable_features |= 1 << 60;
        vsock.ack_features(acked_features);
        assert_eq!(
            acked_features & !unavailable_features,
            vsock.acked_features()
        );

        acked_features |= 1 << 1;
        unavailable_features |= 1 << 1;
        vsock.ack_features(acked_features);
        assert_eq!(
            acked_features & !unavailable_features,
            vsock.acked_features()
        );
    }

    #[test]
    fn read_config() {
        let cid = 0xfca9a559fdcb9756;
        let vsock = Vsock::new_for_testing(cid, 0);

        let mut buf = [0 as u8; 8];
        vsock.read_config(0, &mut buf);
        assert_eq!(cid, LittleEndian::read_u64(&buf));

        vsock.read_config(0, &mut buf[..4]);
        assert_eq!((cid & 0xffffffff) as u32, LittleEndian::read_u32(&buf[..4]));

        vsock.read_config(4, &mut buf[..4]);
        assert_eq!((cid >> 32) as u32, LittleEndian::read_u32(&buf[..4]));

        let data: [u8; 8] = [8, 226, 5, 46, 159, 59, 89, 77];
        buf.copy_from_slice(&data);

        vsock.read_config(12, &mut buf);
        assert_eq!(&buf, &data);
    }

    #[test]
    fn features() {
        let cid = 5;
        let features: u64 = 0xfc195ae8db88cff9;

        let vsock = Vsock::new_for_testing(cid, features);
        assert_eq!(features, vsock.features());
    }
}
<commit_msg>devices: vsock: replace byteorder with from_le_bytes()<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use std::thread;

use data_model::{DataInit, Le64};

use ::vhost::Vsock as VhostVsockHandle;
use sys_util::{error, warn, EventFd, GuestMemory};
use virtio_sys::vhost;

use super::worker::Worker;
use super::{Error, Result};
use crate::virtio::{copy_config, Queue, VirtioDevice, TYPE_VSOCK};

const QUEUE_SIZE: u16 = 256;
const NUM_QUEUES: usize = 3;
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];

pub struct Vsock {
    worker_kill_evt: Option<EventFd>,
    kill_evt: Option<EventFd>,
    vhost_handle: Option<VhostVsockHandle>,
    cid: u64,
    interrupt: Option<EventFd>,
    avail_features: u64,
    acked_features: u64,
}

impl Vsock {
    /// Create a new virtio-vsock device with the given VM cid.
    pub fn new(cid: u64, mem: &GuestMemory) -> Result<Vsock> {
        let kill_evt = EventFd::new().map_err(Error::CreateKillEventFd)?;
        let handle = VhostVsockHandle::new(mem).map_err(Error::VhostOpen)?;

        let avail_features = 1 << vhost::VIRTIO_F_NOTIFY_ON_EMPTY
            | 1 << vhost::VIRTIO_RING_F_INDIRECT_DESC
            | 1 << vhost::VIRTIO_RING_F_EVENT_IDX
            | 1 << vhost::VHOST_F_LOG_ALL
            | 1 << vhost::VIRTIO_F_ANY_LAYOUT
            | 1 << vhost::VIRTIO_F_VERSION_1;

        Ok(Vsock {
            worker_kill_evt: Some(kill_evt.try_clone().map_err(Error::CloneKillEventFd)?),
            kill_evt: Some(kill_evt),
            vhost_handle: Some(handle),
            cid,
            interrupt: Some(EventFd::new().map_err(Error::VhostIrqCreate)?),
            avail_features,
            acked_features: 0,
        })
    }

    pub fn new_for_testing(cid: u64, features: u64) -> Vsock {
        Vsock {
            worker_kill_evt: None,
            kill_evt: None,
            vhost_handle: None,
            cid,
            interrupt: None,
            avail_features: features,
            acked_features: 0,
        }
    }

    pub fn acked_features(&self) -> u64 {
        self.acked_features
    }
}

impl Drop for Vsock {
    fn drop(&mut self) {
        // Only kill the child if it claimed its eventfd.
        if self.worker_kill_evt.is_none() {
            if let Some(kill_evt) = &self.kill_evt {
                // Ignore the result because there is nothing we can do about it.
                let _ = kill_evt.write(1);
            }
        }
    }
}

impl VirtioDevice for Vsock {
    fn keep_fds(&self) -> Vec<RawFd> {
        let mut keep_fds = Vec::new();

        if let Some(handle) = &self.vhost_handle {
            keep_fds.push(handle.as_raw_fd());
        }

        if let Some(interrupt) = &self.interrupt {
            keep_fds.push(interrupt.as_raw_fd());
        }

        if let Some(worker_kill_evt) = &self.worker_kill_evt {
            keep_fds.push(worker_kill_evt.as_raw_fd());
        }

        keep_fds
    }

    fn device_type(&self) -> u32 {
        TYPE_VSOCK
    }

    fn queue_max_sizes(&self) -> &[u16] {
        QUEUE_SIZES
    }

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let cid = Le64::from(self.cid);
        copy_config(data, 0, DataInit::as_slice(&cid), offset);
    }

    fn ack_features(&mut self, value: u64) {
        let mut v = value;

        // Check if the guest is ACK'ing a feature that we didn't claim to have.
        let unrequested_features = v & !self.avail_features;
        if unrequested_features != 0 {
            warn!("vsock: virtio-vsock got unknown feature ack: {:x}", v);

            // Don't count these features as acked.
            v &= !unrequested_features;
        }
        self.acked_features |= v;
    }

    fn activate(
        &mut self,
        _: GuestMemory,
        interrupt_evt: EventFd,
        interrupt_resample_evt: EventFd,
        status: Arc<AtomicUsize>,
        queues: Vec<Queue>,
        queue_evts: Vec<EventFd>,
    ) {
        if queues.len() != NUM_QUEUES || queue_evts.len() != NUM_QUEUES {
            error!("net: expected {} queues, got {}", NUM_QUEUES, queues.len());
            return;
        }

        if let Some(vhost_handle) = self.vhost_handle.take() {
            if let Some(interrupt) = self.interrupt.take() {
                if let Some(kill_evt) = self.worker_kill_evt.take() {
                    let acked_features = self.acked_features;
                    let cid = self.cid;
                    let worker_result = thread::Builder::new()
                        .name("vhost_vsock".to_string())
                        .spawn(move || {
                            // The third vq is an event-only vq that is not handled by the vhost
                            // subsystem (but still needs to exist).  Split it off here.
                            let vhost_queues = queues[..2].to_vec();
                            let mut worker = Worker::new(
                                vhost_queues,
                                vhost_handle,
                                interrupt,
                                status,
                                interrupt_evt,
                                interrupt_resample_evt,
                                acked_features,
                            );
                            let activate_vqs = |handle: &VhostVsockHandle| -> Result<()> {
                                handle.set_cid(cid).map_err(Error::VhostVsockSetCid)?;
                                handle.start().map_err(Error::VhostVsockStart)?;
                                Ok(())
                            };
                            let result =
                                worker.run(queue_evts, QUEUE_SIZES, kill_evt, activate_vqs);
                            if let Err(e) = result {
                                error!("vsock worker thread exited with error: {:?}", e);
                            }
                        });

                    if let Err(e) = worker_result {
                        error!("failed to spawn vhost_vsock worker: {}", e);
                        return;
                    }
                }
            }
        }
    }
}

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

    use std::convert::TryInto;

    #[test]
    fn ack_features() {
        let cid = 5;
        let features: u64 = (1 << 20) | (1 << 49) | (1 << 2) | (1 << 19);
        let mut acked_features: u64 = 0;
        let mut unavailable_features: u64 = 0;

        let mut vsock = Vsock::new_for_testing(cid, features);
        assert_eq!(acked_features, vsock.acked_features());

        acked_features |= 1 << 2;
        vsock.ack_features(acked_features);
        assert_eq!(acked_features, vsock.acked_features());

        acked_features |= 1 << 49;
        vsock.ack_features(acked_features);
        assert_eq!(acked_features, vsock.acked_features());

        acked_features |= 1 << 60;
        unavailable_features |= 1 << 60;
        vsock.ack_features(acked_features);
        assert_eq!(
            acked_features & !unavailable_features,
            vsock.acked_features()
        );

        acked_features |= 1 << 1;
        unavailable_features |= 1 << 1;
        vsock.ack_features(acked_features);
        assert_eq!(
            acked_features & !unavailable_features,
            vsock.acked_features()
        );
    }

    #[test]
    fn read_config() {
        let cid = 0xfca9a559fdcb9756;
        let vsock = Vsock::new_for_testing(cid, 0);

        let mut buf = [0 as u8; 8];
        vsock.read_config(0, &mut buf);
        assert_eq!(cid, u64::from_le_bytes(buf));

        vsock.read_config(0, &mut buf[..4]);
        assert_eq!(
            (cid & 0xffffffff) as u32,
            u32::from_le_bytes(buf[..4].try_into().unwrap())
        );

        vsock.read_config(4, &mut buf[..4]);
        assert_eq!(
            (cid >> 32) as u32,
            u32::from_le_bytes(buf[..4].try_into().unwrap())
        );

        let data: [u8; 8] = [8, 226, 5, 46, 159, 59, 89, 77];
        buf.copy_from_slice(&data);

        vsock.read_config(12, &mut buf);
        assert_eq!(&buf, &data);
    }

    #[test]
    fn features() {
        let cid = 5;
        let features: u64 = 0xfc195ae8db88cff9;

        let vsock = Vsock::new_for_testing(cid, features);
        assert_eq!(features, vsock.features());
    }
}
<|endoftext|>