<commit_before>use quote::{ToTokens, Tokens};
use syn::{Field, MetaItem, NestedMetaItem};

#[derive(Debug)]
pub struct Request {
    fields: Vec<RequestField>,
}

impl Request {
    pub fn has_body_fields(&self) -> bool {
        self.fields.iter().any(|field| field.is_body())
    }

    pub fn request_body_init_fields(&self) -> Tokens {
        let mut tokens = Tokens::new();

        for request_field in self.body_fields() {
            let field =  match *request_field {
                RequestField::Body(ref field) => field,
                _ => panic!("expected body field"),
            };

            let field_name = field.ident.as_ref().expect("expected body field to have a name");

            tokens.append(quote! {
                #field_name: request.#field_name,
            });
        }

        tokens
    }

    fn body_fields(&self) -> RequestBodyFields {
        RequestBodyFields::new(&self.fields)
    }
}

impl From<Vec<Field>> for Request {
    fn from(fields: Vec<Field>) -> Self {
        let request_fields = fields.into_iter().map(|mut field| {
            let mut request_field_kind = RequestFieldKind::Body;

            field.attrs = field.attrs.into_iter().filter(|attr| {
                let (attr_ident, nested_meta_items) = match attr.value {
                    MetaItem::List(ref attr_ident, ref nested_meta_items) => (attr_ident, nested_meta_items),
                    _ => return true,
                };

                if attr_ident != "ruma_api" {
                    return true;
                }

                for nested_meta_item in nested_meta_items {
                    match *nested_meta_item {
                        NestedMetaItem::MetaItem(ref meta_item) => {
                            match *meta_item {
                                MetaItem::Word(ref ident) => {
                                    if ident == "header" {
                                        request_field_kind = RequestFieldKind::Header;
                                    } else if ident == "path" {
                                        request_field_kind = RequestFieldKind::Path;
                                    } else if ident == "query" {
                                        request_field_kind = RequestFieldKind::Query;
                                    } else {
                                        panic!(
                                            "ruma_api! attribute meta item on requests must be: header, path, or query"
                                        );
                                    }
                                }
                                _ => panic!(
                                    "ruma_api! attribute meta item on requests cannot be a list or name/value pair"
                                ),
                            }
                        }
                        NestedMetaItem::Literal(_) => panic!(
                            "ruma_api! attribute meta item on requests must be: header, path, or query"
                        ),
                    }
                }

                false
            }).collect();

            match request_field_kind {
                RequestFieldKind::Body => RequestField::Body(field),
                RequestFieldKind::Header => RequestField::Header(field),
                RequestFieldKind::Path => RequestField::Path(field),
                RequestFieldKind::Query => RequestField::Query(field),
            }
        }).collect();

        Request {
            fields: request_fields,
        }
    }
}

impl ToTokens for Request {
    fn to_tokens(&self, mut tokens: &mut Tokens) {
        tokens.append(quote! {
            /// Data for a request to this API endpoint.
            #[derive(Debug, Serialize)]
            pub struct Request
        });

        if self.fields.len() == 0 {
            tokens.append(";");
        } else {
            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Header(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Path(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Query(ref field) => field.to_tokens(&mut tokens),
                }

                tokens.append(",");
            }

            tokens.append("}");
        }

        if self.has_body_fields() {
            tokens.append(quote! {
                /// Data in the request body.
                #[derive(Debug, Serialize)]
                struct RequestBody
            });

            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => {
                        field.to_tokens(&mut tokens);

                        tokens.append(",");
                    }
                    _ => {}
                }
            }

            tokens.append("}");
        }
    }
}

#[derive(Debug)]
pub enum RequestField {
    Body(Field),
    Header(Field),
    Path(Field),
    Query(Field),
}

impl RequestField {
    fn is_body(&self) -> bool {
        match *self {
            RequestField::Body(_) => true,
            _ => false,
        }
    }
}

enum RequestFieldKind {
    Body,
    Header,
    Path,
    Query,
}

#[derive(Debug)]
pub struct RequestBodyFields<'a> {
    fields: &'a [RequestField],
    index: usize,
}

impl<'a> RequestBodyFields<'a> {
    pub fn new(fields: &'a [RequestField]) -> Self {
        RequestBodyFields {
            fields,
            index: 0,
        }
    }
}

impl<'a> Iterator for RequestBodyFields<'a> {
    type Item = &'a RequestField;

    fn next(&mut self) -> Option<&'a RequestField> {
        while let Some(value) = self.fields.get(self.index) {
            self.index += 1;

            if value.is_body() {
                return Some(value);
            }
        }

        None
    }
}
<commit_msg>Allow a single field to be specified as the entire request body.<commit_after>use quote::{ToTokens, Tokens};
use syn::{Field, MetaItem, NestedMetaItem};

#[derive(Debug)]
pub struct Request {
    fields: Vec<RequestField>,
}

impl Request {
    pub fn has_body_fields(&self) -> bool {
        self.fields.iter().any(|field| field.is_body())
    }

    pub fn request_body_init_fields(&self) -> Tokens {
        let mut tokens = Tokens::new();

        for request_field in self.body_fields() {
            let field =  match *request_field {
                RequestField::Body(ref field) => field,
                _ => panic!("expected body field"),
            };

            let field_name = field.ident.as_ref().expect("expected body field to have a name");

            tokens.append(quote! {
                #field_name: request.#field_name,
            });
        }

        tokens
    }

    fn body_fields(&self) -> RequestBodyFields {
        RequestBodyFields::new(&self.fields)
    }

    fn newtype_body_field(&self) -> Option<Field> {
        for request_field in self.fields.iter() {
            match *request_field {
                RequestField::NewtypeBody(ref field) => {
                    let mut newtype_field = field.clone();

                    newtype_field.ident = None;

                    return Some(newtype_field);
                }
                _ => continue,
            }
        }

        None
    }
}

impl From<Vec<Field>> for Request {
    fn from(fields: Vec<Field>) -> Self {
        let mut has_newtype_body = false;

        let request_fields = fields.into_iter().map(|mut field| {
            let mut request_field_kind = RequestFieldKind::Body;

            field.attrs = field.attrs.into_iter().filter(|attr| {
                let (attr_ident, nested_meta_items) = match attr.value {
                    MetaItem::List(ref attr_ident, ref nested_meta_items) => (attr_ident, nested_meta_items),
                    _ => return true,
                };

                if attr_ident != "ruma_api" {
                    return true;
                }

                for nested_meta_item in nested_meta_items {
                    match *nested_meta_item {
                        NestedMetaItem::MetaItem(ref meta_item) => {
                            match *meta_item {
                                MetaItem::Word(ref ident) => {
                                    if ident == "body" {
                                        has_newtype_body = true;
                                        request_field_kind = RequestFieldKind::NewtypeBody;
                                    } else if ident == "header" {
                                        request_field_kind = RequestFieldKind::Header;
                                    } else if ident == "path" {
                                        request_field_kind = RequestFieldKind::Path;
                                    } else if ident == "query" {
                                        request_field_kind = RequestFieldKind::Query;
                                    } else {
                                        panic!(
                                            "ruma_api! attribute meta item on requests must be: body, header, path, or query"
                                        );
                                    }
                                }
                                _ => panic!(
                                    "ruma_api! attribute meta item on requests cannot be a list or name/value pair"
                                ),
                            }
                        }
                        NestedMetaItem::Literal(_) => panic!(
                            "ruma_api! attribute meta item on requests must be: body, header, path, or query"
                        ),
                    }
                }

                false
            }).collect();

            match request_field_kind {
                RequestFieldKind::Body => {
                    if has_newtype_body {
                        panic!("ruma_api! requests cannot have both normal body fields and a newtype body field");
                    } else {
                        return RequestField::Body(field);
                    }
                }
                RequestFieldKind::Header => RequestField::Header(field),
                RequestFieldKind::NewtypeBody => RequestField::NewtypeBody(field),
                RequestFieldKind::Path => RequestField::Path(field),
                RequestFieldKind::Query => RequestField::Query(field),
            }
        }).collect();

        Request {
            fields: request_fields,
        }
    }
}

impl ToTokens for Request {
    fn to_tokens(&self, mut tokens: &mut Tokens) {
        tokens.append(quote! {
            /// Data for a request to this API endpoint.
            #[derive(Debug, Serialize)]
            pub struct Request
        });

        if self.fields.len() == 0 {
            tokens.append(";");
        } else {
            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Header(ref field) => field.to_tokens(&mut tokens),
                    RequestField::NewtypeBody(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Path(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Query(ref field) => field.to_tokens(&mut tokens),
                }

                tokens.append(",");
            }

            tokens.append("}");
        }

        if let Some(newtype_body_field) = self.newtype_body_field() {
            tokens.append(quote! {
                /// Data in the request body.
                #[derive(Debug, Serialize)]
                struct RequestBody
            });

            tokens.append("(");

            newtype_body_field.to_tokens(&mut tokens);

            tokens.append(");");
        } else if self.has_body_fields() {
            tokens.append(quote! {
                /// Data in the request body.
                #[derive(Debug, Serialize)]
                struct RequestBody
            });

            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => {
                        field.to_tokens(&mut tokens);

                        tokens.append(",");
                    }
                    _ => {}
                }
            }

            tokens.append("}");
        }
    }
}

#[derive(Debug)]
pub enum RequestField {
    Body(Field),
    Header(Field),
    NewtypeBody(Field),
    Path(Field),
    Query(Field),
}

impl RequestField {
    fn is_body(&self) -> bool {
        match *self {
            RequestField::Body(_) => true,
            _ => false,
        }
    }
}

enum RequestFieldKind {
    Body,
    Header,
    NewtypeBody,
    Path,
    Query,
}

#[derive(Debug)]
pub struct RequestBodyFields<'a> {
    fields: &'a [RequestField],
    index: usize,
}

impl<'a> RequestBodyFields<'a> {
    pub fn new(fields: &'a [RequestField]) -> Self {
        RequestBodyFields {
            fields,
            index: 0,
        }
    }
}

impl<'a> Iterator for RequestBodyFields<'a> {
    type Item = &'a RequestField;

    fn next(&mut self) -> Option<&'a RequestField> {
        while let Some(value) = self.fields.get(self.index) {
            self.index += 1;

            if value.is_body() {
                return Some(value);
            }
        }

        None
    }
}
<|endoftext|>


<commit_before>#![cfg(not(test))]

use core::fmt;
use core::fmt::Write;

use serial_logger;
use serial_logger::write_static;

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn eh_personality() {
    write_static("PANIC: eh_personality\n");
}

#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {
    write_static("PANIC: rust_eh_unwind_resume\n");
}

#[no_mangle]
pub extern "C" fn __udivti3() {
    write_static("ERROR: Unimplemented intrinsic __udivti3\n");
}

#[no_mangle]
pub extern "C" fn __umodti3() {
    write_static("ERROR: Unimplemented intrinsic __umodti3\n");
}

#[no_mangle]
pub extern "C" fn __muloti4() {
    write_static("ERROR: Unimplemented intrinsic __muloti4\n");
}

#[no_mangle]
pub extern "C" fn __floatundisf() {
    write_static("ERROR: Unimplemented intrinsic __floatundisf\n");
}

#[no_mangle]
pub extern "C" fn __floatundidf() {
    write_static("ERROR: Unimplemented intrinsic __floatundidf\n");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() {
    write_static("PANIC: _Unwind_Resume\n");
}

#[allow(empty_loop)]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {

    write_static("PANIC: \n");
    let mut logger: serial_logger::SerialLogger = Default::default();
    let _ = write!(logger, "{}\n", fmt);
    let _ = write!(logger, "Line: {}\nFile: ", file_line.1);
    write_static(file_line.0);
    let _ = write!(logger, "\n");

    loop {
        unsafe {
            // If we're going to hang the CPU, do it properly.
            asm!("cli; hlt;");
        }
    }
}
<commit_msg>Remove buggy printing crap from runtime panic_fmt<commit_after>#![cfg(not(test))]

