<commit_before>extern crate serde;

use std::fmt;
use std::ops::{Deref, DerefMut};

use {Error, Result};
use api::Pushable;
use thread::{Context, Thread, ThreadInternal};
use types::{VmTag, VmIndex};
use value::{Def, Value};
use self::serde::ser::{self, Serialize};

pub fn to_value<T>(thread: &Thread, value: &T) -> Result<Value>
    where T: Serialize
{
    let mut context = thread.context();
    let mut serializer = Serializer {
        thread: thread,
        context: &mut context,
    };
    value.serialize(&mut serializer)?;
    Ok(serializer.context.stack.pop())
}

impl ser::Error for Error {
    fn custom<T>(msg: T) -> Self
        where T: fmt::Display
    {
        Error::Message(format!("{}", msg))
    }
}

struct Serializer<'t> {
    thread: &'t Thread,
    context: &'t mut Context,
}

impl<'t> Serializer<'t> {
    fn to_value<T>(&mut self, value: T) -> Result<()>
        where T: Pushable<'t>
    {
        value.push(self.thread, self.context)
    }

    fn alloc(&mut self, tag: VmTag, values: VmIndex) -> Result<()> {
        let value = self.context
            .gc
            .alloc(Def {
                       tag: tag,
                       elems: &self.context.stack[self.context.stack.len() - values..],
                   })?;
        for _ in 0..values {
            self.context.stack.pop();
        }
        self.context.stack.push(Value::Data(value));
        Ok(())
    }
}

struct RecordSerializer<'s, 'vm: 's> {
    serializer: &'s mut Serializer<'vm>,
    variant_index: VmTag,
    values: VmIndex,
}

impl<'s, 'vm> Deref for RecordSerializer<'s, 'vm> {
    type Target = Serializer<'vm>;
    fn deref(&self) -> &Self::Target {
        self.serializer
    }
}

impl<'s, 'vm> DerefMut for RecordSerializer<'s, 'vm> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.serializer
    }
}

impl<'s, 'vm> RecordSerializer<'s, 'vm> {
    fn new(serializer: &'s mut Serializer<'vm>, variant_index: u32) -> Self {
        RecordSerializer {
            serializer: serializer,
            variant_index: variant_index,
            values: 0,
        }
    }
}

impl<'a, 'vm> ser::Serializer for &'a mut Serializer<'vm> {
    type Ok = ();

    // The error type when some error occurs during serialization.
    type Error = Error;

    // Associated types for keeping track of additional state while serializing
    // compound data structures like sequences and maps. In this case no
    // additional state is required beyond what is already stored in the
    // Serializer struct.
    type SerializeSeq = RecordSerializer<'a, 'vm>;
    type SerializeTuple = RecordSerializer<'a, 'vm>;
    type SerializeTupleStruct = RecordSerializer<'a, 'vm>;
    type SerializeTupleVariant = RecordSerializer<'a, 'vm>;
    type SerializeMap = RecordSerializer<'a, 'vm>;
    type SerializeStruct = RecordSerializer<'a, 'vm>;
    type SerializeStructVariant = RecordSerializer<'a, 'vm>;

    // Here we go with the simple methods. The following 12 methods receive one
    // of the primitive types of the data model and map it to JSON by appending
    // into the output string.
    fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
        self.to_value(v)
    }

    // JSON does not distinguish between different sizes of integers, so all
    // signed integers will be serialized the same and all unsigned integers
    // will be serialized the same. Other formats, especially compact binary
    // formats, may need independent logic for the different sizes.
    fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
        self.serialize_i64(v as i64)
    }

    // Not particularly efficient but this is example code anyway. A more
    // performant approach would be to use the `itoa` crate.
    fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
        self.to_value(v as isize)
    }

    fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
        self.serialize_u64(v as u64)
    }

    fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
        self.serialize_u64(v as u64)
    }

    fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
        self.serialize_u64(v as u64)
    }

    fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
        self.to_value(v as isize)
    }

    fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
        self.serialize_f64(v as f64)
    }

    fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
        self.to_value(v)
    }

    fn serialize_char(self, v: char) -> Result<Self::Ok> {
        self.serialize_str(&v.to_string())
    }

    fn serialize_str(self, v: &str) -> Result<Self::Ok> {
        self.to_value(v)
    }

    fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
        self.to_value(v)
    }

    // An absent optional is represented as the JSON `null`.
    fn serialize_none(self) -> Result<Self::Ok> {
        self.serialize_unit()
    }

    // A present optional is represented as just the contained value. Note that
    // this is a lossy representation. For example the values `Some(())` and
    // `None` both serialize as just `null`. Unfortunately this is typically
    // what people expect when working with JSON. Other formats are encouraged
    // to behave more intelligently if possible.
    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok>
        where T: ?Sized + Serialize
    {
        value.serialize(self)
    }

    fn serialize_unit(self) -> Result<Self::Ok> {
        self.context.stack.push(Value::Tag(0));
        Ok(())
    }

    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> {
        self.serialize_unit()
    }

    fn serialize_unit_variant(self,
                              _name: &'static str,
                              variant_index: u32,
                              _variant: &'static str)
                              -> Result<Self::Ok> {
        self.context.stack.push(Value::Tag(variant_index));
        Ok(())
    }

    // As is done here, serializers are encouraged to treat newtype structs as
    // insignificant wrappers around the data they contain.
    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Self::Ok>
        where T: ?Sized + Serialize
    {
        value.serialize(self)
    }

    // Note that newtype variant (and all of the other variant serialization
    // methods) refer exclusively to the "externally tagged" enum
    // representation.
    //
    // Serialize this to JSON in externally tagged form as `{ NAME: VALUE }`.
    fn serialize_newtype_variant<T>(self,
                                    _name: &'static str,
                                    variant_index: u32,
                                    _variant: &'static str,
                                    value: &T)
                                    -> Result<Self::Ok>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut *self)?;
        self.alloc(variant_index, 1)
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
        Ok(RecordSerializer::new(self, 0))
    }

    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_struct(self,
                              _name: &'static str,
                              len: usize)
                              -> Result<Self::SerializeTupleStruct> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_variant(self,
                               _name: &'static str,
                               variant_index: u32,
                               _variant: &'static str,
                               _len: usize)
                               -> Result<Self::SerializeTupleVariant> {
        Ok(RecordSerializer::new(self, variant_index))
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
        Ok(RecordSerializer::new(self, 0))
    }

    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
        self.serialize_map(Some(len))
    }

    fn serialize_struct_variant(self,
                                _name: &'static str,
                                variant_index: u32,
                                _variant: &'static str,
                                _len: usize)
                                -> Result<Self::SerializeStructVariant> {
        Ok(RecordSerializer::new(self, variant_index))
    }
}

impl<'a, 'vm> ser::SerializeSeq for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeTuple for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeTupleStruct for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeTupleVariant for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeMap for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_key<T>(&mut self, _key: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        Ok(())
    }

    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeStruct for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