use core::fmt;
use core::fmt::Write;

use serial_logger;
use serial_logger::write_static;

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn eh_personality() {
    write_static("PANIC: eh_personality\n");
}

#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {
    write_static("PANIC: rust_eh_unwind_resume\n");
}

#[no_mangle]
pub extern "C" fn __udivti3() {
    write_static("ERROR: Unimplemented intrinsic __udivti3\n");
}

#[no_mangle]
pub extern "C" fn __umodti3() {
    write_static("ERROR: Unimplemented intrinsic __umodti3\n");
}

#[no_mangle]
pub extern "C" fn __muloti4() {
    write_static("ERROR: Unimplemented intrinsic __muloti4\n");
}

#[no_mangle]
pub extern "C" fn __floatundisf() {
    write_static("ERROR: Unimplemented intrinsic __floatundisf\n");
}

#[no_mangle]
pub extern "C" fn __floatundidf() {
    write_static("ERROR: Unimplemented intrinsic __floatundidf\n");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() {
    write_static("PANIC: _Unwind_Resume\n");
}

#[allow(empty_loop)]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {

    write_static("PANIC: \n");
    let mut logger: serial_logger::SerialLogger = Default::default();
    let _ = write!(logger, "{}\n", fmt);

    loop {
        unsafe {
            asm!("cli; hlt;");
        }
    }
}
<|endoftext|>


<commit_before>extern crate num;

/**
  Models an infinite signal, negative indices return
  always zero (to ensure causality of the signal),
  uninitialized positive indices, too.
  Can be used with any type that implements
  num::traits::Num and Clone.
*/
#[allow(dead_code)]
pub struct ZeroPaddedSignal<T> {
  values: Vec<T>,
}

impl<T: num::traits::Num + Clone> ZeroPaddedSignal<T> {
  /**
    Returns the number of initialized values.
  */
  #[allow(dead_code)]
  pub fn size(&self) -> usize {
    self.values.len()
  }

  /**
    Returns the value at the given index, zero if index
    is negative or uninitialized.
  */
  #[allow(dead_code)]
  pub fn get(&self, idx: isize) -> T {
    /* Check for negative index: */
    if idx < 0 {
      /* Negative, return zero: */
      T::zero()
    } else {
      /* Not negative, cast to unsigned: */
      let idx = idx as usize;
      /* Check if the index is initialized: */
      if let Some(v) = self.values.get(idx).cloned() {
        /* It is, return the value: */
        v
      } else {
        /* It's not, return zero: */
        T::zero()
      }
    }
  }

  /**
    Returns a vector of signal values, starting with index start,
    ending with index end.
  */
  #[allow(dead_code)]
  pub fn to_vector(&self, start: isize, end: isize) -> Vec<T> {
    /* Create an empty vector: */
    let mut x: Vec<T> = Vec::new();
    /* Loop through the given range: */
    for i in start..(end+1) {
      /* Add the values to the vector: */
      x.push(self.get(i));
    }
    /* Make the vector immutable: */
    let x = x;
    /* Return the vector: */
    x
  }

  /**
    Creates a new signal by doing Linear Prediction using
    the given coefficients.
  */
  #[allow(dead_code)]
  pub fn linear_prediction(&self, a: Vec<T>) -> ZeroPaddedSignal<T> {
    /* Create a vector for the values: */
    let mut vals: Vec<T> = Vec::new();
    /* Calculate the size of the new signal: */
    let size: usize = self.size() + a.len();
    /* Iterate over the new indices: */
    for i in 0..size {
      let mut val: T = T::zero();
      /* ... and the coefficients: */
      for j in 0..a.len() {
        /* Calculate and typecast the index in the old signal: */
        let idx = (i as isize) - ((j+1) as isize);
        /* Weight the value and add it up: */
        if let Some(v) = a.get(j).cloned() {
          val = val + v*self.get(idx);
        }
      }
      /* Add the value to the vector: */
      vals.push(val);
    }
    /* Create a signal from the vector and return it: */
    let x: ZeroPaddedSignal<T> = ZeroPaddedSignal { values: vals };
    x
  }

  /**
    Sets the signal value at the given index. If there's
    a gap between the last initialized index and the given
    one, the values between are initialized with zero.
  */
  #[allow(dead_code)]
  pub fn set(&mut self, idx: usize, val: T) {
    /* Initialize the gap values with zero, if necessary: */
    for _ in self.size()..(idx+1) {
      self.values.push(T::zero());
    }
    /* Set the new value: */
    self.values[idx] = val;
  }
}

/**
  Models a maximum length sequence generator.
*/
#[allow(dead_code)]
struct MaximumLengthSequence<T> {
  coefficients: Vec<bool>,
  state: Vec<bool>,
  val_false: T,
  val_true: T
}

impl<T: num::traits::Num + Copy> MaximumLengthSequence<T> {
  /**
    Creates a new instance using the given coefficients
    and the given initial state.
    Example polynom: f(x) = x^4 + a3*x^3 + a2*x^2 + a1*x + 1
      leads to coefficients: [a1,a2,a3]
  */
  #[allow(dead_code)]
  pub fn new(coefficients: Vec<bool>, state: Vec<bool>)
    -> MaximumLengthSequence<T> {
    /* Vectors must not be empty: */
    assert!(state.len() > 0);
    /* Lengths of coefficients vector and state vector must match: */
    assert_eq!(coefficients.len()+1, state.len());
    /* Return the instance: */
    MaximumLengthSequence::<T> {
      coefficients: coefficients,
      state: state,
      val_false: T::zero(),
      val_true: T::one()
    }
  }

  /**
    Sets the two values the sequence can be.
  */
  #[allow(dead_code)]
  pub fn set_vals(&mut self, val_false: T, val_true: T) {
    self.val_false = val_false;
    self.val_true = val_true;
  }

  /**
    Returns the next value and switches to the next state.
  */
  #[allow(dead_code)]
  pub fn next(&mut self) -> T {
    /* Create the variable we need to return later: */
    let x: T;
    if self.state[self.state.len()-1] {
      x = self.val_true;
    } else {
      x = self.val_false;
    }
    /* Set the new state: */
    self.state = MaximumLengthSequence::<T>::next_state(&self.state);
    /* Return the value: */
    x
  }

  /**
    Returns one period as a vector, does not change
    the internal state.
  */
  #[allow(dead_code)]
  pub fn to_vector(self) -> Vec<T> {
    /* Create a temporary internal state */
    let mut state: Vec<bool> = self.state;
    /* Create a vector that we return later: */
    let mut x: Vec<T> = Vec::new();
    /* Iterate over the period: */
    for _ in 0..(2usize.pow(state.len() as u32)-1) {
      /* Add the value: */
      if state[state.len()-1] {
        x.push(self.val_true);
      } else {
        x.push(self.val_false);
      }
      /* And set the new state: */
      state = MaximumLengthSequence::<T>::next_state(&state);
    }
    /* Make the vector immutable and return it: */
    let x = x;
    x
  }

  /**
    Returns the next state for the given one.
  */
  fn next_state(state: &Vec<bool>) -> Vec<bool> {
    /* Create a new state vector: */
    let mut new_state: Vec<bool> = Vec::new();
    /* Create the new first value: */
    let mut first: bool = state[state.len()-1];
    for i in 1..(state.len()-1) {
      first ^= state[i];
    }
    new_state.push(first);
    /* Shift the other values through: */
    for i in 1..state.len() {
      new_state.push(state[i-1]);
    }
    /* Make the new state immutable and return it: */
    let new_state = new_state;
    new_state
  }
}

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

  #[test]
  fn zero_padded_signal() {
    /* Create test signals: */
    let mut x1: ZeroPaddedSignal<u32> = ZeroPaddedSignal {
      values: vec![42,7,11]
    };
    /* Test size method: */
    assert_eq!( 3, x1.size());
    /* Test get method: */
    assert_eq!( 0, x1.get(  -1));
    assert_eq!(42, x1.get(   0));
    assert_eq!( 7, x1.get(   1));
    assert_eq!(11, x1.get(   2));
    assert_eq!( 0, x1.get(   3));
    assert_eq!( 0, x1.get( 100));
    assert_eq!( 0, x1.get(-100));
    /* Test to_vector method: */
    assert_eq!(vec![0,0,0,42,7,11,0], x1.to_vector(-3,3));
    assert_eq!(0, x1.to_vector(3,-3).len());
    /* Test set method: */
    x1.set(0, 5);
    assert_eq!(vec![5,7,11], x1.values);
    x1.set(5, 12);
    assert_eq!(vec![5,7,11,0,0,12], x1.values);
    x1.set(6,100);
    assert_eq!(vec![5,7,11,0,0,12,100], x1.values);
  }

  #[test]
  fn linear_prediction() {
    /* Create test signals: */
    let x1: ZeroPaddedSignal<f64> = ZeroPaddedSignal {
      values: vec![1.,1.,1.,1.,1.,1.]
    };
    /* Test linear_prediction method: */
    assert_eq_floatvec!(
      vec![0.,0.8,0.8,0.8,0.7,0.7,0.7,-0.1,-0.1,-0.1],
      x1.linear_prediction(vec![0.8,0.,0.,-0.1]).values,
      1e-15
    );
  }

  #[test]
  fn maximum_length_sequence1() {
    /* Create test sequences: */
    /* x^3 + x + 1; init state: 0-1-1 */
    let mut x1: MaximumLengthSequence<u8> =
      MaximumLengthSequence::new(vec![true,false],
        vec![false,true,true]);
     /* x^3 + x + 1; init state: 1-0-0 */
     let mut x2: MaximumLengthSequence<u8> =
      MaximumLengthSequence::new(vec![true,false],
        vec![true,false,false]);
    /* Test next method. */
    for v in vec![1,1,0,0,1,0,1] {
      assert_eq!(v, x1.next());
    }
    for v in vec![0,0,1,0,1,1,1] {
      assert_eq!(v, x2.next());
    }
    /* Test to_vector method: */
    assert_eq!(vec![1,1,0,0,1,0,1], x1.to_vector());
    assert_eq!(vec![0,0,1,0,1,1,1], x2.to_vector());
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    state.len() > 0")]
  fn maximum_length_sequence2() {
    let _: MaximumLengthSequence<u8> = MaximumLengthSequence::new(
      vec![true], vec![]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    `(left == right)` (left: `3`, right: `1`)")]
  fn maximum_length_sequence3() {
    let _: MaximumLengthSequence<u8> = MaximumLengthSequence::new(
      vec![true,false], vec![true]);
  }

  #[test]
  fn maximum_length_sequence4() {
    /* Create test sequence: */
    /* x^3 + x + 1; init state: 0-1-1 */
    let mut x1: MaximumLengthSequence<i8> =
      MaximumLengthSequence::new(vec![true,false],
        vec![false,true,true]);
    /* Set values: */
    x1.set_vals(-5,5);
    /* Test next method. */
    for v in vec![5,5,-5,-5,5,-5,5] {
      assert_eq!(v, x1.next());
    }
    /* Test to_vector method: */
    assert_eq!(vec![5,5,-5,-5,5,-5,5], x1.to_vector());
  }
}
<commit_msg>signals.rs: Fixed MaximumLengthSequence bug<commit_after>extern crate num;

/**
  Models an infinite signal, negative indices return
  always zero (to ensure causality of the signal),
  uninitialized positive indices, too.
  Can be used with any type that implements
  num::traits::Num and Clone.
*/
#[allow(dead_code)]
pub struct ZeroPaddedSignal<T> {
  values: Vec<T>,
}

impl<T: num::traits::Num + Clone> ZeroPaddedSignal<T> {
  /**
    Returns the number of initialized values.
  */
  #[allow(dead_code)]
  pub fn size(&self) -> usize {
    self.values.len()
  }

  /**
    Returns the value at the given index, zero if index
    is negative or uninitialized.
  */
  #[allow(dead_code)]
  pub fn get(&self, idx: isize) -> T {
    /* Check for negative index: */
    if idx < 0 {
      /* Negative, return zero: */
      T::zero()
    } else {
      /* Not negative, cast to unsigned: */
      let idx = idx as usize;
      /* Check if the index is initialized: */
      if let Some(v) = self.values.get(idx).cloned() {
        /* It is, return the value: */
        v
      } else {
        /* It's not, return zero: */
        T::zero()
      }
    }
  }

  /**
    Returns a vector of signal values, starting with index start,
    ending with index end.
  */
  #[allow(dead_code)]
  pub fn to_vector(&self, start: isize, end: isize) -> Vec<T> {
    /* Create an empty vector: */
    let mut x: Vec<T> = Vec::new();
    /* Loop through the given range: */
    for i in start..(end+1) {
      /* Add the values to the vector: */
      x.push(self.get(i));
    }
    /* Make the vector immutable: */
    let x = x;
    /* Return the vector: */
    x
  }

  /**
    Creates a new signal by doing Linear Prediction using
    the given coefficients.
  */
  #[allow(dead_code)]
  pub fn linear_prediction(&self, a: Vec<T>) -> ZeroPaddedSignal<T> {
    /* Create a vector for the values: */
    let mut vals: Vec<T> = Vec::new();
    /* Calculate the size of the new signal: */
    let size: usize = self.size() + a.len();
    /* Iterate over the new indices: */
    for i in 0..size {
      let mut val: T = T::zero();
      /* ... and the coefficients: */
      for j in 0..a.len() {
        /* Calculate and typecast the index in the old signal: */
        let idx = (i as isize) - ((j+1) as isize);
        /* Weight the value and add it up: */
        if let Some(v) = a.get(j).cloned() {
          val = val + v*self.get(idx);
        }
      }
      /* Add the value to the vector: */
      vals.push(val);
    }
    /* Create a signal from the vector and return it: */
    let x: ZeroPaddedSignal<T> = ZeroPaddedSignal { values: vals };
    x
  }

  /**
    Sets the signal value at the given index. If there's
    a gap between the last initialized index and the given
    one, the values between are initialized with zero.
  */
  #[allow(dead_code)]
  pub fn set(&mut self, idx: usize, val: T) {
    /* Initialize the gap values with zero, if necessary: */
    for _ in self.size()..(idx+1) {
      self.values.push(T::zero());
    }
    /* Set the new value: */
    self.values[idx] = val;
  }
}

/**
  Models a maximum length sequence generator.
*/
#[allow(dead_code)]
struct MaximumLengthSequence<T> {
  coefficients: Vec<bool>,
  state: Vec<bool>,
  val_false: T,
  val_true: T
}

impl<T: num::traits::Num + Copy> MaximumLengthSequence<T> {
  /**
    Creates a new instance using the given coefficients
    and the given initial state.
    Example polynom: f(x) = x^4 + a3*x^3 + a2*x^2 + a1*x + 1
      leads to coefficients: [a1,a2,a3]
  */
  #[allow(dead_code)]
  pub fn new(coefficients: Vec<bool>, state: Vec<bool>)
    -> MaximumLengthSequence<T> {
    /* Vectors must not be empty: */
    assert!(state.len() > 0);
    /* Lengths of coefficients vector and state vector must match: */
    assert_eq!(coefficients.len()+1, state.len());
    /* Return the instance: */
    MaximumLengthSequence::<T> {
      coefficients: coefficients,
      state: state,
      val_false: T::zero(),
      val_true: T::one()
    }
  }

  /**
    Sets the two values the sequence can be.
  */
  #[allow(dead_code)]
  pub fn set_vals(&mut self, val_false: T, val_true: T) {
    self.val_false = val_false;
    self.val_true = val_true;
  }

  /**
    Returns the next value and switches to the next state.
  */
  #[allow(dead_code)]
  pub fn next(&mut self) -> T {
    /* Create the variable we need to return later: */
    let x: T;
    if self.state[self.state.len()-1] {
      x = self.val_true;
    } else {
      x = self.val_false;
    }
    /* Set the new state: */
    self.state = MaximumLengthSequence::<T>::next_state(&self.state,
      &self.coefficients);
    /* Return the value: */
    x
  }

  /**
    Returns one period as a vector, does not change
    the internal state.
  */
  #[allow(dead_code)]
  pub fn to_vector(self) -> Vec<T> {
    /* Create a temporary internal state */
    let mut state: Vec<bool> = self.state;
    /* Create a vector that we return later: */
    let mut x: Vec<T> = Vec::new();
    /* Iterate over the period: */
    for _ in 0..(2usize.pow(state.len() as u32)-1) {
      /* Add the value: */
      if state[state.len()-1] {
        x.push(self.val_true);
      } else {
        x.push(self.val_false);
      }
      /* And set the new state: */
      state = MaximumLengthSequence::<T>::next_state(&state,
        &self.coefficients);
    }
    /* Make the vector immutable and return it: */
    let x = x;
    x
  }

  /**
    Returns the next state for the given one.
  */
  fn next_state(state: &Vec<bool>, coefficients: &Vec<bool>)
    -> Vec<bool> {
    /* Create a new state vector: */
    let mut new_state: Vec<bool> = Vec::new();
    /* Create the new first value: */
    let mut first: bool = state[state.len()-1];
    for i in 0..(state.len()-1) {
      if coefficients[i] {
        first ^= state[state.len()-(i+2)];
      }
    }
    new_state.push(first);
    /* Shift the other values through: */
    for i in 1..state.len() {
      new_state.push(state[i-1]);
    }
    /* Make the new state immutable and return it: */
    let new_state = new_state;
    new_state
  }
}

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

  #[test]
  fn zero_padded_signal() {
    /* Create test signals: */
    let mut x1: ZeroPaddedSignal<u32> = ZeroPaddedSignal {
      values: vec![42,7,11]
    };
    /* Test size method: */
    assert_eq!( 3, x1.size());
    /* Test get method: */
    assert_eq!( 0, x1.get(  -1));
    assert_eq!(42, x1.get(   0));
    assert_eq!( 7, x1.get(   1));
    assert_eq!(11, x1.get(   2));
    assert_eq!( 0, x1.get(   3));
    assert_eq!( 0, x1.get( 100));
    assert_eq!( 0, x1.get(-100));
    /* Test to_vector method: */
    assert_eq!(vec![0,0,0,42,7,11,0], x1.to_vector(-3,3));
    assert_eq!(0, x1.to_vector(3,-3).len());
    /* Test set method: */
    x1.set(0, 5);
    assert_eq!(vec![5,7,11], x1.values);
    x1.set(5, 12);
    assert_eq!(vec![5,7,11,0,0,12], x1.values);
    x1.set(6,100);
    assert_eq!(vec![5,7,11,0,0,12,100], x1.values);
  }

  #[test]
  fn linear_prediction() {
    /* Create test signals: */
    let x1: ZeroPaddedSignal<f64> = ZeroPaddedSignal {
      values: vec![1.,1.,1.,1.,1.,1.]
    };
    /* Test linear_prediction method: */
    assert_eq_floatvec!(
      vec![0.,0.8,0.8,0.8,0.7,0.7,0.7,-0.1,-0.1,-0.1],
      x1.linear_prediction(vec![0.8,0.,0.,-0.1]).values,
      1e-15
    );
  }

  #[test]
  fn maximum_length_sequence1() {
    /* Create test sequences: */
    /* x^3 + x + 1; init state: 0-1-1 */
    let mut x1: MaximumLengthSequence<u8> =
      MaximumLengthSequence::new(vec![true,false],
        vec![false,true,true]);
     /* x^3 + x + 1; init state: 1-0-0 */
     let mut x2: MaximumLengthSequence<u8> =
      MaximumLengthSequence::new(vec![true,false],
        vec![true,false,false]);
    /* Test next method. */
    for v in vec![1,1,0,0,1,0,1] {
      assert_eq!(v, x1.next());
    }
    for v in vec![0,0,1,0,1,1,1] {
      assert_eq!(v, x2.next());
    }
    /* Test to_vector method: */
    assert_eq!(vec![1,1,0,0,1,0,1], x1.to_vector());
    assert_eq!(vec![0,0,1,0,1,1,1], x2.to_vector());
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    state.len() > 0")]
  fn maximum_length_sequence2() {
    let _: MaximumLengthSequence<u8> = MaximumLengthSequence::new(
      vec![true], vec![]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    `(left == right)` (left: `3`, right: `1`)")]
  fn maximum_length_sequence3() {
    let _: MaximumLengthSequence<u8> = MaximumLengthSequence::new(
      vec![true,false], vec![true]);
  }

  #[test]
  fn maximum_length_sequence4() {
    /* Create test sequence: */
    /* x^3 + x + 1; init state: 0-1-1 */
    let mut x1: MaximumLengthSequence<i8> =
      MaximumLengthSequence::new(vec![true,false],
        vec![false,true,true]);
    /* Set values: */
    x1.set_vals(-5,5);
    /* Test next method. */
    for v in vec![5,5,-5,-5,5,-5,5] {
      assert_eq!(v, x1.next());
    }
    /* Test to_vector method: */
    assert_eq!(vec![5,5,-5,-5,5,-5,5], x1.to_vector());
  }
}
<|endoftext|>


<commit_before>pub use std::path::Path;
pub use std::fs::File;

pub use runtime::Runtime;
pub use error::ImagError;
pub use error::ImagErrorBase;

pub struct StorageError {
    base : ImagErrorBase,
    backendname : String,
}

impl StorageError {

    pub fn new<T : StorageBackend>(backend : &T, short: String, long: String) -> StorageError {
        StorageError {
            base: ImagErrorBase {
                shortdesc: short,
                longdesc: long,
            },
            backendname: backend.name()
        }
    }

}

impl<'a> ImagError<'a> for StorageError {

    fn print(&self, rt: &Runtime) {
        if self.base.longdesc.is_empty() {
            let s = format!("Backend {}: {}\n\n{}\n\n",
                            self.backendname,
                            self.base.shortdesc,
                            self.base.longdesc);
            rt.print(&s)
        } else {
            let s = format!("Backend {}: {}\n",
                            self.backendname,
                            self.base.shortdesc);
            rt.print(&s)
        }
    }

    fn print_short(&self, rt : &Runtime) {
        let s = format!("Backend {}: {}\n",
                        self.backendname,
                        self.base.shortdesc);
        rt.print(&s)
    }

    fn print_long(&self, rt : &Runtime) {
        let s = format!("Backend {}: {}\n\n{}\n\n",
                        self.backendname,
                        self.base.shortdesc,
                        self.base.longdesc);
        rt.print(&s)
    }
}

pub trait StorageBackend {

    fn name(&self) -> String;

    fn create(&self, file : File)   -> Option<StorageError>;
    fn read(&self, path: Path)      -> Result<File, StorageError>;
    fn update(&self, file : File)   -> Option<StorageError>;
    fn destroy(&self, path: Path)   -> Option<StorageError>;

}
<commit_msg>Remove error foo from storage<commit_after>pub use std::path::Path;
pub use std::fs::File;
pub use std::error::Error;

pub use runtime::Runtime;

pub trait StorageBackend {

    fn name(&self) -> String;

    fn create(&self, file : File)   -> Option<Error>;
    fn read(&self, path: Path)      -> Result<File, Error>;
    fn update(&self, file : File)   -> Option<Error>;
    fn destroy(&self, path: Path)   -> Option<Error>;

}
<|endoftext|>


<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::{NSInteger, NSUInteger};
use core_foundation::base::CFRange;
use objc::runtime::YES;
use std::ops::Range;
use sys::{MTLTexture, MTLTextureType, MTLTextureUsage};
use {FromRaw, FromRawError, PixelFormat, Region, Resource, Size};

pub struct Texture(id);

impl Texture {
    pub fn with_pixel_format(format: PixelFormat) -> Result<Self, FromRawError> {
        let raw_tex = unsafe { MTLTexture::newTextureViewWithPixelFormat(nil, format.into()) };
        Self::from_raw(raw_tex)
    }

    pub fn new(format: PixelFormat, tex_type: TextureType, levels: Range<isize>, slices: usize)
               -> Result<Self, FromRawError> {
        let cf_levels = CFRange::init(levels.start as NSInteger,
                                      (levels.end - levels.start) as NSInteger);
        let raw_tex = unsafe {
            MTLTexture::newTextureViewWithPixelFormat_textureType_levels_slices(
                nil, format.into(), tex_type.into(), cf_levels,
                slices as NSUInteger)
        };
        Self::from_raw(raw_tex)
    }

    pub fn replace_region_at_slice(&mut self, region: Region, slice: usize, mipmap_level: usize,
                                   bytes: &AsRef<[u8]>, bytes_per_row: usize,
                                   bytes_per_image: usize) {
        unsafe {
            self.0.replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage(
                region.into(), mipmap_level as NSUInteger, slice as NSUInteger,
                bytes.as_ref().as_ptr() as *const _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger);
        }
    }

    pub fn replace_region(&mut self, mipmap_level: usize, region: Region, bytes: &AsRef<[u8]>,
                          bytes_per_row: usize) {
        let bytes = bytes.as_ref();
        if bytes.len() % bytes_per_row != 0 {
            return;
        }
        unsafe {
            self.0.replaceRegion_mipmapLevel_withBytes_bytesPerRow(region.into(),
                                                                   mipmap_level as NSUInteger,
                                                                   bytes.as_ptr() as *const _,
                                                                   bytes_per_row as NSUInteger);
        }
    }

    // TODO(George): Investiage non-allocating APIs, and add predicates in rust code so that
    // panics can be generated
    pub fn get_bytes_at_slice(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize,
                              bytes_per_image: usize, region: Region, mipmap_level: usize,
                              slice: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0.getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice(
                bytes_storage.as_mut_ptr() as *mut _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger, region.into(), mipmap_level as NSUInteger,
                slice as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn get_bytes(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize, region: Region,
                     mipmap_level: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0.getBytes_bytesPerRow_fromRegion_mipmapLevel(
                bytes_storage.as_mut_ptr() as *mut _, bytes_per_row as NSUInteger,
                region.into(), mipmap_level as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn texture_type(&self) -> TextureType {
        unsafe { self.0.textureType().into() }
    }

    pub fn pixel_format(&self) -> PixelFormat {
        unsafe { self.0.pixelFormat().into() }
    }

    pub fn width(&self) -> usize {
        unsafe { self.0.width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { self.0.height() as usize }
    }

    pub fn depth(&self) -> usize {
        unsafe { self.0.depth() as usize }
    }

    pub fn dimensions(&self) -> Size {
        Size::new(self.width(), self.height(), self.depth())
    }

    pub fn mipmap_level_count(&self) -> usize {
        unsafe { self.0.mipmapLevelCount() as usize }
    }

    pub fn array_length(&self) -> usize {
        unsafe { self.0.arrayLength() as usize }
    }

    pub fn sample_count(&self) -> usize {
        unsafe { self.0.sampleCount() as usize }
    }

    pub fn is_frame_buffer_only(&self) -> bool {
        unsafe { self.0.frameBufferOnly() == YES }
    }

    pub fn root_resource(&self) -> Option<Resource> {
        unsafe { FromRaw::from_raw(self.0.rootResource()).ok() }
    }

    pub fn usage(&self) -> TextureUsage {
        unsafe { self.0.usage().into() }
    }

    pub fn parent_texture(&self) -> Option<Self> {
        unsafe { Self::from_raw(self.0.parentTexture()).ok() }
    }

    pub fn parent_relative_level(&self) -> usize {
        unsafe { self.0.parentRelativeLevel() as usize }
    }

    pub fn parent_relative_slice(&self) -> usize {
        unsafe { self.0.parentRelativeSlice() as usize }
    }
}

#[cfg(target_os = "macos")]
impl Texture {}

#[cfg(target_os = "ios")]
impl Texture {
    pub fn buffer(&self) -> Option<()> {
        // TODO(George): Model this correctly
        unimplemented!();
    }

    pub fn buffer_offset(&self) -> usize {
        unsafe { self.0.bufferOffset() as usize }
    }

    pub fn buffer_bytes_per_row(&self) -> usize {
        unsafe { self.0.bufferBytesPerRow() as usize }
    }
}

impl_from_into_raw!(Texture, of protocol "MTLTexture");

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    enum TextureType: MTLTextureType {
        Type1D => MTLTextureType1D,
        Type1DArray => MTLTextureType1DArray,
        Type2D => MTLTextureType2D,
        Type2DArray => MTLTextureType2DArray,
        Type2DMultisample => MTLTextureType2DMultisample,
        TypeCube => MTLTextureTypeCube,
        Type3D => MTLTextureType3D
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    enum TextureUsage: MTLTextureUsage {
        Unknown => MTLTextureUsageUnknown,
        ShaderRead => MTLTextureUsageShaderRead,
        ShaderWrite => MTLTextureUsageShaderWrite,
        RenderTarget => MTLTextureUsageRenderTarget,
        PixelFormatView => MTLTextureUsagePixelFormatView
    }
}
<commit_msg>rustfmt<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::{NSInteger, NSUInteger};
use core_foundation::base::CFRange;
use objc::runtime::YES;
use std::ops::Range;
use sys::{MTLTexture, MTLTextureType, MTLTextureUsage};
use {FromRaw, FromRawError, PixelFormat, Region, Resource, Size};

pub struct Texture(id);

impl Texture {
    pub fn with_pixel_format(format: PixelFormat) -> Result<Self, FromRawError> {
        let raw_tex = unsafe { MTLTexture::newTextureViewWithPixelFormat(nil, format.into()) };
        Self::from_raw(raw_tex)
    }

    pub fn new(format: PixelFormat, tex_type: TextureType, levels: Range<isize>, slices: usize)
               -> Result<Self, FromRawError> {
        let cf_levels = CFRange::init(levels.start as NSInteger,
                                      (levels.end - levels.start) as NSInteger);
        let raw_tex = unsafe {
            MTLTexture::newTextureViewWithPixelFormat_textureType_levels_slices(
                nil, format.into(), tex_type.into(), cf_levels,
                slices as NSUInteger)
        };
        Self::from_raw(raw_tex)
    }

    pub fn replace_region_at_slice(&mut self, region: Region, slice: usize, mipmap_level: usize,
                                   bytes: &AsRef<[u8]>, bytes_per_row: usize,
                                   bytes_per_image: usize) {
        unsafe {
            self.0.replaceRegion_mipmapLevel_slice_withBytes_bytesPerRow_bytesPerImage(
                region.into(), mipmap_level as NSUInteger, slice as NSUInteger,
                bytes.as_ref().as_ptr() as *const _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger);
        }
    }

    pub fn replace_region(&mut self, mipmap_level: usize, region: Region, bytes: &AsRef<[u8]>,
                          bytes_per_row: usize) {
        let bytes = bytes.as_ref();
        if bytes.len() % bytes_per_row != 0 {
            return;
        }
        unsafe {
            self.0.replaceRegion_mipmapLevel_withBytes_bytesPerRow(region.into(),
                                                                   mipmap_level as NSUInteger,
                                                                   bytes.as_ptr() as *const _,
                                                                   bytes_per_row as NSUInteger);
        }
    }

    // TODO(George): Investiage non-allocating APIs, and add predicates in rust code so that
    // panics can be generated
    pub fn get_bytes_at_slice(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize,
                              bytes_per_image: usize, region: Region, mipmap_level: usize,
                              slice: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0.getBytes_bytesPerRow_bytesPerImage_fromRegion_mipmapLevel_slice(
                bytes_storage.as_mut_ptr() as *mut _, bytes_per_row as NSUInteger,
                bytes_per_image as NSUInteger, region.into(), mipmap_level as NSUInteger,
                slice as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn get_bytes(&self, bytes_storage: &mut Vec<u8>, bytes_per_row: usize, region: Region,
                     mipmap_level: usize) {
        bytes_storage.resize(self.width() * self.height() * self.depth(), 0u8);
        unsafe {
            self.0
                .getBytes_bytesPerRow_fromRegion_mipmapLevel(bytes_storage.as_mut_ptr() as *mut _,
                                                             bytes_per_row as NSUInteger,
                                                             region.into(),
                                                             mipmap_level as NSUInteger);
        }
        bytes_storage.shrink_to_fit();
    }

    pub fn texture_type(&self) -> TextureType {
        unsafe { self.0.textureType().into() }
    }

    pub fn pixel_format(&self) -> PixelFormat {
        unsafe { self.0.pixelFormat().into() }
    }

    pub fn width(&self) -> usize {
        unsafe { self.0.width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { self.0.height() as usize }
    }

    pub fn depth(&self) -> usize {
        unsafe { self.0.depth() as usize }
    }

    pub fn dimensions(&self) -> Size {
        Size::new(self.width(), self.height(), self.depth())
    }

    pub fn mipmap_level_count(&self) -> usize {
        unsafe { self.0.mipmapLevelCount() as usize }
    }

    pub fn array_length(&self) -> usize {
        unsafe { self.0.arrayLength() as usize }
    }

    pub fn sample_count(&self) -> usize {
        unsafe { self.0.sampleCount() as usize }
    }

    pub fn is_frame_buffer_only(&self) -> bool {
        unsafe { self.0.frameBufferOnly() == YES }
    }

    pub fn root_resource(&self) -> Option<Resource> {
        unsafe { FromRaw::from_raw(self.0.rootResource()).ok() }
    }

    pub fn usage(&self) -> TextureUsage {
        unsafe { self.0.usage().into() }
    }

    pub fn parent_texture(&self) -> Option<Self> {
        unsafe { Self::from_raw(self.0.parentTexture()).ok() }
    }

    pub fn parent_relative_level(&self) -> usize {
        unsafe { self.0.parentRelativeLevel() as usize }
    }

    pub fn parent_relative_slice(&self) -> usize {
        unsafe { self.0.parentRelativeSlice() as usize }
    }
}

#[cfg(target_os = "macos")]
impl Texture {}

#[cfg(target_os = "ios")]
impl Texture {
    pub fn buffer(&self) -> Option<()> {
        // TODO(George): Model this correctly
        unimplemented!();
    }

    pub fn buffer_offset(&self) -> usize {
        unsafe { self.0.bufferOffset() as usize }
    }

    pub fn buffer_bytes_per_row(&self) -> usize {
        unsafe { self.0.bufferBytesPerRow() as usize }
    }
}

impl_from_into_raw!(Texture, of protocol "MTLTexture");

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    enum TextureType: MTLTextureType {
        Type1D => MTLTextureType1D,
        Type1DArray => MTLTextureType1DArray,
        Type2D => MTLTextureType2D,
        Type2DArray => MTLTextureType2DArray,
        Type2DMultisample => MTLTextureType2DMultisample,
        TypeCube => MTLTextureTypeCube,
        Type3D => MTLTextureType3D
    }
}

convertible_enum! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    enum TextureUsage: MTLTextureUsage {
        Unknown => MTLTextureUsageUnknown,
        ShaderRead => MTLTextureUsageShaderRead,
        ShaderWrite => MTLTextureUsageShaderWrite,
        RenderTarget => MTLTextureUsageRenderTarget,
        PixelFormatView => MTLTextureUsagePixelFormatView
    }
}
<|endoftext|>


<commit_before>use rules;

fn is_separator(c: char) -> bool {
	return c == ' ' || c == '\u{A0}'
	 || c == '.' || c == ','
	 || c == '"' || c == '-';
}

fn is_letter(c: char) -> bool {
	return !is_separator(c);
}

fn is_digit(c: char) -> bool {
	return c.is_digit(10);
}

fn find_start_at(slice: &str, pat: &str, start_at: usize) -> Option<usize> {
    slice[start_at..].find(pat).map(|i| start_at + i)
}

#[derive(Debug)]
enum Follow {
	Nothing,
	Any,
	Letter,
	Digit
}

// Replaces a word or multiple words.
// - If the word to search starts or ends with a *:
//   a separator or letter can precede or follow
// - If the word to search starts or ends with a +:
//   a letter can precede or follow
// - If the word to search starts or ends with a #:
//   a digit can precede or follow
// - If the word to search does not:
//   only a separator can precede or follow
fn replace_by_rule(line_str: &str, what: &str, with: &str) -> String {
	let mut new_line = String::new(); // Result

	// First check if the text to search ends with a star.
	let (what_no_star_after, follow) = {
		if what.ends_with("*") {
			(&what[..what.len()-1], Follow::Any)
		}
		else if what.ends_with("+") {
			(&what[..what.len()-1], Follow::Letter)
		}
		else if what.ends_with("#") {
			(&what[..what.len()-1], Follow::Digit)
		}
		else {
			(what, Follow::Nothing)
		}
	};

	let (what_no_star, precede) = {
		if what_no_star_after.starts_with("*") {
			(&what_no_star_after[1..], Follow::Any)
		}
		else if what_no_star_after.starts_with("+") {
			(&what_no_star_after[1..], Follow::Letter)
		}
		else if what_no_star_after.starts_with("#") {
			(&what_no_star_after[1..], Follow::Digit)
		}
		else {
			(what_no_star_after, Follow::Nothing)
		}
	};
	/*
	println!("what: {} what_no_star: {} precede: {:?} follow: {:?}",
		what, what_no_star, precede, follow);*/

	let mut start_at = 0;
	loop {
		// Perform a simple string search first, then look at the result
		// more precisely
		match find_start_at(line_str, what_no_star, start_at) {
			None => {
				new_line.push_str(&line_str[start_at..]);
				break;
			},
			Some(index) => {
				// Found! Verify the characters around to know if it is really a word

				// Look also the previous char, we do not want to replace text in the
				// middle of a word. We accept ' as prev char too (not as next char).
				let prev_char = line_str[0..index].chars().last();
				let do_replace1 = match prev_char {
					Some(c) => match precede {
						Follow::Nothing => !is_letter(c) || (c == '\''),
						Follow::Any => true,
						Follow::Letter => is_letter(c),
						Follow::Digit => is_digit(c)
					},
					None => true // Beginning of the line
				};

				// Now, next char
				let next_char = line_str[index + what_no_star.len()..].chars().next();
				let do_replace2 = match next_char {
					Some(c) => match follow {
						Follow::Nothing => is_separator(c),
						Follow::Any => true,
						Follow::Letter => is_letter(c),
						Follow::Digit => is_digit(c)
					},
					None => true
				};

				// Poor man debugger
				/*
				println!("line: '{}' index: {} prev_char: {:?} next_char: {:?} r1: {} r2: {}",
					line_str, index, prev_char, next_char,
					do_replace1, do_replace2);*/

				new_line.push_str(&line_str[start_at..index]);
				start_at = index + what_no_star.len();
				let end_reached = start_at >= line_str.len();

				if do_replace1 && do_replace2 {
					// Replace the found text but verify if we are at the
					// end of a line and the "with" text ends with a space
					let with2 = if end_reached && with.ends_with(' ') {
						&with[0..with.len()-1]
					}
					else {
						with
					};
					new_line.push_str(with2);
				}
				else {
					new_line.push_str(what_no_star);
				}

				if end_reached {
					break;
				}
			}
		}
	}
	new_line
}

///////////////////////////////////////////////////////////////////////////////
// Replaces words in one line of text based on rules
pub fn replace_one(text: &str, language: &str) -> String {
	let mut result = text.to_string();

	let mut rule_set = rules::RULES_FR;
	if language == "EN" {
		rule_set = rules::RULES_EN;
	}

	for rule_ref in rule_set.iter() {
		let &(what, with) = rule_ref;
		result = replace_by_rule(&result, what, with);
	}
	result
}

#[test]
fn test_replace_one() {
	assert_eq!(replace_one("Ca va"), "Ça va");
	assert_eq!(replace_one("Ca."), "Ça.");
	assert_eq!(replace_one("Ca"), "Ça");
	assert!(replace_one("Caribou") != "Çaribou");
	assert_eq!(replace_one("oeizz"), "œizz");
	assert_eq!(replace_one("des soeurs."), "des sœurs.");

	// No space if newline
	assert_eq!(replace_one("D'ou sa"), "D'où sa");
	assert_eq!(replace_one("bien sur,"), "bien sûr,");

	assert_eq!(replace_one("bien sur,"), "bien sûr,");
	assert_eq!(replace_one("Ecart entre"), "Écart entre");
	assert_eq!(replace_one("un coca"), "un coca");
	assert_eq!(replace_one("l'Etat"), "l'État");
	assert_eq!(replace_one("ok?"), "ok\u{A0}?");
	assert_eq!(replace_one("ok ?"), "ok\u{A0}?");
	assert_eq!(replace_one("ok!"), "ok\u{A0}!");
	assert_eq!(replace_one("ok !"), "ok\u{A0}!");
	assert_eq!(replace_one("A quoi?"), "À quoi\u{A0}?");
	assert_eq!(replace_one("A t'écouter"), "À t'écouter");
	assert_eq!(replace_one("manoeuvrer"), "manœuvrer");
	assert_eq!(replace_one("Etiez-vous"), "Étiez-vous");
	assert_eq!(replace_one("des qu'il"), "dès qu'il");
	assert_eq!(replace_one("10ème"), "10ᵉ");
	assert_eq!(replace_one("10e"), "10ᵉ");
	assert_eq!(replace_one("10è"), "10ᵉ");
	assert_eq!(replace_one("\"Oeil pour oeil\""), "\"Œil pour œil\"");
	assert_eq!(replace_one("Etaient-ils"), "Étaient-ils");
	assert_eq!(replace_one("caca"), "caca");
}
<commit_msg>Fix unit tests<commit_after>use rules;

fn is_separator(c: char) -> bool {
	return c == ' ' || c == '\u{A0}'
	 || c == '.' || c == ','
	 || c == '"' || c == '-';
}

fn is_letter(c: char) -> bool {
	return !is_separator(c);
}

fn is_digit(c: char) -> bool {
	return c.is_digit(10);
}

fn find_start_at(slice: &str, pat: &str, start_at: usize) -> Option<usize> {
    slice[start_at..].find(pat).map(|i| start_at + i)
}

#[derive(Debug)]
enum Follow {
	Nothing,
	Any,
	Letter,
	Digit
}

// Replaces a word or multiple words.
// - If the word to search starts or ends with a *:
//   a separator or letter can precede or follow
// - If the word to search starts or ends with a +:
//   a letter can precede or follow
// - If the word to search starts or ends with a #:
//   a digit can precede or follow
// - If the word to search does not:
//   only a separator can precede or follow
fn replace_by_rule(line_str: &str, what: &str, with: &str) -> String {
	let mut new_line = String::new(); // Result

	// First check if the text to search ends with a star.
	let (what_no_star_after, follow) = {
		if what.ends_with("*") {
			(&what[..what.len()-1], Follow::Any)
		}
		else if what.ends_with("+") {
			(&what[..what.len()-1], Follow::Letter)
		}
		else if what.ends_with("#") {
			(&what[..what.len()-1], Follow::Digit)
		}
		else {
			(what, Follow::Nothing)
		}
	};

	let (what_no_star, precede) = {
		if what_no_star_after.starts_with("*") {
			(&what_no_star_after[1..], Follow::Any)
		}
		else if what_no_star_after.starts_with("+") {
			(&what_no_star_after[1..], Follow::Letter)
		}
		else if what_no_star_after.starts_with("#") {
			(&what_no_star_after[1..], Follow::Digit)
		}
		else {
			(what_no_star_after, Follow::Nothing)
		}
	};
	/*
	println!("what: {} what_no_star: {} precede: {:?} follow: {:?}",
		what, what_no_star, precede, follow);*/

	let mut start_at = 0;
	loop {
		// Perform a simple string search first, then look at the result
		// more precisely
		match find_start_at(line_str, what_no_star, start_at) {
			None => {
				new_line.push_str(&line_str[start_at..]);
				break;
			},
			Some(index) => {
				// Found! Verify the characters around to know if it is really a word

				// Look also the previous char, we do not want to replace text in the
				// middle of a word. We accept ' as prev char too (not as next char).
				let prev_char = line_str[0..index].chars().last();
				let do_replace1 = match prev_char {
					Some(c) => match precede {
						Follow::Nothing => !is_letter(c) || (c == '\''),
						Follow::Any => true,
						Follow::Letter => is_letter(c),
						Follow::Digit => is_digit(c)
					},
					None => true // Beginning of the line
				};

				// Now, next char
				let next_char = line_str[index + what_no_star.len()..].chars().next();
				let do_replace2 = match next_char {
					Some(c) => match follow {
						Follow::Nothing => is_separator(c),
						Follow::Any => true,
						Follow::Letter => is_letter(c),
						Follow::Digit => is_digit(c)
					},
					None => true
				};

				// Poor man debugger
				/*
				println!("line: '{}' index: {} prev_char: {:?} next_char: {:?} r1: {} r2: {}",
					line_str, index, prev_char, next_char,
					do_replace1, do_replace2);*/

				new_line.push_str(&line_str[start_at..index]);
				start_at = index + what_no_star.len();
				let end_reached = start_at >= line_str.len();

				if do_replace1 && do_replace2 {
					// Replace the found text but verify if we are at the
					// end of a line and the "with" text ends with a space
					let with2 = if end_reached && with.ends_with(' ') {
						&with[0..with.len()-1]
					}
					else {
						with
					};
					new_line.push_str(with2);
				}
				else {
					new_line.push_str(what_no_star);
				}

				if end_reached {
					break;
				}
			}
		}
	}
	new_line
}

///////////////////////////////////////////////////////////////////////////////
// Replaces words in one line of text based on rules
pub fn replace_one(text: &str, language: &str) -> String {
	let mut result = text.to_string();

	let mut rule_set = rules::RULES_FR;
	if language == "EN" {
		rule_set = rules::RULES_EN;
	}

	for rule_ref in rule_set.iter() {
		let &(what, with) = rule_ref;
		result = replace_by_rule(&result, what, with);
	}
	result
}

// For unit testing
#[allow(dead_code)]
pub fn replace_one_fr(text: &str) -> String {
	replace_one(text, "FR")
}

#[test]
fn test_replace_one_fr() {
	assert_eq!(replace_one_fr("Ca va"), "Ça va");
	assert_eq!(replace_one_fr("Ca."), "Ça.");
	assert_eq!(replace_one_fr("Ca"), "Ça");
	assert!(replace_one_fr("Caribou") != "Çaribou");
	assert_eq!(replace_one_fr("oeizz"), "œizz");
	assert_eq!(replace_one_fr("des soeurs."), "des sœurs.");

	// No space if newline
	assert_eq!(replace_one_fr("D'ou sa"), "D'où sa");
	assert_eq!(replace_one_fr("bien sur,"), "bien sûr,");

	assert_eq!(replace_one_fr("bien sur,"), "bien sûr,");
	assert_eq!(replace_one_fr("Ecart entre"), "Écart entre");
	assert_eq!(replace_one_fr("un coca"), "un coca");
	assert_eq!(replace_one_fr("l'Etat"), "l'État");
	assert_eq!(replace_one_fr("ok?"), "ok\u{A0}?");
	assert_eq!(replace_one_fr("ok ?"), "ok\u{A0}?");
	assert_eq!(replace_one_fr("ok!"), "ok\u{A0}!");
	assert_eq!(replace_one_fr("ok !"), "ok\u{A0}!");
	assert_eq!(replace_one_fr("A quoi?"), "À quoi\u{A0}?");
	assert_eq!(replace_one_fr("A t'écouter"), "À t'écouter");
	assert_eq!(replace_one_fr("manoeuvrer"), "manœuvrer");
	assert_eq!(replace_one_fr("Etiez-vous"), "Étiez-vous");
	assert_eq!(replace_one_fr("des qu'il"), "dès qu'il");
	assert_eq!(replace_one_fr("10ème"), "10ᵉ");
	assert_eq!(replace_one_fr("10e"), "10ᵉ");
	assert_eq!(replace_one_fr("10è"), "10ᵉ");
	assert_eq!(replace_one_fr("\"Oeil pour oeil\""), "\"Œil pour œil\"");
	assert_eq!(replace_one_fr("Etaient-ils"), "Étaient-ils");
	assert_eq!(replace_one_fr("caca"), "caca");
}
<|endoftext|>


<commit_before>use std::io::{self, Write, Read};
use std::error::Error;
use std::net::{UdpSocket, SocketAddr, ToSocketAddrs};
use std::fmt;

use serde::{Serialize, Deserialize};
use msgpack::{Serializer, Deserializer};
use msgpack::decode::Error as DeserializeError;
use msgpack::encode::Error as SerializeError;

const MAX_UDP_SIZE: u16 = 65535;
pub struct Transit {
    socket: UdpSocket,
    buffer: Box<[u8]>,
}

pub type UnderlyingError = Box<Error + Send + Sync>;
#[derive(Debug)]
pub enum TransitError {
    IoError(io::Error),
    SerializeError(UnderlyingError),
    DeserializeError(UnderlyingError),
}

impl Error for TransitError {
    fn description(&self) -> &str {
        match *self {
            TransitError::IoError(ref err) => err.description(),
            TransitError::SerializeError(ref err) => err.description(),
            TransitError::DeserializeError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            TransitError::IoError(ref err) => err.cause(),
            TransitError::SerializeError(ref err) => err.cause(),
            TransitError::DeserializeError(ref err) => err.cause(),
        }
    }
}

impl From<io::Error> for TransitError {
    fn from(err: io::Error) -> TransitError {
        TransitError::IoError(err)
    }
}

impl From<DeserializeError> for TransitError {
    fn from(err: DeserializeError) -> TransitError {
        TransitError::DeserializeError(Box::new(err))
    }
}

impl From<SerializeError> for TransitError {
    fn from(err: SerializeError) -> TransitError {
        TransitError::SerializeError(Box::new(err))
    }
}

impl fmt::Display for TransitError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TransitError::IoError(ref err) =>
                write!(fmt, "IoError: {}", err),
            TransitError::DeserializeError(ref err) =>
                write!(fmt, "DeserializeError: {}", err),
            TransitError::SerializeError(ref err) =>
                write!(fmt, "SerializeError: {}", err),
        }
    }
}

/// Sends and receives types over UDP, removing any knowledge of buffers and dealing with the std
/// library.
///
/// This use the `bincode` crate to serialize objects. Does not currently support securely sending
/// packets over the network or ensuring that only packets of the correct type are serialized.
///
/// # Examples
///
/// ```rust
/// use std::io;
/// use transit::udp::*;
///
/// let transit = Transit::new("localhost:65000").unwrap();
/// let mut transit2 = Transit::new("localhost:65001").unwrap();
/// let test = String::from("hello, rust");
///
/// let res = transit.send_to(&test, "localhost:65001");
/// assert!(res.is_ok());
/// let res: Result<(String, _), TransitError> = transit2.recv_from();
/// assert!(res.is_ok());
/// let (data, _addr) = res.unwrap();
/// assert_eq!(data, "hello, rust");
/// ```
impl Transit {
    pub fn new<A>(addr: A) -> Result<Transit, TransitError> where A: ToSocketAddrs {
        let socket = try!(UdpSocket::bind(addr));
        Ok(Transit {
            socket: socket,
            buffer: udp_buffer(),
        })
    }

    /// On success, this function returns the type deserialized using the Deserialize trait
    /// implementation. It is not defined what happens when Transit trys to deserialize a different
    /// type into another currently.
    pub fn recv_from<T>(&mut self) -> Result<(T, SocketAddr), TransitError> where T: Deserialize {
        let (n, addr) = try!(self.socket.recv_from(&mut self.buffer));
        let data = try!(deserialize(&self.buffer[..n]));
        Ok((data, addr))
    }

    /// Transforms the packet into a byte array and sends it to the associated address.
    pub fn send_to<T, A>(&self, pkt: &T, addr: A) -> Result<(), TransitError> where T: Serialize, A: ToSocketAddrs {
        let mut vec = Vec::new();
        try!(serialize(&mut vec, pkt));
        try!(self.socket.send_to(&vec[..], addr));
        Ok(())
    }

    pub fn local_addr(&self)  -> Result<SocketAddr, TransitError> {
        let addr = try!(self.socket.local_addr());
        Ok(addr)
    }
}

fn udp_buffer() -> Box<[u8]> {
    (0..MAX_UDP_SIZE as usize)
        .map(|_x| 0u8)
        .collect::<Vec<u8>>()
        .into_boxed_slice()
}

fn serialize<W, T>(mut buf: W, val: &T) -> Result<(), TransitError> where W: Write, T: Serialize {
    try!(val.serialize(&mut Serializer::new(&mut buf)));
    Ok(())
}

fn deserialize<R, T>(buf: R) -> Result<T, TransitError> where R: Read, T: Deserialize {
    let data = try!(Deserialize::deserialize(&mut Deserializer::new(buf)));
    Ok(data)
}

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

    #[derive(Serialize, Deserialize, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
    struct Test {
        ten: u8,
    }

    #[derive(Serialize, Deserialize, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
    struct Another {
        data: String,
    }

    #[test]
    fn test_send_recv() {
        let addr1 = "127.0.0.1:61001";
        let addr2 = "127.0.0.1:61002";
        let mut transit1 = Transit::new(addr1).unwrap();
        let transit2 = Transit::new(addr2).unwrap();
        let test = Test { ten: 10 };

        let res = transit2.send_to(&test, addr1);
        assert!(res.is_ok());
        let res = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr): (Test, _) = res.unwrap();
        assert_eq!(data, test);
    }

    #[test]
    fn test_send_recv_string() {
        let addr1 = "127.0.0.1:63001";
        let addr2 = "127.0.0.1:63002";
        let mut transit1 = Transit::new(addr1).unwrap();
        let transit2 = Transit::new(addr2).unwrap();
        let test = String::from("hello");

        let res = transit2.send_to(&test, addr1);
        assert!(res.is_ok());
        let res = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr): (String, _) = res.unwrap();
        assert_eq!(data, test);
    }

    #[test]
    fn test_send_recv_bytes() {
        let addr1 = "127.0.0.1:64001";
        let addr2 = "127.0.0.1:64002";
        let mut transit1 = Transit::new(addr1).unwrap();
        let transit2 = Transit::new(addr2).unwrap();
        let vec: Vec<u8> = vec!(9u8);
        let slice = &vec[..];

        let res = transit2.send_to(&slice, addr1);
        assert!(res.is_ok());
        let res = transit2.send_to(&slice, addr1);
        assert!(res.is_ok());

        let res: Result<(Vec<u8>, _), TransitError> = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr) = res.unwrap();
        assert_eq!(data, vec);
        let res: Result<(Vec<u8>, _), TransitError> = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr) = res.unwrap();
        assert_eq!(data, vec);
    }

    #[test]
    fn test_packet_type() {
        let addr1 = "127.0.0.1:62001";
        let addr2 = "127.0.0.1:62002";
        let transit1 = Transit::new(addr1).unwrap();
        let mut transit2 = Transit::new(addr2).unwrap();
        let test = Another { data: String::from("Hello") };

        let res = transit1.send_to(&test, addr2);
        assert!(res.is_ok());
        let res: Result<(Test, _), TransitError> = transit2.recv_from();
        assert!(res.is_err());
    }
}
<commit_msg>Use the internal buffer for sending types<commit_after>use std::io::{self, Write, Read};
use std::error::Error;
use std::net::{UdpSocket, SocketAddr, ToSocketAddrs};
use std::fmt;

use serde::{Serialize, Deserialize};
use msgpack::{Serializer, Deserializer};
use msgpack::decode::Error as DeserializeError;
use msgpack::encode::Error as SerializeError;

const MAX_UDP_SIZE: u16 = 65535;
pub struct Transit {
    socket: UdpSocket,
    buffer: Box<[u8]>,
}

pub type UnderlyingError = Box<Error + Send + Sync>;
#[derive(Debug)]
pub enum TransitError {
    IoError(io::Error),
    SerializeError(UnderlyingError),
    DeserializeError(UnderlyingError),
}

impl Error for TransitError {
    fn description(&self) -> &str {
        match *self {
            TransitError::IoError(ref err) => err.description(),
            TransitError::SerializeError(ref err) => err.description(),
            TransitError::DeserializeError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            TransitError::IoError(ref err) => err.cause(),
            TransitError::SerializeError(ref err) => err.cause(),
            TransitError::DeserializeError(ref err) => err.cause(),
        }
    }
}

impl From<io::Error> for TransitError {
    fn from(err: io::Error) -> TransitError {
        TransitError::IoError(err)
    }
}

impl From<DeserializeError> for TransitError {
    fn from(err: DeserializeError) -> TransitError {
        TransitError::DeserializeError(Box::new(err))
    }
}

impl From<SerializeError> for TransitError {
    fn from(err: SerializeError) -> TransitError {
        TransitError::SerializeError(Box::new(err))
    }
}

impl fmt::Display for TransitError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TransitError::IoError(ref err) =>
                write!(fmt, "IoError: {}", err),
            TransitError::DeserializeError(ref err) =>
                write!(fmt, "DeserializeError: {}", err),
            TransitError::SerializeError(ref err) =>
                write!(fmt, "SerializeError: {}", err),
        }
    }
}