// Similar to `SerializeTupleVariant`, here the `end` method is responsible for
// closing both of the curly braces opened by `serialize_struct_variant`.
impl<'a, 'vm> ser::SerializeStructVariant for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use thread::{RootedThread, ThreadInternal};

    fn make_value<'vm, T>(thread: &'vm Thread, value: T) -> Value
        where T: Pushable<'vm>
    {
        let mut context = thread.context();
        value.push(thread, &mut context).unwrap();
        context.stack.pop()
    }

    #[test]
    fn bool() {
        let thread = RootedThread::new();
        assert_eq!(to_value(&thread, &true).unwrap(), Value::Tag(1));
    }

    #[derive(Serialize)]
    struct Record {
        test: i32,
        string: String,
    }

    #[test]
    fn record() {
        let thread = RootedThread::new();
        let actual = to_value(&thread,
                              &Record {
                                   test: 123,
                                   string: "abc".to_string(),
                               })
                .unwrap();
        assert_eq!(actual,
                   make_value(&thread,
                              record! {
                       test => 123,
                       string => "abc"
                   }));
    }

    #[derive(Serialize)]
    enum Enum {
        A(String),
        B(i32),
    }

    #[test]
    fn enum_() {
        let thread = RootedThread::new();

        let actual = to_value(&thread, &Enum::A("abc".to_string())).unwrap();
        let s = make_value(&thread, "abc");
        assert_eq!(actual,
                   Value::Data(thread
                                   .context()
                                   .gc
                                   .alloc(Def {
                                              tag: 0,
                                              elems: &[s],
                                          })
                                   .unwrap()));

        let actual = to_value(&thread, &Enum::B(1232)).unwrap();
        assert_eq!(actual,
                   Value::Data(thread
                                   .context()
                                   .gc
                                   .alloc(Def {
                                              tag: 1,
                                              elems: &[Value::Int(1232)],
                                          })
                                   .unwrap()));
    }
}
<commit_msg>feat(vm): Add serialization Pushable wrapper<commit_after>extern crate serde;

use std::fmt;
use std::ops::{Deref, DerefMut};

use {Error, Result};
use api::Pushable;
use thread::{Context, Thread, ThreadInternal};
use types::{VmTag, VmIndex};
use value::{Def, Value};
use self::serde::ser::{self, Serialize};

pub fn to_value<T>(thread: &Thread, value: &T) -> Result<Value>
    where T: ?Sized + Serialize
{
    let mut context = thread.context();
    Ser(value).push(thread, &mut context)?;
    Ok(context.stack.pop())
}

pub struct Ser<T>(pub T);

impl<'vm, T> Pushable<'vm> for Ser<T>
    where T: Serialize
{
    fn push(self, thread: &'vm Thread, context: &mut Context) -> Result<()> {
        let mut serializer = Serializer {
            thread: thread,
            context: context,
        };
        self.0.serialize(&mut serializer)
    }
}

impl ser::Error for Error {
    fn custom<T>(msg: T) -> Self
        where T: fmt::Display
    {
        Error::Message(format!("{}", msg))
    }
}

struct Serializer<'t> {
    thread: &'t Thread,
    context: &'t mut Context,
}

impl<'t> Serializer<'t> {
    fn to_value<T>(&mut self, value: T) -> Result<()>
        where T: Pushable<'t>
    {
        value.push(self.thread, self.context)
    }

    fn alloc(&mut self, tag: VmTag, values: VmIndex) -> Result<()> {
        let value = self.context
            .gc
            .alloc(Def {
                       tag: tag,
                       elems: &self.context.stack[self.context.stack.len() - values..],
                   })?;
        for _ in 0..values {
            self.context.stack.pop();
        }
        self.context.stack.push(Value::Data(value));
        Ok(())
    }
}

struct RecordSerializer<'s, 'vm: 's> {
    serializer: &'s mut Serializer<'vm>,
    variant_index: VmTag,
    values: VmIndex,
}

impl<'s, 'vm> Deref for RecordSerializer<'s, 'vm> {
    type Target = Serializer<'vm>;
    fn deref(&self) -> &Self::Target {
        self.serializer
    }
}

impl<'s, 'vm> DerefMut for RecordSerializer<'s, 'vm> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.serializer
    }
}

impl<'s, 'vm> RecordSerializer<'s, 'vm> {
    fn new(serializer: &'s mut Serializer<'vm>, variant_index: u32) -> Self {
        RecordSerializer {
            serializer: serializer,
            variant_index: variant_index,
            values: 0,
        }
    }
}

impl<'a, 'vm> ser::Serializer for &'a mut Serializer<'vm> {
    type Ok = ();

    // The error type when some error occurs during serialization.
    type Error = Error;

    // Associated types for keeping track of additional state while serializing
    // compound data structures like sequences and maps. In this case no
    // additional state is required beyond what is already stored in the
    // Serializer struct.
    type SerializeSeq = RecordSerializer<'a, 'vm>;
    type SerializeTuple = RecordSerializer<'a, 'vm>;
    type SerializeTupleStruct = RecordSerializer<'a, 'vm>;
    type SerializeTupleVariant = RecordSerializer<'a, 'vm>;
    type SerializeMap = RecordSerializer<'a, 'vm>;
    type SerializeStruct = RecordSerializer<'a, 'vm>;
    type SerializeStructVariant = RecordSerializer<'a, 'vm>;

    // Here we go with the simple methods. The following 12 methods receive one
    // of the primitive types of the data model and map it to JSON by appending
    // into the output string.
    fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
        self.to_value(v)
    }

    // JSON does not distinguish between different sizes of integers, so all
    // signed integers will be serialized the same and all unsigned integers
    // will be serialized the same. Other formats, especially compact binary
    // formats, may need independent logic for the different sizes.
    fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
        self.serialize_i64(v as i64)
    }

    // Not particularly efficient but this is example code anyway. A more
    // performant approach would be to use the `itoa` crate.
    fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
        self.to_value(v as isize)
    }

    fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
        self.serialize_u64(v as u64)
    }

    fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
        self.serialize_u64(v as u64)
    }

    fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
        self.serialize_u64(v as u64)
    }

    fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
        self.to_value(v as isize)
    }

    fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
        self.serialize_f64(v as f64)
    }

    fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
        self.to_value(v)
    }

    fn serialize_char(self, v: char) -> Result<Self::Ok> {
        self.serialize_str(&v.to_string())
    }

    fn serialize_str(self, v: &str) -> Result<Self::Ok> {
        self.to_value(v)
    }

    fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
        self.to_value(v)
    }

    // An absent optional is represented as the JSON `null`.
    fn serialize_none(self) -> Result<Self::Ok> {
        self.serialize_unit()
    }

    // A present optional is represented as just the contained value. Note that
    // this is a lossy representation. For example the values `Some(())` and
    // `None` both serialize as just `null`. Unfortunately this is typically
    // what people expect when working with JSON. Other formats are encouraged
    // to behave more intelligently if possible.
    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok>
        where T: ?Sized + Serialize
    {
        value.serialize(self)
    }

    fn serialize_unit(self) -> Result<Self::Ok> {
        self.context.stack.push(Value::Tag(0));
        Ok(())
    }

    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> {
        self.serialize_unit()
    }

    fn serialize_unit_variant(self,
                              _name: &'static str,
                              variant_index: u32,
                              _variant: &'static str)
                              -> Result<Self::Ok> {
        self.context.stack.push(Value::Tag(variant_index));
        Ok(())
    }

    // As is done here, serializers are encouraged to treat newtype structs as
    // insignificant wrappers around the data they contain.
    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Self::Ok>
        where T: ?Sized + Serialize
    {
        value.serialize(self)
    }

    // Note that newtype variant (and all of the other variant serialization
    // methods) refer exclusively to the "externally tagged" enum
    // representation.
    //
    // Serialize this to JSON in externally tagged form as `{ NAME: VALUE }`.
    fn serialize_newtype_variant<T>(self,
                                    _name: &'static str,
                                    variant_index: u32,
                                    _variant: &'static str,
                                    value: &T)
                                    -> Result<Self::Ok>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut *self)?;
        self.alloc(variant_index, 1)
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
        Ok(RecordSerializer::new(self, 0))
    }

    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_struct(self,
                              _name: &'static str,
                              len: usize)
                              -> Result<Self::SerializeTupleStruct> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_variant(self,
                               _name: &'static str,
                               variant_index: u32,
                               _variant: &'static str,
                               _len: usize)
                               -> Result<Self::SerializeTupleVariant> {
        Ok(RecordSerializer::new(self, variant_index))
    }

    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
        Ok(RecordSerializer::new(self, 0))
    }

    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
        self.serialize_map(Some(len))
    }

    fn serialize_struct_variant(self,
                                _name: &'static str,
                                variant_index: u32,
                                _variant: &'static str,
                                _len: usize)
                                -> Result<Self::SerializeStructVariant> {
        Ok(RecordSerializer::new(self, variant_index))
    }
}