/// Sends and receives types over UDP, removing any knowledge of buffers and dealing with the std
/// library.
///
/// This use the `bincode` crate to serialize objects. Does not currently support securely sending
/// packets over the network or ensuring that only packets of the correct type are serialized.
///
/// # Examples
///
/// ```rust
/// use std::io;
/// use transit::udp::*;
///
/// let mut transit = Transit::new("localhost:65000").unwrap();
/// let mut transit2 = Transit::new("localhost:65001").unwrap();
/// let test = String::from("hello, rust");
///
/// let res = transit.send_to(&test, "localhost:65001");
/// assert!(res.is_ok());
/// let res: Result<(String, _), TransitError> = transit2.recv_from();
/// assert!(res.is_ok());
/// let (data, _addr) = res.unwrap();
/// assert_eq!(data, "hello, rust");
/// ```
impl Transit {
    pub fn new<A>(addr: A) -> Result<Transit, TransitError> where A: ToSocketAddrs {
        let socket = try!(UdpSocket::bind(addr));
        Ok(Transit {
            socket: socket,
            buffer: udp_buffer(),
        })
    }

    /// On success, this function returns the type deserialized using the Deserialize trait
    /// implementation. It is not defined what happens when Transit trys to deserialize a different
    /// type into another currently.
    pub fn recv_from<T>(&mut self) -> Result<(T, SocketAddr), TransitError> where T: Deserialize {
        let (n, addr) = try!(self.socket.recv_from(&mut self.buffer));
        let data = try!(deserialize(&self.buffer[..n]));
        Ok((data, addr))
    }

    /// Transforms the packet into a byte array and sends it to the associated address.
    pub fn send_to<T, A>(&mut self, pkt: &T, addr: A) -> Result<(), TransitError> where T: Serialize, A: ToSocketAddrs {
        let n = {
            let bytes = &mut self.buffer[..];
            let mut buf = ByteCounter::new(bytes);
            try!(serialize(&mut buf, pkt));
            buf.write_count()
        };
        try!(self.socket.send_to(&self.buffer[..n], addr));
        Ok(())
    }

    pub fn local_addr(&self)  -> Result<SocketAddr, TransitError> {
        let addr = try!(self.socket.local_addr());
        Ok(addr)
    }
}

fn udp_buffer() -> Box<[u8]> {
    (0..MAX_UDP_SIZE as usize)
        .map(|_x| 0u8)
        .collect::<Vec<u8>>()
        .into_boxed_slice()
}

fn serialize<W, T>(mut buf: W, val: &T) -> Result<(), TransitError> where W: Write, T: Serialize {
    try!(val.serialize(&mut Serializer::new(&mut buf)));
    Ok(())
}

fn deserialize<R, T>(buf: R) -> Result<T, TransitError> where R: Read, T: Deserialize {
    let data = try!(Deserialize::deserialize(&mut Deserializer::new(buf)));
    Ok(data)
}