impl<'a, 'vm> ser::SerializeSeq for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeTuple for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeTupleStruct for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeTupleVariant for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeMap for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_key<T>(&mut self, _key: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        Ok(())
    }

    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

impl<'a, 'vm> ser::SerializeStruct for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

// Similar to `SerializeTupleVariant`, here the `end` method is responsible for
// closing both of the curly braces opened by `serialize_struct_variant`.
impl<'a, 'vm> ser::SerializeStructVariant for RecordSerializer<'a, 'vm> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        value.serialize(&mut **self)?;
        self.values += 1;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok> {
        self.serializer.alloc(self.variant_index, self.values)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use thread::{RootedThread, ThreadInternal};

    fn make_value<'vm, T>(thread: &'vm Thread, value: T) -> Value
        where T: Pushable<'vm>
    {
        let mut context = thread.context();
        value.push(thread, &mut context).unwrap();
        context.stack.pop()
    }

    #[test]
    fn bool() {
        let thread = RootedThread::new();
        assert_eq!(to_value(&thread, &true).unwrap(), Value::Tag(1));
    }

    #[derive(Serialize)]
    struct Record {
        test: i32,
        string: String,
    }

    #[test]
    fn record() {
        let thread = RootedThread::new();
        let actual = to_value(&thread,
                              &Record {
                                   test: 123,
                                   string: "abc".to_string(),
                               })
                .unwrap();
        assert_eq!(actual,
                   make_value(&thread,
                              record! {
                       test => 123,
                       string => "abc"
                   }));
    }

    #[derive(Serialize)]
    enum Enum {
        A(String),
        B(i32),
    }

    #[test]
    fn enum_() {
        let thread = RootedThread::new();

        let actual = to_value(&thread, &Enum::A("abc".to_string())).unwrap();
        let s = make_value(&thread, "abc");
        assert_eq!(actual,
                   Value::Data(thread
                                   .context()
                                   .gc
                                   .alloc(Def {
                                              tag: 0,
                                              elems: &[s],
                                          })
                                   .unwrap()));

        let actual = to_value(&thread, &Enum::B(1232)).unwrap();
        assert_eq!(actual,
                   Value::Data(thread
                                   .context()
                                   .gc
                                   .alloc(Def {
                                              tag: 1,
                                              elems: &[Value::Int(1232)],
                                          })
                                   .unwrap()));
    }
}
<|endoftext|>


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

use syntax::ast;
use syntax::ast::P;
use syntax::ext::base::ExtCtxt;
use syntax::codemap::DUMMY_SP;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a, 'b, 'c> {
  builder: &'a mut Builder,
  cx: &'b ExtCtxt<'c>,
}

impl<'a, 'b, 'c> BuildSetters<'a, 'b, 'c> {
  pub fn new(builder: &'a mut Builder, cx: &'b ExtCtxt<'c>)
             -> BuildSetters<'a, 'b, 'c> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a, 'b, 'c> node::RegVisitor for BuildSetters<'a, 'b, 'c> {
  fn visit_prim_reg<'a>(&'a mut self, path: &Vec<String>,
      reg: &'a node::Reg, _width: node::RegWidth, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $name<'a> {
      value: $packed_ty,
      mask: $packed_ty,
      reg: &'a $reg_ty,
    }
  );
  item.unwrap()
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>)
                 -> P<ast::Item> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let item = quote_item!(cx,
    #[doc="Create a new updater"]
    pub fn new(reg: &'a $reg_ty) -> $setter_ty {
      $setter_ty {
        value: 0,
        mask: 0,
        reg: reg,
      }
    });
  item.unwrap()
}

fn build_drop<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  // no need to read write-only registers
  let wo_reg: bool = fields.iter().all(|f| f.access == node::WriteOnly);
  let initial_value =
    if wo_reg {
      quote_expr!(cx, 0)
    } else {
      quote_expr!(cx, self.reg.value.get())
    };

  let item = quote_item!(cx,
    #[unsafe_destructor]
    #[doc = "This performs the register update"]
    impl<'a> Drop for $setter_ty<'a> {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = $initial_value & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done<'a>(cx: &'a ExtCtxt) -> P<ast::Method>
{
  quote_method!(cx,
    #[doc="Commit changes to register. This is to allow chains of `set_*` \
           invocations to be used as a statement."]
    pub fn done(self) {}
  )
}

fn build_impl<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path);
  let setter_ty: P<ast::Ty> = cx.ty_ident(
    DUMMY_SP,
    utils::setter_name(cx, path));
  let methods: Vec<P<ast::Method>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done: P<ast::Method> = build_done(cx);
  let impl_ = quote_item!(cx,
    #[allow(dead_code)]
    impl<'a> $setter_ty<'a> {
      $new
      $methods
      $done
    }
    );
  impl_.unwrap()
}

fn build_field_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> Option<P<ast::Method>>
{
  match field.access {
    node::ReadOnly => None,
    node::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                          field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from_str("set_")+field.name.node).as_slice());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}

fn build_field_clear_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from_str("clear_")+field.name.node).as_slice());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}
<commit_msg>ioreg/setter: Clean up redundant lifetimes<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::ast;
use syntax::ast::P;
use syntax::ext::base::ExtCtxt;
use syntax::codemap::DUMMY_SP;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a, 'b, 'c> {
  builder: &'a mut Builder,
  cx: &'b ExtCtxt<'c>,
}

impl<'a, 'b, 'c> BuildSetters<'a, 'b, 'c> {
  pub fn new(builder: &'a mut Builder, cx: &'b ExtCtxt<'c>)
             -> BuildSetters<'a, 'b, 'c> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a, 'b, 'c> node::RegVisitor for BuildSetters<'a, 'b, 'c> {
  fn visit_prim_reg<'a>(&'a mut self, path: &Vec<String>,
      reg: &'a node::Reg, _width: node::RegWidth, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $name<'a> {
      value: $packed_ty,
      mask: $packed_ty,
      reg: &'a $reg_ty,
    }
  );
  item.unwrap()
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>)
                 -> P<ast::Item> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let item = quote_item!(cx,
    #[doc="Create a new updater"]
    pub fn new(reg: &'a $reg_ty) -> $setter_ty {
      $setter_ty {
        value: 0,
        mask: 0,
        reg: reg,
      }
    });
  item.unwrap()
}

fn build_drop(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  // no need to read write-only registers
  let wo_reg: bool = fields.iter().all(|f| f.access == node::WriteOnly);
  let initial_value =
    if wo_reg {
      quote_expr!(cx, 0)
    } else {
      quote_expr!(cx, self.reg.value.get())
    };

  let item = quote_item!(cx,
    #[unsafe_destructor]
    #[doc = "This performs the register update"]
    impl<'a> Drop for $setter_ty<'a> {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = $initial_value & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done(cx: &ExtCtxt) -> P<ast::Method>
{
  quote_method!(cx,
    #[doc="Commit changes to register. This is to allow chains of `set_*` \
           invocations to be used as a statement."]
    pub fn done(self) {}
  )
}

fn build_impl(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
              fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path);
  let setter_ty: P<ast::Ty> = cx.ty_ident(
    DUMMY_SP,
    utils::setter_name(cx, path));
  let methods: Vec<P<ast::Method>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done: P<ast::Method> = build_done(cx);
  let impl_ = quote_item!(cx,
    #[allow(dead_code)]
    impl<'a> $setter_ty<'a> {
      $new
      $methods
      $done
    }
    );
  impl_.unwrap()
}

fn build_field_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  field: &node::Field) -> Option<P<ast::Method>>
{
  match field.access {
    node::ReadOnly => None,
    node::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from_str("set_")+field.name.node).as_slice());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}