struct ByteCounter<W> {
    counter: usize,
    writer: W,
}

impl<W> ByteCounter<W> {
    fn new(writer: W) -> ByteCounter<W> {
        ByteCounter {
            counter: 0,
            writer: writer,
        }
    }

    fn write_count(&self) -> usize {
        self.counter
    }
}

impl<W: Write> Write for ByteCounter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = try!(self.writer.write(buf));
        self.counter += n;
        Ok(n)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

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

    #[derive(Serialize, Deserialize, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
    struct Test {
        ten: u8,
    }

    #[derive(Serialize, Deserialize, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
    struct Another {
        data: String,
    }

    #[test]
    fn test_send_recv() {
        let addr1 = "127.0.0.1:61001";
        let addr2 = "127.0.0.1:61002";
        let mut transit1 = Transit::new(addr1).unwrap();
        let mut transit2 = Transit::new(addr2).unwrap();
        let test = Test { ten: 10 };

        let res = transit2.send_to(&test, addr1);
        assert!(res.is_ok());
        let res = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr): (Test, _) = res.unwrap();
        assert_eq!(data, test);
    }

    #[test]
    fn test_send_recv_string() {
        let addr1 = "127.0.0.1:63001";
        let addr2 = "127.0.0.1:63002";
        let mut transit1 = Transit::new(addr1).unwrap();
        let mut transit2 = Transit::new(addr2).unwrap();
        let test = String::from("hello");

        let res = transit2.send_to(&test, addr1);
        assert!(res.is_ok());
        let res = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr): (String, _) = res.unwrap();
        assert_eq!(data, test);
    }

    #[test]
    fn test_send_recv_bytes() {
        let addr1 = "127.0.0.1:64001";
        let addr2 = "127.0.0.1:64002";
        let mut transit1 = Transit::new(addr1).unwrap();
        let mut transit2 = Transit::new(addr2).unwrap();
        let vec = vec!(9u8);
        let slice = &vec[..];

        let res = transit2.send_to(&slice, addr1);
        assert!(res.is_ok());
        let res = transit2.send_to(&slice, addr1);
        assert!(res.is_ok());

        let res: Result<(Vec<u8>, _), TransitError> = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr) = res.unwrap();
        assert_eq!(data, vec);
        let res: Result<(Vec<u8>, _), TransitError> = transit1.recv_from();
        assert!(res.is_ok());
        let (data, _addr) = res.unwrap();
        assert_eq!(data, vec);
    }

    #[test]
    fn test_packet_type() {
        let addr1 = "127.0.0.1:62001";
        let addr2 = "127.0.0.1:62002";
        let mut transit1 = Transit::new(addr1).unwrap();
        let mut transit2 = Transit::new(addr2).unwrap();
        let test = Another { data: String::from("Hello") };

        let res = transit1.send_to(&test, addr2);
        assert!(res.is_ok());
        let res: Result<(Test, _), TransitError> = transit2.recv_from();
        assert!(res.is_err());
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `Variant` binding and helper traits.
//!
//! [`Variant`](struct.Variant.html) is an immutable dynamically-typed generic
//! container. Its type and value are defined at construction and never change.
//!
//! `Variant` types are described by [`VariantType`](../struct.VariantType.html)
//! "type strings".
//!
//! Although `GVariant` supports arbitrarily complex types, this binding is
//! currently limited to the basic ones: `bool`, `u8`, `i16`, `u16`, `i32`,
//! `u32`, `i64`, `u64`, `f64` and `&str`/`String`.
//!
//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::Variant;
//!
//! // Using the `ToVariant` trait.
//! let num = 10.to_variant();
//!
//! // `is` tests the type of the value.
//! assert!(num.is::<i32>());
//!
//! // `get` tries to extract the value.
//! assert_eq!(num.get::<i32>(), Some(10));
//! assert_eq!(num.get::<u32>(), None);
//!
//! // `Variant` implements `From`
//! let hello = Variant::from("Hello!");
//!
//! // `get_str` tries to borrow a string slice.
//! assert_eq!(hello.get_str(), Some("Hello!"));
//! assert_eq!(num.get_str(), None);
//! ```

use VariantTy;
use ffi as glib_ffi;
use translate::*;
use std::borrow::Cow;
use std::cmp::{PartialEq, Eq, PartialOrd, Ordering};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::slice;
use std::str;

glib_wrapper! {
    /// A generic immutable value capable of carrying various types.
    ///
    /// See the [module documentation](index.html) for more details.
    pub struct Variant(Shared<glib_ffi::GVariant>);

    match fn {
        ref => |ptr| glib_ffi::g_variant_ref_sink(ptr),
        unref => |ptr| glib_ffi::g_variant_unref(ptr),
        get_type => || glib_ffi::g_variant_type_get_gtype(),
    }
}

impl Variant {
    /// Returns the type of the value.
    pub fn type_(&self) -> &VariantTy {
        unsafe { VariantTy::from_ptr(glib_ffi::g_variant_get_type(self.to_glib_none().0)) }
    }

    /// Returns `true` if the type of the value corresponds to `T`.
    #[inline]
    pub fn is<T: StaticVariantType>(&self) -> bool {
        self.type_() == T::static_variant_type()
    }

    /// Tries to extract a value of type `T`.
    ///
    /// Returns `Some` if `T` matches the variant's type.
    #[inline]
    pub fn get<T: FromVariant>(&self) -> Option<T> {
        T::from_variant(self)
    }

    /// Tries to extract a `&str`.
    ///
    /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type
    /// strings).
    pub fn get_str(&self) -> Option<&str> {
        unsafe {
            match self.type_().to_str() {
                "s" | "o" | "g" => {
                    let mut len = 0;
                    let ptr = glib_ffi::g_variant_get_string(self.to_glib_none().0, &mut len);
                    let ret = str::from_utf8_unchecked(
                        slice::from_raw_parts(ptr as *const u8, len as usize));
                    Some(ret)
                }
                _ => None,
            }
        }
    }
}

unsafe impl Send for Variant { }
unsafe impl Sync for Variant { }

impl fmt::Debug for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("Variant {{ ptr: {:?}, type: \"{}\", value: {} }}",
            self.to_glib_none().0, self.type_(), self))
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let serialized: String = unsafe {
            from_glib_full(glib_ffi::g_variant_print(self.to_glib_none().0, false.to_glib()))
        };
        f.write_str(&serialized)
    }
}

impl PartialEq for Variant {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_variant_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Variant { }

impl PartialOrd for Variant {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        unsafe {
            if glib_ffi::g_variant_classify(self.to_glib_none().0) !=
               glib_ffi::g_variant_classify(other.to_glib_none().0) {
                return None;
            }

            if glib_ffi::g_variant_is_container(self.to_glib_none().0) != glib_ffi::GFALSE {
                return None;
            }

            let res = glib_ffi::g_variant_compare(self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _);
            if res < 0 {
                Some(Ordering::Less)
            } else if res > 0 {
                Some(Ordering::Equal)
            } else {
                Some(Ordering::Greater)
            }
        }
    }
}

impl Hash for Variant {
    fn hash<H: Hasher>(&self, state: &mut H) {
        unsafe {
            state.write_u32(glib_ffi::g_variant_hash(self.to_glib_none().0 as *const _))
        }
    }
}

/// Converts to `Variant`.
pub trait ToVariant {
    /// Returns a `Variant` clone of `self`.
    fn to_variant(&self) -> Variant;
}

/// Extracts a value.
pub trait FromVariant: Sized + StaticVariantType {
    /// Tries to extract a value.
    ///
    /// Returns `Some` if the variant's type matches `Self`.
    fn from_variant(variant: &Variant) -> Option<Self>;
}

/// Returns `VariantType` of `Self`.
pub trait StaticVariantType {
    /// Returns the `VariantType` corresponding to `Self`.
    fn static_variant_type() -> Cow<'static, VariantTy>;
}

impl<'a, T: ?Sized + ToVariant> ToVariant for &'a T {
    fn to_variant(&self) -> Variant {
        <T as ToVariant>::to_variant(self)
    }
}

impl<'a, T: ?Sized + StaticVariantType> StaticVariantType for &'a T {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        <T as StaticVariantType>::static_variant_type()
    }
}

macro_rules! impl_numeric {
    ($name:ty, $type_str:expr, $new_fn:ident, $get_fn:ident) => {
        impl StaticVariantType for $name {
            fn static_variant_type() -> Cow<'static, VariantTy> {
                unsafe { VariantTy::from_str_unchecked($type_str).into() }
            }
        }

        impl ToVariant for $name {
            fn to_variant(&self) -> Variant {
                unsafe { from_glib_none(glib_ffi::$new_fn(*self)) }
            }
        }

        impl FromVariant for $name {
            fn from_variant(variant: &Variant) -> Option<Self> {
                unsafe {
                    if variant.is::<Self>() {
                        Some(glib_ffi::$get_fn(variant.to_glib_none().0))
                    } else {
                        None
                    }
                }
            }
        }
    }
}