fn build_field_clear_fn(cx: &ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from_str("clear_")+field.name.node).as_slice());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}
<|endoftext|>


<commit_before>extern crate regex;

use self::regex::Regex;

pub fn is_test_file(path: &String) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^(features/step_definitions/|test/|spec/|tests/|src/test/|\w*Tests/)").unwrap();
    }
    RE.is_match(path.as_str())
}

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

    // Swift/XCTest/XCUI/Quick

    #[test]
    fn is_test_file_detects_swift_xctest_files() {
        let s = String::from("AutomotiveTests/Vehicles/VehicleAttributesVehicleTests.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_swift_xcui_files() {
        let s = String::from("AutomotiveUITests/Vehicles/VehicleAttributesVehicleUITests.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_swift_quick_files() {
        let s = String::from("AutomotiveTests/Vehicles/VehicleAttributesVehicleSpec.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_swift_quick_ui_files() {
        let s = String::from("AutomotiveUITests/Vehicles/VehicleAttributesVehicleUISpec.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_swift_implementation_files() {
        let s = String::from("Automotive/Vehicles/VehicleAttributesVehicle.swift");
        assert_eq!(is_test_file(&s), false);
    }

    // Ruby Gem

    #[test]
    fn is_test_file_detects_ruby_gem_test_files() {
        let s = String::from("spec/foo_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_ruby_gem_test_files_under_lib() {
        let s = String::from("spec/lib/foo_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_ruby_gem_implementation_files() {
        let s = String::from("lib/foo.rb");
        assert_eq!(is_test_file(&s), false);
    }

    // Rake Tasks

    #[test]
    fn is_test_file_detects_rake_test_files() {
        let s = String::from("spec/lib/tasks/bar/foo_rake_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_rake_implementation_files() {
        let s = String::from("lib/tasks/bar/foo.rake");
        assert_eq!(is_test_file(&s), false);
    }

    // Rails

    #[test]
    fn is_test_file_does_not_detect_rails_controller_implementation_files() {
        let s = String::from("app/controllers/tasks_controller.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_model_implementation_files() {
        let s = String::from("app/models/task.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_helper_implementation_files() {
        let s = String::from("app/helpers/hoopty.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_mailer_implementation_files() {
        let s = String::from("app/mailers/hoopty_mailer.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_lib_implementation_files() {
        let s = String::from("lib/foo.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_rake_implementation_files() {
        let s = String::from("bar/foo.rake");
        assert_eq!(is_test_file(&s), false);
    }

    // Rails Minitest

    #[test]
    fn is_test_file_detects_minitest_controller_test_files() {
        let s = String::from("test/controllers/tasks_controller_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_model_test_files() {
        let s = String::from("test/models/task_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_helper_test_files() {
        let s = String::from("test/helpers/hoopty_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_mailer_test_files() {
        let s = String::from("test/mailers/hoopty_mailer_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_lib_test_files() {
        let s = String::from("test/foo_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_rake_test_files() {
        let s = String::from("test/bar/foo_rake_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Rails RSpec

    #[test]
    fn is_test_file_detects_rspec_controller_test_files() {
        let s = String::from("spec/controllers/tasks_controller_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_model_test_files() {
        let s = String::from("spec/models/task_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_helper_test_files() {
        let s = String::from("spec/helpers/hoopty_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_mailer_test_files() {
        let s = String::from("spec/mailers/hoopty_mailer_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_lib_test_files() {
        let s = String::from("spec/foo_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_rake_test_files() {
        let s = String::from("spec/bar/foo_rake_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Hanami App Arch

    #[test]
    fn is_test_file_does_not_detect_hanami_app_controller_implementation_files() {
        let s = String::from("app/controllers/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_app_view_implementation_files() {
        let s = String::from("app/views/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_app_lib_implementation_files() {
        let s = String::from("lib/foo/bar/car/my_lib.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_app_general_implementation_files() {
        let s = String::from("app/fulfiller.rb");
        assert_eq!(is_test_file(&s), false);
    }

    // Hanami App Arch RSpec

    #[test]
    fn is_test_file_detects_hanami_app_rspec_controller_test_files() {
        let s = String::from("spec/controllers/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_app_rspec_view_test_files() {
        let s = String::from("spec/views/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_app_rspec_lib_test_files() {
        let s = String::from("spec/foo/bar/car/my_lib_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_app_rspec_general_test_files() {
        let s = String::from("spec/fulfiller_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Hanami Container Arch

    #[test]
    fn is_test_file_does_not_detect_hanami_container_controller_implementation_files() {
        let s = String::from("apps/web/controllers/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_container_view_implementation_files() {
        let s = String::from("apps/web/views/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_container_lib_implementation_files() {
        let s = String::from("lib/foo/bar/car/my_lib.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_container_general_implementation_files() {
        let s = String::from("apps/offer_service/fulfiller.rb");
        assert_eq!(is_test_file(&s), false);
    }

    // Hanami Container Arch RSpec

    #[test]
    fn is_test_file_detects_hanami_container_rspec_controller_test_files() {
        let s = String::from("spec/web/controllers/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_container_rspec_view_test_files() {
        let s = String::from("spec/web/views/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_container_rspec_lib_test_files() {
        let s = String::from("spec/foo/bar/car/my_lib_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_container_rspec_general_test_files() {
        let s = String::from("spec/offer_service/fulfiller_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Elixer ExUnit

    #[test]
    fn is_test_file_detects_elixer_exunit_files() {
        let s = String::from("test/lib/my_awesome_app/supervisor_test.exs");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_elixer_implementation_files() {
        let s = String::from("lib/my_awesome_app/supervisor.ex");
        assert_eq!(is_test_file(&s), false);
    }

    // Jasmine JavaScript

    #[test]
    fn is_test_file_detects_js_jasmine_test_files() {
        let s = String::from("spec/foo/bar/jacked_spec.js");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_js_implementation_files() {
        let s = String::from("foo/bar/jacked.js");
        assert_eq!(is_test_file(&s), false);
    }

    // Python

    #[test]
    fn is_test_file_detects_python_test_files() {
        let s = String::from("test/test_toaster.py");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_python_implementation_files() {
        let s = String::from("toaster.py");
        assert_eq!(is_test_file(&s), false);
    }

    // Cucumber Ruby

    #[test]
    fn is_test_file_detects_cucumber_step_definition_files() {
        let s = String::from("features/step_definitions/project_management_steps.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_cucumber_feature_files() {
        let s = String::from("features/project_management.feature");
        assert_eq!(is_test_file(&s), false);
    }

    // Java Maven JUnit

    #[test]
    fn is_test_file_detects_java_maven_junit_test_files() {
        let s = String::from("src/test/java/com/example/SomethingTest.java");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_java_implementation_files() {
        let s = String::from("src/main/java/com/example/Something.java");
        assert_eq!(is_test_file(&s), false);
    }

    // Scala ScalaTest

    #[test]
    fn is_test_file_detects_scala_scalatest_test_files() {
        let s = String::from("src/test/scala/com/example/SomethingTest.scala");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_scala_scalatest_spec_files() {
        let s = String::from("src/test/scala/com/example/SomethingSpec.scala");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_scala_scalatest_suite_files() {
        let s = String::from("src/test/scala/com/example/SomethingSuite.scala");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_scala_implementation_files() {
        let s = String::from("src/main/scala/com/example/Something.scala");
        assert_eq!(is_test_file(&s), false);
    }
}
<commit_msg>Change signature of is_test_file to take &str<commit_after>extern crate regex;

use self::regex::Regex;

pub fn is_test_file(path: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^(features/step_definitions/|test/|spec/|tests/|src/test/|\w*Tests/)").unwrap();
    }
    RE.is_match(path)
}

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

    // Swift/XCTest/XCUI/Quick

    #[test]
    fn is_test_file_detects_swift_xctest_files() {
        let s = String::from("AutomotiveTests/Vehicles/VehicleAttributesVehicleTests.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_swift_xcui_files() {
        let s = String::from("AutomotiveUITests/Vehicles/VehicleAttributesVehicleUITests.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_swift_quick_files() {
        let s = String::from("AutomotiveTests/Vehicles/VehicleAttributesVehicleSpec.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_swift_quick_ui_files() {
        let s = String::from("AutomotiveUITests/Vehicles/VehicleAttributesVehicleUISpec.swift");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_swift_implementation_files() {
        let s = String::from("Automotive/Vehicles/VehicleAttributesVehicle.swift");
        assert_eq!(is_test_file(&s), false);
    }

    // Ruby Gem

    #[test]
    fn is_test_file_detects_ruby_gem_test_files() {
        let s = String::from("spec/foo_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_ruby_gem_test_files_under_lib() {
        let s = String::from("spec/lib/foo_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_ruby_gem_implementation_files() {
        let s = String::from("lib/foo.rb");
        assert_eq!(is_test_file(&s), false);
    }

    // Rake Tasks

    #[test]
    fn is_test_file_detects_rake_test_files() {
        let s = String::from("spec/lib/tasks/bar/foo_rake_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_rake_implementation_files() {
        let s = String::from("lib/tasks/bar/foo.rake");
        assert_eq!(is_test_file(&s), false);
    }

    // Rails

    #[test]
    fn is_test_file_does_not_detect_rails_controller_implementation_files() {
        let s = String::from("app/controllers/tasks_controller.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_model_implementation_files() {
        let s = String::from("app/models/task.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_helper_implementation_files() {
        let s = String::from("app/helpers/hoopty.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_mailer_implementation_files() {
        let s = String::from("app/mailers/hoopty_mailer.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_lib_implementation_files() {
        let s = String::from("lib/foo.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_rails_rake_implementation_files() {
        let s = String::from("bar/foo.rake");
        assert_eq!(is_test_file(&s), false);
    }

    // Rails Minitest

    #[test]
    fn is_test_file_detects_minitest_controller_test_files() {
        let s = String::from("test/controllers/tasks_controller_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_model_test_files() {
        let s = String::from("test/models/task_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_helper_test_files() {
        let s = String::from("test/helpers/hoopty_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_mailer_test_files() {
        let s = String::from("test/mailers/hoopty_mailer_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_lib_test_files() {
        let s = String::from("test/foo_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_minitest_rake_test_files() {
        let s = String::from("test/bar/foo_rake_test.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Rails RSpec

    #[test]
    fn is_test_file_detects_rspec_controller_test_files() {
        let s = String::from("spec/controllers/tasks_controller_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_model_test_files() {
        let s = String::from("spec/models/task_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_helper_test_files() {
        let s = String::from("spec/helpers/hoopty_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_mailer_test_files() {
        let s = String::from("spec/mailers/hoopty_mailer_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_lib_test_files() {
        let s = String::from("spec/foo_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_rspec_rake_test_files() {
        let s = String::from("spec/bar/foo_rake_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Hanami App Arch

    #[test]
    fn is_test_file_does_not_detect_hanami_app_controller_implementation_files() {
        let s = String::from("app/controllers/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_app_view_implementation_files() {
        let s = String::from("app/views/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_app_lib_implementation_files() {
        let s = String::from("lib/foo/bar/car/my_lib.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_app_general_implementation_files() {
        let s = String::from("app/fulfiller.rb");
        assert_eq!(is_test_file(&s), false);
    }

    // Hanami App Arch RSpec

    #[test]
    fn is_test_file_detects_hanami_app_rspec_controller_test_files() {
        let s = String::from("spec/controllers/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_app_rspec_view_test_files() {
        let s = String::from("spec/views/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_app_rspec_lib_test_files() {
        let s = String::from("spec/foo/bar/car/my_lib_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_app_rspec_general_test_files() {
        let s = String::from("spec/fulfiller_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Hanami Container Arch

    #[test]
    fn is_test_file_does_not_detect_hanami_container_controller_implementation_files() {
        let s = String::from("apps/web/controllers/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_container_view_implementation_files() {
        let s = String::from("apps/web/views/users/create.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_container_lib_implementation_files() {
        let s = String::from("lib/foo/bar/car/my_lib.rb");
        assert_eq!(is_test_file(&s), false);
    }

    #[test]
    fn is_test_file_does_not_detect_hanami_container_general_implementation_files() {
        let s = String::from("apps/offer_service/fulfiller.rb");
        assert_eq!(is_test_file(&s), false);
    }

    // Hanami Container Arch RSpec

    #[test]
    fn is_test_file_detects_hanami_container_rspec_controller_test_files() {
        let s = String::from("spec/web/controllers/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_container_rspec_view_test_files() {
        let s = String::from("spec/web/views/users/create_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_container_rspec_lib_test_files() {
        let s = String::from("spec/foo/bar/car/my_lib_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_hanami_container_rspec_general_test_files() {
        let s = String::from("spec/offer_service/fulfiller_spec.rb");
        assert_eq!(is_test_file(&s), true);
    }

    // Elixer ExUnit

    #[test]
    fn is_test_file_detects_elixer_exunit_files() {
        let s = String::from("test/lib/my_awesome_app/supervisor_test.exs");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_elixer_implementation_files() {
        let s = String::from("lib/my_awesome_app/supervisor.ex");
        assert_eq!(is_test_file(&s), false);
    }

    // Jasmine JavaScript

    #[test]
    fn is_test_file_detects_js_jasmine_test_files() {
        let s = String::from("spec/foo/bar/jacked_spec.js");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_js_implementation_files() {
        let s = String::from("foo/bar/jacked.js");
        assert_eq!(is_test_file(&s), false);
    }

    // Python

    #[test]
    fn is_test_file_detects_python_test_files() {
        let s = String::from("test/test_toaster.py");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_python_implementation_files() {
        let s = String::from("toaster.py");
        assert_eq!(is_test_file(&s), false);
    }

    // Cucumber Ruby

    #[test]
    fn is_test_file_detects_cucumber_step_definition_files() {
        let s = String::from("features/step_definitions/project_management_steps.rb");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_cucumber_feature_files() {
        let s = String::from("features/project_management.feature");
        assert_eq!(is_test_file(&s), false);
    }

    // Java Maven JUnit

    #[test]
    fn is_test_file_detects_java_maven_junit_test_files() {
        let s = String::from("src/test/java/com/example/SomethingTest.java");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_java_implementation_files() {
        let s = String::from("src/main/java/com/example/Something.java");
        assert_eq!(is_test_file(&s), false);
    }

    // Scala ScalaTest

    #[test]
    fn is_test_file_detects_scala_scalatest_test_files() {
        let s = String::from("src/test/scala/com/example/SomethingTest.scala");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_scala_scalatest_spec_files() {
        let s = String::from("src/test/scala/com/example/SomethingSpec.scala");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_detects_scala_scalatest_suite_files() {
        let s = String::from("src/test/scala/com/example/SomethingSuite.scala");
        assert_eq!(is_test_file(&s), true);
    }

    #[test]
    fn is_test_file_does_not_detect_scala_implementation_files() {
        let s = String::from("src/main/scala/com/example/Something.scala");
        assert_eq!(is_test_file(&s), false);
    }
}
<|endoftext|>


<commit_before>use crate::command_prelude::*;
use cargo::ops::{self, OutputMetadataOptions};

pub fn cli() -> App {
    subcommand("metadata")
        .about(
            "Output the resolved dependencies of a package, \
             the concrete used versions including overrides, \
             in machine-readable format",
        )
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg_features()
        .arg(multi_opt(
            "filter-platform",
            "TRIPLE",
            "Only include resolve dependencies matching the given target-triple",
        ))
        .arg(opt(
            "no-deps",
            "Output information only about the workspace members \
             and don't fetch dependencies",
        ))
        .arg_manifest_path()
        .arg(
            opt("format-version", "Format version")
                .value_name("VERSION")
                .possible_value("1"),
        )
        .after_help("Run `cargo help metadata` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;

    let version = match args.value_of("format-version") {
        None => {
            config.shell().warn(
                "please specify `--format-version` flag explicitly \
                 to avoid compatibility problems",
            )?;
            1
        }
        Some(version) => version.parse().unwrap(),
    };

    let options = OutputMetadataOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        no_deps: args.is_present("no-deps"),
        filter_platforms: args._values_of("filter-platform"),
        version,
    };

    let result = ops::output_metadata(&ws, &options)?;
    config.shell().print_json(&result);
    Ok(())
}
<commit_msg>Auto merge of #9050 - bishtpawan:master, r=alexcrichton<commit_after>use crate::command_prelude::*;
use cargo::ops::{self, OutputMetadataOptions};

pub fn cli() -> App {
    subcommand("metadata")
        .about(
            "Output the resolved dependencies of a package, \
             the concrete used versions including overrides, \
             in machine-readable format",
        )
        .arg(opt("quiet", "Do not print cargo log messages").short("q"))
        .arg_features()
        .arg(multi_opt(
            "filter-platform",
            "TRIPLE",
            "Only include resolve dependencies matching the given target-triple",
        ))
        .arg(opt(
            "no-deps",
            "Output information only about the workspace members \
             and don't fetch dependencies",
        ))
        .arg_manifest_path()
        .arg(
            opt("format-version", "Format version")
                .value_name("VERSION")
                .possible_value("1"),
        )
        .after_help("Run `cargo help metadata` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;

    let version = match args.value_of("format-version") {
        None => {
            config.shell().warn(
                "please specify `--format-version` flag explicitly \
                 to avoid compatibility problems",
            )?;
            1
        }
        Some(version) => version.parse().unwrap(),
    };

    let options = OutputMetadataOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        no_deps: args.is_present("no-deps"),
        filter_platforms: args._values_of("filter-platform"),
        version,
    };

    let result = ops::output_metadata(&ws, &options)?;
    config.shell().print_json(&result);
    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate common;

use common::session::Session;
use common::types::{I32, F32, Ty};
use common::page::{Page, ROWBATCH_SIZE};
use common::input::InputSource;
use common::storage::{MemTable, RandomTable};

macro_rules! assert_write_rows {
	($gen:expr, $mem:expr, $num:expr, $total_row:expr) => {
		{
		  let page = $gen.next().unwrap();
		  assert_eq!($num, page.value_count());
		  $mem.write(page).ok().unwrap();
		  assert_eq!($total_row, $mem.row_num());
  	}
	}
}

#[test]
pub fn test_next_once()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, 5);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, 5, 5);
  assert_write_rows!(gen, mem, 0, 5);
}

#[test]
pub fn test_next_once2()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, ROWBATCH_SIZE);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, ROWBATCH_SIZE, ROWBATCH_SIZE);
  assert_write_rows!(gen, mem, 0,             ROWBATCH_SIZE);
}

#[test]
pub fn test_next_multiple()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, (ROWBATCH_SIZE * 2) + 100);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, ROWBATCH_SIZE, ROWBATCH_SIZE);
  assert_write_rows!(gen, mem, ROWBATCH_SIZE, ROWBATCH_SIZE * 2);
  assert_write_rows!(gen, mem, 100,           ROWBATCH_SIZE * 2 + 100);
  assert_write_rows!(gen, mem, 0,             ROWBATCH_SIZE * 2 + 100);
}

#[test]
pub fn test_read()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, 5);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, 5, 5);
  assert_write_rows!(gen, mem, 0, 5);

  let reader = mem.reader();
  for x in reader {
  	let r: (i32, f32) = x.ok().unwrap();
  }
}

#[test]
pub fn test_write_projected()
{
  let schema = &[I32, F32, I32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, 5);
  let mut mem = MemTable::new(&session, &[F32, I32], &["x", "y"]);

  let page      = gen.next().unwrap();
  let projected = page.project(&[1,2]);

  assert_eq!(5, page.value_count());
  assert_eq!(3, page.chunk_num());

  let mut empty_page = Page::empty_page(2);
  empty_page.set_chunks(&projected[..]);
  empty_page.set_value_count(page.value_count());

  let omitted_chunk_sz = page.chunk(0).size;

  assert_eq!(2, empty_page.chunk_num());
  assert_eq!(page.size() - omitted_chunk_sz , empty_page.size());
  assert_eq!(page.value_count(), empty_page.value_count());

  mem.write(&empty_page).ok().unwrap();
  assert_eq!(5, mem.row_num());
  /*
  let reader = mem.reader();
  let mut row_id = 0usize;
  for x in reader {
  	let r: (f32, i32) = x.ok().unwrap();
  	assert_eq!(page.minipage(1).read_f32(row_id), r.0);
  	assert_eq!(page.minipage(2).read_i32(row_id), r.1);

  	row_id += 1;
  }*/
}<commit_msg>Enabled test_write_projected in memtable_tests.rs.<commit_after>#[macro_use]
extern crate common;

use common::session::Session;
use common::types::{I32, F32, Ty};
use common::page::{c_api, Page, ROWBATCH_SIZE};
use common::input::InputSource;
use common::storage::{MemTable, RandomTable};

macro_rules! assert_write_rows {
	($gen:expr, $mem:expr, $num:expr, $total_row:expr) => {
		{
		  let page = $gen.next().unwrap();
		  assert_eq!($num, page.value_count());
		  $mem.write(page).ok().unwrap();
		  assert_eq!($total_row, $mem.row_num());
  	}
	}
}

#[test]
pub fn test_next_once()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, 5);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, 5, 5);
  assert_write_rows!(gen, mem, 0, 5);
}

#[test]
pub fn test_next_once2()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, ROWBATCH_SIZE);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, ROWBATCH_SIZE, ROWBATCH_SIZE);
  assert_write_rows!(gen, mem, 0,             ROWBATCH_SIZE);
}

#[test]
pub fn test_next_multiple()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, (ROWBATCH_SIZE * 2) + 100);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, ROWBATCH_SIZE, ROWBATCH_SIZE);
  assert_write_rows!(gen, mem, ROWBATCH_SIZE, ROWBATCH_SIZE * 2);
  assert_write_rows!(gen, mem, 100,           ROWBATCH_SIZE * 2 + 100);
  assert_write_rows!(gen, mem, 0,             ROWBATCH_SIZE * 2 + 100);
}

#[test]
pub fn test_read()
{
  let schema = &[I32, F32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, 5);
  let mut mem = MemTable::new(&session, schema, &["x","y"]);

  assert_write_rows!(gen, mem, 5, 5);
  assert_write_rows!(gen, mem, 0, 5);

  let reader = mem.reader();
  for x in reader {
  	let r: (i32, f32) = x.ok().unwrap();
  }
}

#[test]
pub fn test_write_projected()
{
  let schema = &[I32, F32, I32];

  let session = Session;
  let mut gen = RandomTable::new(&session, schema, 5);
  let mut mem = MemTable::new(&session, &[F32, I32], &["x", "y"]);

  let page      = gen.next().unwrap();
  let projected = page.project(&[1,2]);

  assert_eq!(5, page.value_count());
  assert_eq!(3, page.chunk_num());

  let mut empty_page = Page::empty_page(2);
  empty_page.set_chunks(&projected[..]);
  empty_page.set_value_count(page.value_count());

  let omitted_chunk_sz = page.chunk(0).size;

  assert_eq!(2, empty_page.chunk_num());
  assert_eq!(page.size() - omitted_chunk_sz , empty_page.size());
  assert_eq!(page.value_count(), empty_page.value_count());

  mem.write(&empty_page).ok().unwrap();
  assert_eq!(5, mem.row_num());

  let reader = mem.reader();
  let mut row_id = 0usize;

  unsafe {
    for x in reader {
      let r: (f32, i32) = x.ok().unwrap();
      assert_eq!(c_api::read_raw_f32(page.chunk(1), row_id), r.0);
      assert_eq!(c_api::read_raw_i32(page.chunk(2), row_id), r.1);

      row_id += 1;
    }
  }
}<|endoftext|>


<commit_before>use std::io::{self, BufWriter};

use std::io::Write;
use std::fs::File;

use flexstr::{shared_fmt as flex_fmt, ToSharedStr};

use crate::web::config::*;
use crate::data_types::*;

use super::go_format_writer::GpadGafWriteMode;
use super::util::make_extension_string;

pub fn write_phenotype_annotation_files(api_maps: &APIMaps,
                                        config: &Config,
                                        output_dir: &str)
  -> Result<(), io::Error>
{
    let load_org_taxonid =
        if let Some(load_org_taxonid) = config.load_organism_taxonid {
            load_org_taxonid
        } else {
            return Ok(())
        };

    let phaf_cv_name = config.file_exports.phaf_cv_name.to_shared_str();

    let phaf_parental_strain = config.file_exports.phaf_parental_strain.get(&load_org_taxonid)
        .unwrap_or_else(|| panic!("no phaf_parental_strain configured for {}", load_org_taxonid));

    let database_name = &config.database_name;

    let phaf_file_name =
        format!("{}/single_locus_phenotype_annotations_taxon_{}.phaf", output_dir,
                load_org_taxonid);
    let phaf_file = File::create(phaf_file_name).expect("Unable to open file");
    let mut phaf_writer = BufWriter::new(&phaf_file);

    let header = "#Database name\tGene systematic ID\tFYPO ID\tAllele description\tExpression\tParental strain\tStrain name (background)\tGenotype description\tGene name\tAllele name\tAllele synonym\tAllele type\tEvidence\tCondition\tPenetrance\tSeverity\tExtension\tReference\tTaxon\tDate\tPloidy\n";

    phaf_writer.write_all(header.as_bytes())?;

    'GENOTYPES:
    for genotype_details in api_maps.genotypes.values() {
        if genotype_details.taxonid != load_org_taxonid {
            continue 'GENOTYPES;
        }

        // only export single locus genotypes that are haploid or homozygous diploid
        let expressed_allele =
            if genotype_details.loci.len() == 1 {
                let locus = &genotype_details.loci[0];

                let expressed_alleles = &locus.expressed_alleles;

                if expressed_alleles.len() > 1 {
                    continue 'GENOTYPES;
                }

                for test_expressed_allele in &expressed_alleles[1..] {
                    if expressed_alleles[0] != *test_expressed_allele {
                        continue 'GENOTYPES;
                    }
                }

                &expressed_alleles[0]
            } else {
                continue;
            };

        let locus_allele =
            api_maps.alleles.get(&expressed_allele.allele_uniquename)
            .unwrap_or_else(|| panic!("no allele found for {}", expressed_allele.allele_uniquename));

        let locus_allele_synonyms =
            locus_allele.synonyms.iter().map(|s| s.name.clone()).collect::<Vec<_>>().join("|");

        let locus_gene = api_maps.genes.get(&locus_allele.gene_uniquename)
            .unwrap_or_else(|| panic!("no gene found for {}", locus_allele.gene_uniquename));

        let locus_gene_name_or_uniquename =
            if let Some(ref name) = locus_gene.name {
                name
            } else {
                &locus_gene.uniquename
            };

        let expression =
            if let Some(ref expression) = expressed_allele.expression {
                if expression == "Null" && locus_allele.allele_type == "deletion" {
                    flex_fmt!("")
                } else {
                    expression.clone()
                }
            } else {
                flex_fmt!("")
            };

        if let Some(term_annotations) = genotype_details.cv_annotations.get(&phaf_cv_name) {
            for term_annotation in term_annotations {
                let term =
                    api_maps.terms.get(&term_annotation.term)
                    .unwrap_or_else(|| panic!("failed to find term summary for {}",
                                              term_annotation.term));

                for annotation_id in &term_annotation.annotations {
                    let annotation_detail = api_maps.annotation_details
                        .get(annotation_id)
                        .unwrap_or_else(|| panic!("can't find annotation {}", annotation_id));

                    let conditions =
                        annotation_detail.conditions.iter()
                        .map(|fs| fs.as_str())
                        .collect::<Vec<_>>()
                        .join(",");

                    let penetrance =
                        annotation_detail.extension.iter()
                        .filter(|bit| {
                            bit.rel_type_name == "has_penetrance"
                        })
                        .map(|bit| if let ExtRange::Term(ref termid) = bit.ext_range {
                            let bit_term = api_maps.terms.get(termid)
                                .unwrap_or_else(|| panic!("can't find term for {}", termid));
                            bit_term.name.to_string()
                        } else {
                            bit.ext_range.to_string()
                        })
                        .collect::<Vec<_>>()
                        .join(",");

                    let severity =
                        annotation_detail.extension.iter()
                        .filter(|bit| {
                            bit.rel_type_name == "has_severity"
                        })
                        .map(|bit| if let ExtRange::Term(ref termid) = bit.ext_range {
                            let bit_term = api_maps.terms.get(termid)
                                .unwrap_or_else(|| panic!("can't find term for {}", termid));
                            bit_term.name.to_string()
                        } else {
                            bit.ext_range.to_string()
                        })
                        .collect::<Vec<_>>()
                        .join(",");

                    let extension_bits =
                        annotation_detail.extension.iter()
                        .filter(|bit| {
                            bit.rel_type_name != "has_penetrance" && bit.rel_type_name != "has_severity"
                        })
                        .map(|bit| bit.clone())
                        .collect::<Vec<_>>();

                    let extension =
                        make_extension_string(config, &api_maps.terms,
                                              &GpadGafWriteMode::PomBaseGaf,
                                              &extension_bits);

                    let date =
                        annotation_detail.date.clone().unwrap_or_else(|| flex_fmt!("NO_DATE"));

                    let reference_uniquename =
                        if let Some(ref reference) = annotation_detail.reference {
                            reference.clone()
                        } else {
                            flex_fmt!("")
                        };

                    let line =
                        format!("{}\t{}\t{}\t{}\t{}\t{}\t{}\t\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n",
                                database_name,
                                locus_gene.uniquename,
                                term.termid,
                                locus_allele.description.clone().unwrap_or_else(|| flex_fmt!("")),
                                expression,
                                phaf_parental_strain,
                                "", //annotation_detail.genotype_background.clone().unwrap_or_else(|| flex_fmt!("")),
                                locus_gene_name_or_uniquename,
                                locus_allele.name.clone().unwrap_or_else(|| flex_fmt!("")),
                                locus_allele_synonyms,
                                locus_allele.allele_type,
                                annotation_detail.evidence.clone().unwrap_or_else(|| flex_fmt!("")),
                                conditions,
                                penetrance,
                                severity,
                                extension,
                                reference_uniquename,
                                load_org_taxonid,
                                date,
                        );
                    phaf_writer.write_all(line.as_bytes())?;
                }
            }

        }
    }

  Ok(())
}
<commit_msg>Fill in the Ploidy column when exporting PHAF<commit_after>use std::io::{self, BufWriter};

use std::io::Write;
use std::fs::File;

use flexstr::{shared_fmt as flex_fmt, ToSharedStr};

use crate::web::config::*;
use crate::data_types::*;

use super::go_format_writer::GpadGafWriteMode;
use super::util::make_extension_string;

pub fn write_phenotype_annotation_files(api_maps: &APIMaps,
                                        config: &Config,
                                        output_dir: &str)
  -> Result<(), io::Error>
{
    let load_org_taxonid =
        if let Some(load_org_taxonid) = config.load_organism_taxonid {
            load_org_taxonid
        } else {
            return Ok(())
        };

    let phaf_cv_name = config.file_exports.phaf_cv_name.to_shared_str();

    let phaf_parental_strain = config.file_exports.phaf_parental_strain.get(&load_org_taxonid)
        .unwrap_or_else(|| panic!("no phaf_parental_strain configured for {}", load_org_taxonid));

    let database_name = &config.database_name;

    let phaf_file_name =
        format!("{}/single_locus_phenotype_annotations_taxon_{}.phaf", output_dir,
                load_org_taxonid);
    let phaf_file = File::create(phaf_file_name).expect("Unable to open file");
    let mut phaf_writer = BufWriter::new(&phaf_file);

    let header = "#Database name\tGene systematic ID\tFYPO ID\tAllele description\tExpression\tParental strain\tStrain name (background)\tGenotype description\tGene name\tAllele name\tAllele synonym\tAllele type\tEvidence\tCondition\tPenetrance\tSeverity\tExtension\tReference\tTaxon\tDate\tPloidy\n";

    phaf_writer.write_all(header.as_bytes())?;

    'GENOTYPES:
    for genotype_details in api_maps.genotypes.values() {
        if genotype_details.taxonid != load_org_taxonid {
            continue 'GENOTYPES;
        }

        // only export single locus genotypes that are haploid or homozygous diploid
        let expressed_allele =
            if genotype_details.loci.len() == 1 {
                let locus = &genotype_details.loci[0];

                let expressed_alleles = &locus.expressed_alleles;

                for test_expressed_allele in &expressed_alleles[1..] {
                    if expressed_alleles[0] != *test_expressed_allele {
                        continue 'GENOTYPES;
                    }
                }

                &expressed_alleles[0]
            } else {
                continue;
            };

        let is_homozygous_diploid = genotype_details.loci[0].expressed_alleles.len() > 1;

        let locus_allele =
            api_maps.alleles.get(&expressed_allele.allele_uniquename)
            .unwrap_or_else(|| panic!("no allele found for {}", expressed_allele.allele_uniquename));

        let locus_allele_synonyms =
            locus_allele.synonyms.iter().map(|s| s.name.clone()).collect::<Vec<_>>().join("|");

        let locus_gene = api_maps.genes.get(&locus_allele.gene_uniquename)
            .unwrap_or_else(|| panic!("no gene found for {}", locus_allele.gene_uniquename));

        let locus_gene_name_or_uniquename =
            if let Some(ref name) = locus_gene.name {
                name
            } else {
                &locus_gene.uniquename
            };

        let expression =
            if let Some(ref expression) = expressed_allele.expression {
                if expression == "Null" && locus_allele.allele_type == "deletion" {
                    flex_fmt!("")
                } else {
                    expression.clone()
                }
            } else {
                flex_fmt!("")
            };

        if let Some(term_annotations) = genotype_details.cv_annotations.get(&phaf_cv_name) {
            for term_annotation in term_annotations {
                let term =
                    api_maps.terms.get(&term_annotation.term)
                    .unwrap_or_else(|| panic!("failed to find term summary for {}",
                                              term_annotation.term));

                for annotation_id in &term_annotation.annotations {
                    let annotation_detail = api_maps.annotation_details
                        .get(annotation_id)
                        .unwrap_or_else(|| panic!("can't find annotation {}", annotation_id));

                    let conditions =
                        annotation_detail.conditions.iter()
                        .map(|fs| fs.as_str())
                        .collect::<Vec<_>>()
                        .join(",");

                    let penetrance =
                        annotation_detail.extension.iter()
                        .filter(|bit| {
                            bit.rel_type_name == "has_penetrance"
                        })
                        .map(|bit| if let ExtRange::Term(ref termid) = bit.ext_range {
                            let bit_term = api_maps.terms.get(termid)
                                .unwrap_or_else(|| panic!("can't find term for {}", termid));
                            bit_term.name.to_string()
                        } else {
                            bit.ext_range.to_string()
                        })
                        .collect::<Vec<_>>()
                        .join(",");

                    let severity =
                        annotation_detail.extension.iter()
                        .filter(|bit| {
                            bit.rel_type_name == "has_severity"
                        })
                        .map(|bit| if let ExtRange::Term(ref termid) = bit.ext_range {
                            let bit_term = api_maps.terms.get(termid)
                                .unwrap_or_else(|| panic!("can't find term for {}", termid));
                            bit_term.name.to_string()
                        } else {
                            bit.ext_range.to_string()
                        })
                        .collect::<Vec<_>>()
                        .join(",");

                    let extension_bits =
                        annotation_detail.extension.iter()
                        .filter(|bit| {
                            bit.rel_type_name != "has_penetrance" && bit.rel_type_name != "has_severity"
                        })
                        .map(|bit| bit.clone())
                        .collect::<Vec<_>>();

                    let extension =
                        make_extension_string(config, &api_maps.terms,
                                              &GpadGafWriteMode::PomBaseGaf,
                                              &extension_bits);

                    let date =
                        annotation_detail.date.clone().unwrap_or_else(|| flex_fmt!("NO_DATE"));

                    let reference_uniquename =
                        if let Some(ref reference) = annotation_detail.reference {
                            reference.clone()
                        } else {
                            flex_fmt!("")
                        };

                    let line =
                        format!("{}\t{}\t{}\t{}\t{}\t{}\t{}\t\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n",
                                database_name,
                                locus_gene.uniquename,
                                term.termid,
                                locus_allele.description.clone().unwrap_or_else(|| flex_fmt!("")),
                                expression,
                                phaf_parental_strain,
                                "", //annotation_detail.genotype_background.clone().unwrap_or_else(|| flex_fmt!("")),
                                locus_gene_name_or_uniquename,
                                locus_allele.name.clone().unwrap_or_else(|| flex_fmt!("")),
                                locus_allele_synonyms,
                                locus_allele.allele_type,
                                annotation_detail.evidence.clone().unwrap_or_else(|| flex_fmt!("")),
                                conditions,
                                penetrance,
                                severity,
                                extension,
                                reference_uniquename,
                                load_org_taxonid,
                                date,
                                if is_homozygous_diploid { "homozygous diploid" } else { "haploid" },
                        );
                    phaf_writer.write_all(line.as_bytes())?;
                }
            }

        }
    }

  Ok(())
}
<|endoftext|>