impl_numeric!(u8, "y", g_variant_new_byte, g_variant_get_byte);
impl_numeric!(i16, "n", g_variant_new_int16, g_variant_get_int16);
impl_numeric!(u16, "q", g_variant_new_uint16, g_variant_get_uint16);
impl_numeric!(i32, "i", g_variant_new_int32, g_variant_get_int32);
impl_numeric!(u32, "u", g_variant_new_uint32, g_variant_get_uint32);
impl_numeric!(i64, "x", g_variant_new_int64, g_variant_get_int64);
impl_numeric!(u64, "t", g_variant_new_uint64, g_variant_get_uint64);
impl_numeric!(f64, "d", g_variant_new_double, g_variant_get_double);

impl StaticVariantType for bool {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("b").into() }
    }
}

impl ToVariant for bool {
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_boolean(self.to_glib())) }
    }
}

impl FromVariant for bool {
    fn from_variant(variant: &Variant) -> Option<Self> {
        unsafe {
            if variant.is::<Self>() {
                Some(from_glib(glib_ffi::g_variant_get_boolean(variant.to_glib_none().0)))
            } else {
                None
            }
        }
    }
}

impl StaticVariantType for String {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for String {
    fn to_variant(&self) -> Variant {
        self[..].to_variant()
    }
}

impl FromVariant for String {
    fn from_variant(variant: &Variant) -> Option<Self> {
        variant.get_str().map(String::from)
    }
}

impl StaticVariantType for str {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for str {
    #[cfg(any(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_take_string(self.to_glib_full())) }
    }

    #[cfg(not(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_string(self.to_glib_none().0)) }
    }
}

impl<T: ToVariant> From<T> for Variant {
    fn from(value: T) -> Variant {
        value.to_variant()
    }
}

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

    macro_rules! unsigned {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    n /= 2;
                }
            }
        }
    }

    macro_rules! signed {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    let v = Variant::from(-n);
                    assert_eq!(v.get(), Some(-n));
                    n /= 2;
                }
            }
        }
    }

    unsigned!(test_u8, u8);
    unsigned!(test_u16, u16);
    unsigned!(test_u32, u32);
    unsigned!(test_u64, u64);
    signed!(test_i16, i16);
    signed!(test_i32, i32);
    signed!(test_i64, i64);

    #[test]
    fn test_str() {
        let s = "this is a test";
        let v = Variant::from(s);
        assert_eq!(v.get_str(), Some(s));
    }

    #[test]
    fn test_string() {
        let s = String::from("this is a test");
        let v = Variant::from(s.clone());
        assert_eq!(v.get(), Some(s.clone()));
    }

    #[test]
    fn test_eq() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        assert_eq!(v1, v2);
        assert!(v1 != v3);
    }

    #[test]
    fn test_hash() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        let mut set = HashSet::new();
        set.insert(v1);
        assert!(set.contains(&v2));
        assert!(!set.contains(&v3));
    }
}
<commit_msg>fix: return correct type for Variant::get_type()<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `Variant` binding and helper traits.
//!
//! [`Variant`](struct.Variant.html) is an immutable dynamically-typed generic
//! container. Its type and value are defined at construction and never change.
//!
//! `Variant` types are described by [`VariantType`](../struct.VariantType.html)
//! "type strings".
//!
//! Although `GVariant` supports arbitrarily complex types, this binding is
//! currently limited to the basic ones: `bool`, `u8`, `i16`, `u16`, `i32`,
//! `u32`, `i64`, `u64`, `f64` and `&str`/`String`.
//!
//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::Variant;
//!
//! // Using the `ToVariant` trait.
//! let num = 10.to_variant();
//!
//! // `is` tests the type of the value.
//! assert!(num.is::<i32>());
//!
//! // `get` tries to extract the value.
//! assert_eq!(num.get::<i32>(), Some(10));
//! assert_eq!(num.get::<u32>(), None);
//!
//! // `Variant` implements `From`
//! let hello = Variant::from("Hello!");
//!
//! // `get_str` tries to borrow a string slice.
//! assert_eq!(hello.get_str(), Some("Hello!"));
//! assert_eq!(num.get_str(), None);
//! ```

use VariantTy;
use Type;
use ffi as glib_ffi;
use translate::*;
use std::borrow::Cow;
use std::cmp::{PartialEq, Eq, PartialOrd, Ordering};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::slice;
use std::str;

glib_wrapper! {
    /// A generic immutable value capable of carrying various types.
    ///
    /// See the [module documentation](index.html) for more details.
    pub struct Variant(Shared<glib_ffi::GVariant>);

    match fn {
        ref => |ptr| glib_ffi::g_variant_ref_sink(ptr),
        unref => |ptr| glib_ffi::g_variant_unref(ptr),
        get_type => || Type::Variant.to_glib(),
    }
}

impl Variant {
    /// Returns the type of the value.
    pub fn type_(&self) -> &VariantTy {
        unsafe { VariantTy::from_ptr(glib_ffi::g_variant_get_type(self.to_glib_none().0)) }
    }

    /// Returns `true` if the type of the value corresponds to `T`.
    #[inline]
    pub fn is<T: StaticVariantType>(&self) -> bool {
        self.type_() == T::static_variant_type()
    }

    /// Tries to extract a value of type `T`.
    ///
    /// Returns `Some` if `T` matches the variant's type.
    #[inline]
    pub fn get<T: FromVariant>(&self) -> Option<T> {
        T::from_variant(self)
    }

    /// Tries to extract a `&str`.
    ///
    /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type
    /// strings).
    pub fn get_str(&self) -> Option<&str> {
        unsafe {
            match self.type_().to_str() {
                "s" | "o" | "g" => {
                    let mut len = 0;
                    let ptr = glib_ffi::g_variant_get_string(self.to_glib_none().0, &mut len);
                    let ret = str::from_utf8_unchecked(
                        slice::from_raw_parts(ptr as *const u8, len as usize));
                    Some(ret)
                }
                _ => None,
            }
        }
    }
}

unsafe impl Send for Variant { }
unsafe impl Sync for Variant { }

impl fmt::Debug for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("Variant {{ ptr: {:?}, type: \"{}\", value: {} }}",
            self.to_glib_none().0, self.type_(), self))
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let serialized: String = unsafe {
            from_glib_full(glib_ffi::g_variant_print(self.to_glib_none().0, false.to_glib()))
        };
        f.write_str(&serialized)
    }
}

impl PartialEq for Variant {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_variant_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Variant { }

impl PartialOrd for Variant {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        unsafe {
            if glib_ffi::g_variant_classify(self.to_glib_none().0) !=
               glib_ffi::g_variant_classify(other.to_glib_none().0) {
                return None;
            }

            if glib_ffi::g_variant_is_container(self.to_glib_none().0) != glib_ffi::GFALSE {
                return None;
            }

            let res = glib_ffi::g_variant_compare(self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _);
            if res < 0 {
                Some(Ordering::Less)
            } else if res > 0 {
                Some(Ordering::Equal)
            } else {
                Some(Ordering::Greater)
            }
        }
    }
}

impl Hash for Variant {
    fn hash<H: Hasher>(&self, state: &mut H) {
        unsafe {
            state.write_u32(glib_ffi::g_variant_hash(self.to_glib_none().0 as *const _))
        }
    }
}

/// Converts to `Variant`.
pub trait ToVariant {
    /// Returns a `Variant` clone of `self`.
    fn to_variant(&self) -> Variant;
}

/// Extracts a value.
pub trait FromVariant: Sized + StaticVariantType {
    /// Tries to extract a value.
    ///
    /// Returns `Some` if the variant's type matches `Self`.
    fn from_variant(variant: &Variant) -> Option<Self>;
}

/// Returns `VariantType` of `Self`.
pub trait StaticVariantType {
    /// Returns the `VariantType` corresponding to `Self`.
    fn static_variant_type() -> Cow<'static, VariantTy>;
}

impl<'a, T: ?Sized + ToVariant> ToVariant for &'a T {
    fn to_variant(&self) -> Variant {
        <T as ToVariant>::to_variant(self)
    }
}

impl<'a, T: ?Sized + StaticVariantType> StaticVariantType for &'a T {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        <T as StaticVariantType>::static_variant_type()
    }
}

macro_rules! impl_numeric {
    ($name:ty, $type_str:expr, $new_fn:ident, $get_fn:ident) => {
        impl StaticVariantType for $name {
            fn static_variant_type() -> Cow<'static, VariantTy> {
                unsafe { VariantTy::from_str_unchecked($type_str).into() }
            }
        }

        impl ToVariant for $name {
            fn to_variant(&self) -> Variant {
                unsafe { from_glib_none(glib_ffi::$new_fn(*self)) }
            }
        }

        impl FromVariant for $name {
            fn from_variant(variant: &Variant) -> Option<Self> {
                unsafe {
                    if variant.is::<Self>() {
                        Some(glib_ffi::$get_fn(variant.to_glib_none().0))
                    } else {
                        None
                    }
                }
            }
        }
    }
}

impl_numeric!(u8, "y", g_variant_new_byte, g_variant_get_byte);
impl_numeric!(i16, "n", g_variant_new_int16, g_variant_get_int16);
impl_numeric!(u16, "q", g_variant_new_uint16, g_variant_get_uint16);
impl_numeric!(i32, "i", g_variant_new_int32, g_variant_get_int32);
impl_numeric!(u32, "u", g_variant_new_uint32, g_variant_get_uint32);
impl_numeric!(i64, "x", g_variant_new_int64, g_variant_get_int64);
impl_numeric!(u64, "t", g_variant_new_uint64, g_variant_get_uint64);
impl_numeric!(f64, "d", g_variant_new_double, g_variant_get_double);

impl StaticVariantType for bool {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("b").into() }
    }
}

impl ToVariant for bool {
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_boolean(self.to_glib())) }
    }
}

impl FromVariant for bool {
    fn from_variant(variant: &Variant) -> Option<Self> {
        unsafe {
            if variant.is::<Self>() {
                Some(from_glib(glib_ffi::g_variant_get_boolean(variant.to_glib_none().0)))
            } else {
                None
            }
        }
    }
}

impl StaticVariantType for String {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for String {
    fn to_variant(&self) -> Variant {
        self[..].to_variant()
    }
}

impl FromVariant for String {
    fn from_variant(variant: &Variant) -> Option<Self> {
        variant.get_str().map(String::from)
    }
}

impl StaticVariantType for str {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for str {
    #[cfg(any(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_take_string(self.to_glib_full())) }
    }

    #[cfg(not(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_string(self.to_glib_none().0)) }
    }
}

impl<T: ToVariant> From<T> for Variant {
    fn from(value: T) -> Variant {
        value.to_variant()
    }
}

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

    macro_rules! unsigned {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    n /= 2;
                }
            }
        }
    }

    macro_rules! signed {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    let v = Variant::from(-n);
                    assert_eq!(v.get(), Some(-n));
                    n /= 2;
                }
            }
        }
    }

    unsigned!(test_u8, u8);
    unsigned!(test_u16, u16);
    unsigned!(test_u32, u32);
    unsigned!(test_u64, u64);
    signed!(test_i16, i16);
    signed!(test_i32, i32);
    signed!(test_i64, i64);

    #[test]
    fn test_str() {
        let s = "this is a test";
        let v = Variant::from(s);
        assert_eq!(v.get_str(), Some(s));
    }

    #[test]
    fn test_string() {
        let s = String::from("this is a test");
        let v = Variant::from(s.clone());
        assert_eq!(v.get(), Some(s.clone()));
    }

    #[test]
    fn test_eq() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        assert_eq!(v1, v2);
        assert!(v1 != v3);
    }

    #[test]
    fn test_hash() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        let mut set = HashSet::new();
        set.insert(v1);
        assert!(set.contains(&v2));
        assert!(!set.contains(&v3));
    }
}
<|endoftext|>