<commit_before>use crate::reflect::MessageDescriptor;
use crate::stream::WithCodedOutputStream;
use crate::CodedInputStream;
use crate::CodedOutputStream;
use crate::Message;
use crate::ProtobufError;
use crate::ProtobufResult;
use crate::UnknownFields;
use std::io::Write;

pub trait MessageDyn {
    fn descriptor(&self) -> MessageDescriptor;

    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;

    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()>;

    fn compute_size(&self) -> u32;

    /// True iff all required fields are initialized.
    /// Always returns `true` for protobuf 3.
    fn is_initialized(&self) -> bool;

    /// Get a reference to unknown fields.
    fn get_unknown_fields(&self) -> &UnknownFields;
    /// Get a mutable reference to unknown fields.
    fn mut_unknown_fields(&mut self) -> &mut UnknownFields;

    /// Temporary for migration
    fn as_message_todo(&self) -> &dyn Message;
}

impl<M: Message> MessageDyn for M {
    fn descriptor(&self) -> MessageDescriptor {
        self.descriptor()
    }

    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()> {
        self.merge_from(is)
    }

    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.write_to_with_cached_sizes(os)
    }

    fn compute_size(&self) -> u32 {
        self.compute_size()
    }

    fn is_initialized(&self) -> bool {
        self.is_initialized()
    }

    fn get_unknown_fields(&self) -> &UnknownFields {
        self.get_unknown_fields()
    }

    fn mut_unknown_fields(&mut self) -> &mut UnknownFields {
        self.mut_unknown_fields()
    }

    fn as_message_todo(&self) -> &dyn Message {
        self
    }
}

impl dyn MessageDyn {
    /// Check if all required fields of this object are initialized.
    fn check_initialized(&self) -> ProtobufResult<()> {
        if !self.is_initialized() {
            Err(ProtobufError::MessageNotInitialized(
                self.descriptor().name().to_owned(),
            ))
        } else {
            Ok(())
        }
    }

    /// Write the message to the writer.
    fn write_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    fn write_to_vec(&self, v: &mut Vec<u8>) -> ProtobufResult<()> {
        v.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to the stream.
    ///
    /// Results in error if message is not fully initialized.
    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized()?;

        // cache sizes
        self.compute_size();
        // TODO: reserve additional
        self.write_to_with_cached_sizes(os)?;

        Ok(())
    }

    /// Write the message to the vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_vec(&self, vec: &mut Vec<u8>) -> ProtobufResult<()> {
        let mut os = CodedOutputStream::vec(vec);
        self.write_length_delimited_to(&mut os)?;
        os.flush()?;
        Ok(())
    }

    /// Update this message object with fields read from given stream.
    fn merge_from_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
        let mut is = CodedInputStream::from_bytes(bytes);
        self.merge_from(&mut is)
    }

    /// Write the message to bytes vec.
    ///
    /// > **Note**: You can use [`Message::parse_from_bytes`]
    /// to do the reverse.
    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        self.check_initialized()?;

        let size = self.compute_size() as usize;
        let mut v = Vec::with_capacity(size);
        // skip zerofill
        unsafe {
            v.set_len(size);
        }
        {
            let mut os = CodedOutputStream::bytes(&mut v);
            self.write_to_with_cached_sizes(&mut os)?;
            os.check_eof();
        }
        Ok(v)
    }

    /// Write the message to the stream prepending the message with message length
    /// encoded as varint.
    pub fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let size = self.compute_size();
        os.write_raw_varint32(size)?;
        self.write_to_with_cached_sizes(os)?;

        // TODO: assert we've written same number of bytes as computed

        Ok(())
    }

    /// Write the message to the writer, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_length_delimited_to(os))
    }

    /// Write the message to the bytes vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        let mut v = Vec::new();
        v.with_coded_output_stream(|os| self.write_length_delimited_to(os))?;
        Ok(v)
    }
}
<commit_msg>Working on MessageDyn<commit_after>use crate::reflect::MessageDescriptor;
use crate::reflect::ProtobufValue;
use crate::stream::WithCodedOutputStream;
use crate::CodedInputStream;
use crate::CodedOutputStream;
use crate::Message;
use crate::ProtobufError;
use crate::ProtobufResult;
use crate::UnknownFields;
use std::fmt;
use std::io::Write;

/// Dynamic-dispatch version of [`Message`].
pub trait MessageDyn: ProtobufValue + fmt::Debug + Send + Sync + 'static {
    fn descriptor(&self) -> MessageDescriptor;

    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;

    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()>;

    fn compute_size(&self) -> u32;

    /// True iff all required fields are initialized.
    /// Always returns `true` for protobuf 3.
    fn is_initialized(&self) -> bool;

    /// Get a reference to unknown fields.
    fn get_unknown_fields(&self) -> &UnknownFields;
    /// Get a mutable reference to unknown fields.
    fn mut_unknown_fields(&mut self) -> &mut UnknownFields;

    /// Temporary for migration
    fn as_message_todo(&self) -> &dyn Message;
}

impl<M: Message> MessageDyn for M {
    fn descriptor(&self) -> MessageDescriptor {
        self.descriptor()
    }

    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()> {
        self.merge_from(is)
    }

    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.write_to_with_cached_sizes(os)
    }

    fn compute_size(&self) -> u32 {
        self.compute_size()
    }

    fn is_initialized(&self) -> bool {
        self.is_initialized()
    }

    fn get_unknown_fields(&self) -> &UnknownFields {
        self.get_unknown_fields()
    }

    fn mut_unknown_fields(&mut self) -> &mut UnknownFields {
        self.mut_unknown_fields()
    }

    fn as_message_todo(&self) -> &dyn Message {
        self
    }
}

impl dyn MessageDyn {
    /// Check if all required fields of this object are initialized.
    fn check_initialized(&self) -> ProtobufResult<()> {
        if !self.is_initialized() {
            Err(ProtobufError::MessageNotInitialized(
                self.descriptor().name().to_owned(),
            ))
        } else {
            Ok(())
        }
    }

    /// Write the message to the writer.
    fn write_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    fn write_to_vec(&self, v: &mut Vec<u8>) -> ProtobufResult<()> {
        v.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to the stream.
    ///
    /// Results in error if message is not fully initialized.
    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized()?;

        // cache sizes
        self.compute_size();
        // TODO: reserve additional
        self.write_to_with_cached_sizes(os)?;

        Ok(())
    }

    /// Write the message to the vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_vec(&self, vec: &mut Vec<u8>) -> ProtobufResult<()> {
        let mut os = CodedOutputStream::vec(vec);
        self.write_length_delimited_to(&mut os)?;
        os.flush()?;
        Ok(())
    }

    /// Update this message object with fields read from given stream.
    fn merge_from_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
        let mut is = CodedInputStream::from_bytes(bytes);
        self.merge_from(&mut is)
    }

    /// Write the message to bytes vec.
    ///
    /// > **Note**: You can use [`Message::parse_from_bytes`]
    /// to do the reverse.
    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        self.check_initialized()?;

        let size = self.compute_size() as usize;
        let mut v = Vec::with_capacity(size);
        // skip zerofill
        unsafe {
            v.set_len(size);
        }
        {
            let mut os = CodedOutputStream::bytes(&mut v);
            self.write_to_with_cached_sizes(&mut os)?;
            os.check_eof();
        }
        Ok(v)
    }

    /// Write the message to the stream prepending the message with message length
    /// encoded as varint.
    pub fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let size = self.compute_size();
        os.write_raw_varint32(size)?;
        self.write_to_with_cached_sizes(os)?;

        // TODO: assert we've written same number of bytes as computed

        Ok(())
    }

    /// Write the message to the writer, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_length_delimited_to(os))
    }

    /// Write the message to the bytes vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        let mut v = Vec::new();
        v.with_coded_output_stream(|os| self.write_length_delimited_to(os))?;
        Ok(v)
    }
}
<|endoftext|>


<commit_before>extern crate diesel;
extern crate dotenv;
extern crate kuchiki;
extern crate server;

use diesel::pg::PgConnection;
use diesel::prelude::*;
use diesel::dsl::sql;
use diesel::sql_types::Bool;

use dotenv::dotenv;
use kuchiki::traits::*;
use server::models::{get_paid_for_by, Ad};
use server::schema::ads::*;
use server::schema::ads::dsl::*;
use server::start_logging;
use std::env;

fn main() {
    dotenv().ok();
    start_logging();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let conn = PgConnection::establish(&database_url).unwrap();
    let dbads: Vec<Ad> = ads.order(created_at.desc())
        .filter(sql::<Bool>("created_at > '2018-05-24'"))
        .load::<Ad>(&conn)
        .expect("Couldn't get ads.");
    for ad in dbads {
        let document = kuchiki::parse_html().one(ad.html.clone());
        let parsed_paid_for_by = get_paid_for_by(&document);
        if parsed_paid_for_by.is_some() {
            println!("{:?}", parsed_paid_for_by.clone().unwrap());
            diesel::update(ads.find(ad.id))
                .set(paid_for_by.eq(parsed_paid_for_by.unwrap()))
                .execute(&conn)
                .unwrap();
        }

    }
}
<commit_msg>backfill paid_for_by for those that need it<commit_after>extern crate diesel;
extern crate dotenv;
extern crate kuchiki;
extern crate server;

use diesel::pg::PgConnection;
use diesel::prelude::*;
use diesel::dsl::sql;
use diesel::sql_types::Bool;

use dotenv::dotenv;
use kuchiki::traits::*;
use server::models::{get_paid_for_by, Ad};
use server::schema::ads::*;
use server::schema::ads::dsl::*;
use server::start_logging;
use std::env;

fn main() {
    dotenv().ok();
    start_logging();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let conn = PgConnection::establish(&database_url).unwrap();
    let dbads: Vec<Ad> = ads.order(created_at.desc())
        .filter(sql::<Bool>("created_at > '2018-05-24'"))
        .filter(sql::<Bool>("paid_for_by is null"))
        .filter(sql::<Bool>("html ilike '%Paid for by%'"))
        .load::<Ad>(&conn)
        .expect("Couldn't get ads.");
    for ad in dbads {
        let document = kuchiki::parse_html().one(ad.html.clone());
        let parsed_paid_for_by = get_paid_for_by(&document);
        if parsed_paid_for_by.is_some() {
            println!("{:?}", parsed_paid_for_by.clone().unwrap());
            diesel::update(ads.find(ad.id))
                .set(paid_for_by.eq(parsed_paid_for_by.unwrap()))
                .execute(&conn)
                .unwrap();
        }

    }
}
<|endoftext|>


<commit_before>use super::{Null, Value, ValueRef};
use ::Result;

/// `ToSqlOutput` represents the possible output types for implementors of the `ToSql` trait.
pub enum ToSqlOutput<'a> {
    /// A borrowed SQLite-representable value.
    Borrowed(ValueRef<'a>),

    /// An owned SQLite-representable value.
    Owned(Value),

    /// A BLOB of the given length that is filled with zeroes.
    #[cfg(feature = "blob")]
    ZeroBlob(i32),
}

impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a>
    where &'a T: Into<ValueRef<'a>>
{
    fn from(t: &'a T) -> Self {
        ToSqlOutput::Borrowed(t.into())
    }
}

impl<'a, T: Into<Value>> From<T> for ToSqlOutput<'a> {
    fn from(t: T) -> Self {
        ToSqlOutput::Owned(t.into())
    }
}

impl<'a> ToSql for ToSqlOutput<'a> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(match *self {
            ToSqlOutput::Borrowed(v) => ToSqlOutput::Borrowed(v),
            ToSqlOutput::Owned(ref v) => ToSqlOutput::Borrowed(ValueRef::from(v)),

            #[cfg(feature = "blob")]
            ToSqlOutput::ZeroBlob(i) => ToSqlOutput::ZeroBlob(i),
        })
    }
}

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    fn to_sql(&self) -> Result<ToSqlOutput>;
}

// We should be able to use a generic impl like this:
//
// impl<T: Copy> ToSql for T where T: Into<Value> {
//     fn to_sql(&self) -> Result<ToSqlOutput> {
//         Ok(ToSqlOutput::from((*self).into()))
//     }
// }
//
// instead of the following macro, but this runs afoul of
// https://github.com/rust-lang/rust/issues/30191 and reports conflicting
// implementations even when there aren't any.

macro_rules! to_sql_self(
    ($t:ty) => (
        impl ToSql for $t {
            fn to_sql(&self) -> Result<ToSqlOutput> {
                Ok(ToSqlOutput::from(*self))
            }
        }
    )
);

to_sql_self!(Null);
to_sql_self!(bool);
to_sql_self!(i8);
to_sql_self!(i16);
to_sql_self!(i32);
to_sql_self!(i64);
to_sql_self!(u8);
to_sql_self!(u16);
to_sql_self!(u32);
to_sql_self!(f64);

impl<'a, T: ?Sized> ToSql for &'a T
    where &'a T: Into<ToSqlOutput<'a>>
{
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from((*self).into()))
    }
}

impl ToSql for String {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_str()))
    }
}

impl ToSql for Vec<u8> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_slice()))
    }
}

impl ToSql for Value {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl<T: ToSql> ToSql for Option<T> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        match *self {
            None => Ok(ToSqlOutput::from(Null)),
            Some(ref t) => t.to_sql(),
        }
    }
}

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

    fn is_to_sql<T: ToSql>() {}

    #[test]
    fn test_integral_types() {
        is_to_sql::<i8>();
        is_to_sql::<i16>();
        is_to_sql::<i32>();
        is_to_sql::<i64>();
        is_to_sql::<u8>();
        is_to_sql::<u16>();
        is_to_sql::<u32>();
    }
}
<commit_msg>Derive Clone, Debug, and PartialEq on ToSqlOutput.<commit_after>use super::{Null, Value, ValueRef};
use ::Result;

/// `ToSqlOutput` represents the possible output types for implementors of the `ToSql` trait.
#[derive(Clone,Debug,PartialEq)]
pub enum ToSqlOutput<'a> {
    /// A borrowed SQLite-representable value.
    Borrowed(ValueRef<'a>),

    /// An owned SQLite-representable value.
    Owned(Value),

    /// A BLOB of the given length that is filled with zeroes.
    #[cfg(feature = "blob")]
    ZeroBlob(i32),
}

impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a>
    where &'a T: Into<ValueRef<'a>>
{
    fn from(t: &'a T) -> Self {
        ToSqlOutput::Borrowed(t.into())
    }
}

impl<'a, T: Into<Value>> From<T> for ToSqlOutput<'a> {
    fn from(t: T) -> Self {
        ToSqlOutput::Owned(t.into())
    }
}

impl<'a> ToSql for ToSqlOutput<'a> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(match *self {
            ToSqlOutput::Borrowed(v) => ToSqlOutput::Borrowed(v),
            ToSqlOutput::Owned(ref v) => ToSqlOutput::Borrowed(ValueRef::from(v)),

            #[cfg(feature = "blob")]
            ToSqlOutput::ZeroBlob(i) => ToSqlOutput::ZeroBlob(i),
        })
    }
}

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    fn to_sql(&self) -> Result<ToSqlOutput>;
}

// We should be able to use a generic impl like this:
//
// impl<T: Copy> ToSql for T where T: Into<Value> {
//     fn to_sql(&self) -> Result<ToSqlOutput> {
//         Ok(ToSqlOutput::from((*self).into()))
//     }
// }
//
// instead of the following macro, but this runs afoul of
// https://github.com/rust-lang/rust/issues/30191 and reports conflicting
// implementations even when there aren't any.

macro_rules! to_sql_self(
    ($t:ty) => (
        impl ToSql for $t {
            fn to_sql(&self) -> Result<ToSqlOutput> {
                Ok(ToSqlOutput::from(*self))
            }
        }
    )
);

to_sql_self!(Null);
to_sql_self!(bool);
to_sql_self!(i8);
to_sql_self!(i16);
to_sql_self!(i32);
to_sql_self!(i64);
to_sql_self!(u8);
to_sql_self!(u16);
to_sql_self!(u32);
to_sql_self!(f64);

impl<'a, T: ?Sized> ToSql for &'a T
    where &'a T: Into<ToSqlOutput<'a>>
{
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from((*self).into()))
    }
}

impl ToSql for String {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_str()))
    }
}

impl ToSql for Vec<u8> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_slice()))
    }
}

impl ToSql for Value {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl<T: ToSql> ToSql for Option<T> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        match *self {
            None => Ok(ToSqlOutput::from(Null)),
            Some(ref t) => t.to_sql(),
        }
    }
}

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

    fn is_to_sql<T: ToSql>() {}

    #[test]
    fn test_integral_types() {
        is_to_sql::<i8>();
        is_to_sql::<i16>();
        is_to_sql::<i32>();
        is_to_sql::<i64>();
        is_to_sql::<u8>();
        is_to_sql::<u16>();
        is_to_sql::<u32>();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::io;

use libc::{c_int, termios};
use libc::{cfgetospeed, cfmakeraw, cfsetispeed, cfsetospeed, tcgetattr, tcsetattr};
use libc::{B0, B110, B134, B150, B200, B300, B50, B75};
use libc::{B1000000, B1152000, B460800, B500000, B576000, B921600};
use libc::{B115200, B19200, B230400, B38400, B57600};
use libc::{B1200, B1800, B2400, B4800, B600, B9600};
use libc::{B1500000, B2000000, B2500000, B3000000, B3500000, B4000000};

use libc::{CS5, CS6, CS7, CS8, CSIZE, CSTOPB, PARENB, PARODD};
use libc::{CLOCAL, CMSPAR, CREAD, CRTSCTS, TCSANOW};
use libc::{VMIN, VTIME};

use uart::{Error, Parity, Result};

fn parse_retval(retval: c_int) -> Result<i32> {
    if retval == -1 {
        Err(Error::Io(io::Error::last_os_error()))
    } else {
        Ok(retval)
    }
}

pub unsafe fn attributes(fd: c_int) -> Result<termios> {
    let mut attr = termios {
        c_iflag: 0,
        c_oflag: 0,
        c_cflag: 0,
        c_lflag: 0,
        c_line: 0,
        c_cc: [0u8; 32],
        c_ispeed: 0,
        c_ospeed: 0,
    };

    parse_retval(tcgetattr(fd, &mut attr))?;

    Ok(attr)
}

pub unsafe fn set_attributes(fd: c_int, attr: &termios) -> Result<()> {
    parse_retval(tcsetattr(fd, TCSANOW, attr))?;

    Ok(())
}

pub unsafe fn line_speed(fd: c_int) -> Result<u32> {
    Ok(match cfgetospeed(&attributes(fd)?) {
        B0 => 0,
        B50 => 50,
        B75 => 75,
        B110 => 110,
        B134 => 134,
        B150 => 150,
        B200 => 200,
        B300 => 300,
        B600 => 600,
        B1200 => 1_200,
        B1800 => 1_800,
        B2400 => 2_400,
        B4800 => 4_800,
        B9600 => 9_600,
        B19200 => 19_200,
        B38400 => 38_400,
        B57600 => 57_600,
        B115200 => 115_200,
        B230400 => 230_400,
        B460800 => 460_800,
        B500000 => 500_000,
        B576000 => 576_000,
        B921600 => 921_600,
        B1000000 => 1_000_000,
        B1152000 => 1_152_000,
        B1500000 => 1_500_000,
        B2000000 => 2_000_000,
        B2500000 => 2_500_000,
        B3000000 => 3_000_000,
        B3500000 => 3_500_000,
        B4000000 => 4_000_000,
        _ => return Err(Error::InvalidValue),
    })
}

pub unsafe fn set_line_speed(fd: c_int, line_speed: u32) -> Result<()> {
    let baud = match line_speed {
        0 => B0,
        50 => B50,
        75 => B75,
        110 => B110,
        134 => B134,
        150 => B150,
        200 => B200,
        300 => B300,
        600 => B600,
        1_200 => B1200,
        1_800 => B1800,
        2_400 => B2400,
        4_800 => B4800,
        9_600 => B9600,
        19_200 => B19200,
        38_400 => B38400,
        57_600 => B57600,
        115_200 => B115200,
        230_400 => B230400,
        460_800 => B460800,
        500_000 => B500000,
        576_000 => B576000,
        921_600 => B921600,
        1_000_000 => B1000000,
        1_152_000 => B1152000,
        1_500_000 => B1500000,
        2_000_000 => B2000000,
        2_500_000 => B2500000,
        3_000_000 => B3000000,
        3_500_000 => B3500000,
        4_000_000 => B4000000,
        _ => return Err(Error::InvalidValue),
    };

    let mut attr = attributes(fd)?;
    parse_retval(cfsetispeed(&mut attr, baud))?;
    parse_retval(cfsetospeed(&mut attr, baud))?;
    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn parity(fd: c_int) -> Result<Parity> {
    let attr = attributes(fd)?;

    if (attr.c_cflag & PARENB) == 0 {
        return Ok(Parity::None);
    } else if (attr.c_cflag & PARENB) > 0 && (attr.c_cflag & PARODD) == 0 {
        return Ok(Parity::Even);
    } else if (attr.c_cflag & PARENB) > 0 && (attr.c_cflag & PARODD) > 0 {
        return Ok(Parity::Odd);
    } else if (attr.c_cflag & PARENB) > 0
        && (attr.c_cflag & CMSPAR) > 0
        && (attr.c_cflag & PARODD) > 0
    {
        return Ok(Parity::Mark);
    } else if (attr.c_cflag & PARENB) > 0
        && (attr.c_cflag & CMSPAR) > 0
        && (attr.c_cflag & PARODD) == 0
    {
        return Ok(Parity::Space);
    }

    Err(Error::InvalidValue)
}

pub unsafe fn set_parity(fd: c_int, parity: Parity) -> Result<()> {
    let mut attr = attributes(fd)?;

    match parity {
        Parity::None => {
            attr.c_cflag &= !PARENB;
            attr.c_cflag &= !PARODD;
        }
        Parity::Even => {
            attr.c_cflag |= PARENB;
            attr.c_cflag &= !PARODD;
        }
        Parity::Odd => {
            attr.c_cflag |= PARENB | PARODD;
        }
        Parity::Mark => {
            attr.c_cflag |= PARENB | PARODD | CMSPAR;
        }
        Parity::Space => {
            attr.c_cflag |= PARENB | CMSPAR;
            attr.c_cflag &= !PARODD;
        }
    }

    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn data_bits(fd: c_int) -> Result<u8> {
    let attr = attributes(fd)?;

    Ok(match attr.c_cflag & CSIZE {
        CS5 => 5,
        CS6 => 6,
        CS7 => 7,
        CS8 => 8,
        _ => return Err(Error::InvalidValue),
    })
}

pub unsafe fn set_data_bits(fd: c_int, data_bits: u8) -> Result<()> {
    let mut attr = attributes(fd)?;

    attr.c_cflag &= !CSIZE;
    match data_bits {
        5 => attr.c_cflag |= CS5,
        6 => attr.c_cflag |= CS6,
        7 => attr.c_cflag |= CS7,
        8 => attr.c_cflag |= CS8,
        _ => return Err(Error::InvalidValue),
    }

    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn stop_bits(fd: c_int) -> Result<u8> {
    let attr = attributes(fd)?;

    if (attr.c_cflag & CSTOPB) > 0 {
        Ok(2)
    } else {
        Ok(1)
    }
}

pub unsafe fn set_stop_bits(fd: c_int, stop_bits: u8) -> Result<()> {
    let mut attr = attributes(fd)?;

    match stop_bits {
        1 => attr.c_cflag &= !CSTOPB,
        2 => attr.c_cflag |= CSTOPB,
        _ => return Err(Error::InvalidValue),
    }

    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn set_raw_mode(fd: c_int) -> Result<()> {
    let mut attr = attributes(fd)?;
    cfmakeraw(&mut attr); // Changes flags to enable non-canonical mode
    attr.c_cc[VMIN] = 0; // Don't block read() when there's no waiting data
    attr.c_cc[VTIME] = 0; // No timeout needed
    set_attributes(fd, &attr)?;

    Ok(())
}

// If CREAD isn't set, all input is discarded
pub unsafe fn enable_read(fd: c_int) -> Result<()> {
    let mut attr = attributes(fd)?;
    attr.c_cflag |= CREAD;
    set_attributes(fd, &attr)?;

    Ok(())
}

// Ignore carrier detect signal
pub unsafe fn ignore_carrier_detect(fd: c_int) -> Result<()> {
    let mut attr = attributes(fd)?;
    attr.c_cflag |= CLOCAL;
    set_attributes(fd, &attr)?;

    Ok(())
}
<commit_msg>Ignore unused imports<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(unused_imports)]
#![allow(dead_code)]

use std::io;

use libc::{c_int, termios};
use libc::{cfgetospeed, cfmakeraw, cfsetispeed, cfsetospeed, tcgetattr, tcsetattr};
use libc::{B0, B110, B134, B150, B200, B300, B50, B75};
use libc::{B1000000, B1152000, B460800, B500000, B576000, B921600};
use libc::{B115200, B19200, B230400, B38400, B57600};
use libc::{B1200, B1800, B2400, B4800, B600, B9600};
use libc::{B1500000, B2000000, B2500000, B3000000, B3500000, B4000000};

use libc::{CS5, CS6, CS7, CS8, CSIZE, CSTOPB, PARENB, PARODD};
use libc::{CLOCAL, CMSPAR, CREAD, CRTSCTS, TCSANOW};
use libc::{VMIN, VTIME};

use uart::{Error, Parity, Result};

fn parse_retval(retval: c_int) -> Result<i32> {
    if retval == -1 {
        Err(Error::Io(io::Error::last_os_error()))
    } else {
        Ok(retval)
    }
}

pub unsafe fn attributes(fd: c_int) -> Result<termios> {
    let mut attr = termios {
        c_iflag: 0,
        c_oflag: 0,
        c_cflag: 0,
        c_lflag: 0,
        c_line: 0,
        c_cc: [0u8; 32],
        c_ispeed: 0,
        c_ospeed: 0,
    };

    parse_retval(tcgetattr(fd, &mut attr))?;

    Ok(attr)
}

pub unsafe fn set_attributes(fd: c_int, attr: &termios) -> Result<()> {
    parse_retval(tcsetattr(fd, TCSANOW, attr))?;

    Ok(())
}

pub unsafe fn line_speed(fd: c_int) -> Result<u32> {
    Ok(match cfgetospeed(&attributes(fd)?) {
        B0 => 0,
        B50 => 50,
        B75 => 75,
        B110 => 110,
        B134 => 134,
        B150 => 150,
        B200 => 200,
        B300 => 300,
        B600 => 600,
        B1200 => 1_200,
        B1800 => 1_800,
        B2400 => 2_400,
        B4800 => 4_800,
        B9600 => 9_600,
        B19200 => 19_200,
        B38400 => 38_400,
        B57600 => 57_600,
        B115200 => 115_200,
        B230400 => 230_400,
        B460800 => 460_800,
        B500000 => 500_000,
        B576000 => 576_000,
        B921600 => 921_600,
        B1000000 => 1_000_000,
        B1152000 => 1_152_000,
        B1500000 => 1_500_000,
        B2000000 => 2_000_000,
        B2500000 => 2_500_000,
        B3000000 => 3_000_000,
        B3500000 => 3_500_000,
        B4000000 => 4_000_000,
        _ => return Err(Error::InvalidValue),
    })
}

pub unsafe fn set_line_speed(fd: c_int, line_speed: u32) -> Result<()> {
    let baud = match line_speed {
        0 => B0,
        50 => B50,
        75 => B75,
        110 => B110,
        134 => B134,
        150 => B150,
        200 => B200,
        300 => B300,
        600 => B600,
        1_200 => B1200,
        1_800 => B1800,
        2_400 => B2400,
        4_800 => B4800,
        9_600 => B9600,
        19_200 => B19200,
        38_400 => B38400,
        57_600 => B57600,
        115_200 => B115200,
        230_400 => B230400,
        460_800 => B460800,
        500_000 => B500000,
        576_000 => B576000,
        921_600 => B921600,
        1_000_000 => B1000000,
        1_152_000 => B1152000,
        1_500_000 => B1500000,
        2_000_000 => B2000000,
        2_500_000 => B2500000,
        3_000_000 => B3000000,
        3_500_000 => B3500000,
        4_000_000 => B4000000,
        _ => return Err(Error::InvalidValue),
    };

    let mut attr = attributes(fd)?;
    parse_retval(cfsetispeed(&mut attr, baud))?;
    parse_retval(cfsetospeed(&mut attr, baud))?;
    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn parity(fd: c_int) -> Result<Parity> {
    let attr = attributes(fd)?;

    if (attr.c_cflag & PARENB) == 0 {
        return Ok(Parity::None);
    } else if (attr.c_cflag & PARENB) > 0 && (attr.c_cflag & PARODD) == 0 {
        return Ok(Parity::Even);
    } else if (attr.c_cflag & PARENB) > 0 && (attr.c_cflag & PARODD) > 0 {
        return Ok(Parity::Odd);
    } else if (attr.c_cflag & PARENB) > 0
        && (attr.c_cflag & CMSPAR) > 0
        && (attr.c_cflag & PARODD) > 0
    {
        return Ok(Parity::Mark);
    } else if (attr.c_cflag & PARENB) > 0
        && (attr.c_cflag & CMSPAR) > 0
        && (attr.c_cflag & PARODD) == 0
    {
        return Ok(Parity::Space);
    }

    Err(Error::InvalidValue)
}

pub unsafe fn set_parity(fd: c_int, parity: Parity) -> Result<()> {
    let mut attr = attributes(fd)?;

    match parity {
        Parity::None => {
            attr.c_cflag &= !PARENB;
            attr.c_cflag &= !PARODD;
        }
        Parity::Even => {
            attr.c_cflag |= PARENB;
            attr.c_cflag &= !PARODD;
        }
        Parity::Odd => {
            attr.c_cflag |= PARENB | PARODD;
        }
        Parity::Mark => {
            attr.c_cflag |= PARENB | PARODD | CMSPAR;
        }
        Parity::Space => {
            attr.c_cflag |= PARENB | CMSPAR;
            attr.c_cflag &= !PARODD;
        }
    }

    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn data_bits(fd: c_int) -> Result<u8> {
    let attr = attributes(fd)?;

    Ok(match attr.c_cflag & CSIZE {
        CS5 => 5,
        CS6 => 6,
        CS7 => 7,
        CS8 => 8,
        _ => return Err(Error::InvalidValue),
    })
}

pub unsafe fn set_data_bits(fd: c_int, data_bits: u8) -> Result<()> {
    let mut attr = attributes(fd)?;

    attr.c_cflag &= !CSIZE;
    match data_bits {
        5 => attr.c_cflag |= CS5,
        6 => attr.c_cflag |= CS6,
        7 => attr.c_cflag |= CS7,
        8 => attr.c_cflag |= CS8,
        _ => return Err(Error::InvalidValue),
    }

    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn stop_bits(fd: c_int) -> Result<u8> {
    let attr = attributes(fd)?;

    if (attr.c_cflag & CSTOPB) > 0 {
        Ok(2)
    } else {
        Ok(1)
    }
}

pub unsafe fn set_stop_bits(fd: c_int, stop_bits: u8) -> Result<()> {
    let mut attr = attributes(fd)?;

    match stop_bits {
        1 => attr.c_cflag &= !CSTOPB,
        2 => attr.c_cflag |= CSTOPB,
        _ => return Err(Error::InvalidValue),
    }

    set_attributes(fd, &attr)?;

    Ok(())
}

pub unsafe fn set_raw_mode(fd: c_int) -> Result<()> {
    let mut attr = attributes(fd)?;
    cfmakeraw(&mut attr); // Changes flags to enable non-canonical mode
    attr.c_cc[VMIN] = 0; // Don't block read() when there's no waiting data
    attr.c_cc[VTIME] = 0; // No timeout needed
    set_attributes(fd, &attr)?;

    Ok(())
}

// If CREAD isn't set, all input is discarded
pub unsafe fn enable_read(fd: c_int) -> Result<()> {
    let mut attr = attributes(fd)?;
    attr.c_cflag |= CREAD;
    set_attributes(fd, &attr)?;

    Ok(())
}

// Ignore carrier detect signal
pub unsafe fn ignore_carrier_detect(fd: c_int) -> Result<()> {
    let mut attr = attributes(fd)?;
    attr.c_cflag |= CLOCAL;
    set_attributes(fd, &attr)?;

    Ok(())
}
<|endoftext|>


<commit_before>use std::str;
use std::io;
use std::fs;
use rustc_serialize::hex::FromHex;
use std::path::{PathBuf, Path};
use std::marker::PhantomData;
use std::error::Error;

use toml;

use rex_utils;
use rex_utils::rect::Rect;
use super::super::frontend::{Frontend, Style, KeyPress};
use super::super::filesystem::Filesystem;
use super::super::config::Value;
use super::input::Input;
use super::widget::Widget;

use super::common::Canceled;

pub enum BaseInputLineActions {
    Edit(char),
    Ctrl(char),
    MoveLeft,
    MoveRight,
    DeleteWithMove,
    Ok,
    Cancel
}

pub trait InputLineBehavior {
    fn get_prefix(&self) -> &str;
    fn get_status(&self) -> Result<&str, &str> {
        Ok("")
    }
    fn do_update(&mut self, data: &[u8]) {

    }
    fn do_enter(&mut self, data: &[u8]);
    fn do_cancel(&mut self);
    fn do_shortcut(&mut self, shortcut: char) {

    }
}

pub struct InputLine<T:InputLineBehavior> {
    behavior: T,
    data: Vec<u8>,
    input_pos: isize,
}

impl<T:InputLineBehavior> InputLine<T> {
    pub fn new(behavior: T) -> InputLine<T> {
        InputLine {
            behavior: behavior,
            data: vec![],
            input_pos: 0,
        }
    }
}

impl<T:InputLineBehavior> Widget for InputLine<T> {
    fn input(&mut self, input: &Input, key: KeyPress) -> bool {
        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.behavior.do_enter(&self.data)
            }
            BaseInputLineActions::Cancel => {
                self.behavior.do_cancel()
            }
            BaseInputLineActions::MoveLeft => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                }
            }
            BaseInputLineActions::MoveRight => {
                if self.input_pos < self.data.len() as isize {
                    self.input_pos += 1;
                }
            }
            BaseInputLineActions::Edit(ch) => {
                if ch.len_utf8() == 1 {
                    self.data.insert(self.input_pos as usize, ch as u8);
                    self.input_pos += 1;
                } else {
                    // TODO: Make it printable rather than alphanumeric
                }
            }
            BaseInputLineActions::Ctrl(ch) => {
                self.behavior.do_shortcut(ch)
            }
            BaseInputLineActions::DeleteWithMove => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                    self.data.remove(self.input_pos as usize);
                    self.behavior.do_update(&self.data);
                }
            }
        };

        self.behavior.do_update(&self.data);

        return true;
    }

    fn draw(&mut self, rb: &mut Frontend, area: Rect<isize>, has_focus: bool) {
        let prefix = self.behavior.get_prefix();

        let (style, status_msg) = match self.behavior.get_status() {
            Ok(sm) => (Style::InputLine, sm),
            Err(sm) => (Style::InputLineError, sm),
        };

        let (x_pos, start_index) = if area.width >= status_msg.len() as isize {
            (area.width - status_msg.len() as isize, 0)
        } else {
            (0, area.width - status_msg.len() as isize)
        };

        rb.print_style(area.left as usize, area.top as usize, style,
                 &rex_utils::string_with_repeat(' ', area.width as usize));
        rb.print_style(x_pos as usize, area.top as usize, style,
              &status_msg[start_index as usize..]);
        rb.print_style(area.left as usize, area.top as usize, style,
                 &format!("{}{} ", prefix, str::from_utf8(&self.data).unwrap()));
        if has_focus {
            rb.set_cursor(prefix.len() as isize + self.input_pos, (area.top as isize));
        }
    }
}

enum RadixType {
    DecRadix,
    HexRadix,
    OctRadix,
}

signal_decl!{GotoEvent(isize)}

pub struct GotoInputLineBehavior {
    radix: RadixType,
    is_valid: bool,
    pub on_done: GotoEvent,
    pub on_cancel: Canceled,
}

impl GotoInputLineBehavior {
    pub fn new() -> GotoInputLineBehavior {
        GotoInputLineBehavior {
            radix: RadixType::DecRadix,
            is_valid: true,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_radix(&mut self, r: RadixType) {
        self.radix = r;
    }

    fn get_pos(&mut self, data: &[u8]) -> Option<isize> {
        let radix = match self.radix {
            RadixType::DecRadix => 10,
            RadixType::HexRadix => 16,
            RadixType::OctRadix => 8,
        };

        match str::from_utf8(&data) {
            Ok(gs) => isize::from_str_radix(&gs, radix).ok(),
            Err(_) => None
        }
    }

    fn do_goto(&mut self, data: &[u8]) {
        match self.get_pos(data) {
            Some(pos) => {
                self.on_done.signal(pos)
            }
            None => {
                self.on_cancel.signal(Some(format!("Bad position!")));
            }
        };
    }
}

impl InputLineBehavior for GotoInputLineBehavior {
    fn get_prefix(&self) -> &str {
        match self.radix {
            RadixType::DecRadix => "Goto (Dec):",
            RadixType::HexRadix => "Goto (Hex):",
            RadixType::OctRadix => "Goto (Oct):",
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if self.is_valid {
            Ok("")
        } else {
            Err("Invalid position")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.is_valid = self.get_pos(data).is_some();
    }

    fn do_enter(&mut self, data: &[u8]) {
        if self.is_valid {
            self.do_goto(data);
        }
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'd' => {
                self.set_radix(RadixType::DecRadix);
            }
            'h' => {
                self.set_radix(RadixType::HexRadix);
            }
            'o' => {
                self.set_radix(RadixType::OctRadix);
            }
            _ => ()
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum DataType {
    AsciiStr,
    UnicodeStr,
    HexStr,
}

signal_decl!{FindEvent(Vec<u8>)}

pub struct FindInputLine {
    data_type: DataType,
    is_valid: bool,
    pub on_find: FindEvent,
    pub on_cancel: Canceled,
}

impl FindInputLine {
    pub fn new() -> FindInputLine {
        FindInputLine {
            data_type: DataType::AsciiStr,
            is_valid: true,
            on_find: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_search_data_type(&mut self, dt: DataType) {
        self.data_type = dt;
    }

    fn parse_hex(&self, data: &[u8]) -> Option<Vec<u8>> {
        str::from_utf8(data).unwrap().from_hex().ok()
    }

    fn do_find(&mut self, data: &[u8]) {
        let ll = self.parse_hex(data);

        let needle: Vec<u8> = match self.data_type {
            DataType::AsciiStr => data.clone().into(),
            DataType::UnicodeStr => data.clone().into(),
            DataType::HexStr => {
                match ll {
                    Some(n) => n,
                    None => {
                        self.on_cancel.signal(Some(format!("Bad hex value")));
                        return;
                    }
                }
            }
        };

        self.on_find.signal(needle);
    }
}

impl InputLineBehavior for FindInputLine {
    fn get_prefix(&self) -> &str {
        match self.data_type {
            DataType::AsciiStr => "Find(Ascii): ",
            DataType::UnicodeStr => "Find(Uni): ",
            DataType::HexStr => "Find(Hex): ",
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if self.is_valid {
            Ok("")
        } else {
            Err("Invalid Hex Value")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.is_valid = (self.data_type != DataType::HexStr) || self.parse_hex(data).is_some();
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.do_find(data);
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'a' => {
                self.set_search_data_type(DataType::AsciiStr);
            }
            'u' => {
                self.set_search_data_type(DataType::UnicodeStr);
            }
            'h' => {
                self.set_search_data_type(DataType::HexStr);
            }
            _ => ()
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum PathInputType {
    Open,
    Save
}

signal_decl!{PathEvent(PathBuf)}

pub struct PathInputLine<FS: Filesystem> {
    pub on_done: PathEvent,
    pub on_cancel: Canceled,
    input_type: PathInputType,
    res: io::Result<()>,

    _fs: PhantomData<FS>
}

impl<FS: Filesystem> PathInputLine<FS> {
    pub fn new(input_type: PathInputType) -> PathInputLine<FS> {
        PathInputLine {
            input_type: input_type,
            on_done: Default::default(),
            on_cancel: Default::default(),
            res: Ok(()),

            _fs: PhantomData,
        }
    }
}

impl<FS: Filesystem> InputLineBehavior for PathInputLine<FS> {
    fn get_prefix(&self) -> &str {
        if self.input_type == PathInputType::Open {
            "Open: "
        } else {
            "Save: "
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        match self.res {
            Ok(_) => Ok(""),
            Err(ref e) => Err(e.description())
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.res = if self.input_type == PathInputType::Open {
            FS::can_open(Path::new(str::from_utf8(data).unwrap()))
        } else {
            FS::can_save(Path::new(str::from_utf8(data).unwrap()))
        }
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(PathBuf::from(str::from_utf8(data).unwrap()));
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}

signal_decl!{ConfigSetEvent(String)}

pub struct ConfigSetLine {
    pub on_done: ConfigSetEvent,
    pub on_cancel: Canceled,
    prefix: String,
}

impl ConfigSetLine {
    pub fn new(prefix: String, value: Value) -> ConfigSetLine {
        ConfigSetLine {
            prefix: prefix,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }
}

impl InputLineBehavior for ConfigSetLine {
    fn get_prefix(&self) -> &str {
        &self.prefix
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(str::from_utf8(&data).unwrap().to_owned());
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}
<commit_msg>Make cleaner error messages for the path input line<commit_after>use std::str;
use std::io;
use std::fs;
use rustc_serialize::hex::FromHex;
use std::path::{PathBuf, Path};
use std::marker::PhantomData;
use std::error::Error;

use toml;

use rex_utils;
use rex_utils::rect::Rect;
use super::super::frontend::{Frontend, Style, KeyPress};
use super::super::filesystem::Filesystem;
use super::super::config::Value;
use super::input::Input;
use super::widget::Widget;

use super::common::Canceled;

pub enum BaseInputLineActions {
    Edit(char),
    Ctrl(char),
    MoveLeft,
    MoveRight,
    DeleteWithMove,
    Ok,
    Cancel
}

pub trait InputLineBehavior {
    fn get_prefix(&self) -> &str;
    fn get_status(&self) -> Result<&str, &str> {
        Ok("")
    }
    fn do_update(&mut self, data: &[u8]) {

    }
    fn do_enter(&mut self, data: &[u8]);
    fn do_cancel(&mut self);
    fn do_shortcut(&mut self, shortcut: char) {

    }
}

pub struct InputLine<T:InputLineBehavior> {
    behavior: T,
    data: Vec<u8>,
    input_pos: isize,
}

impl<T:InputLineBehavior> InputLine<T> {
    pub fn new(behavior: T) -> InputLine<T> {
        InputLine {
            behavior: behavior,
            data: vec![],
            input_pos: 0,
        }
    }
}

impl<T:InputLineBehavior> Widget for InputLine<T> {
    fn input(&mut self, input: &Input, key: KeyPress) -> bool {
        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.behavior.do_enter(&self.data)
            }
            BaseInputLineActions::Cancel => {
                self.behavior.do_cancel()
            }
            BaseInputLineActions::MoveLeft => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                }
            }
            BaseInputLineActions::MoveRight => {
                if self.input_pos < self.data.len() as isize {
                    self.input_pos += 1;
                }
            }
            BaseInputLineActions::Edit(ch) => {
                if ch.len_utf8() == 1 {
                    self.data.insert(self.input_pos as usize, ch as u8);
                    self.input_pos += 1;
                } else {
                    // TODO: Make it printable rather than alphanumeric
                }
            }
            BaseInputLineActions::Ctrl(ch) => {
                self.behavior.do_shortcut(ch)
            }
            BaseInputLineActions::DeleteWithMove => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                    self.data.remove(self.input_pos as usize);
                    self.behavior.do_update(&self.data);
                }
            }
        };

        self.behavior.do_update(&self.data);

        return true;
    }

    fn draw(&mut self, rb: &mut Frontend, area: Rect<isize>, has_focus: bool) {
        let prefix = self.behavior.get_prefix();

        let (style, status_msg) = match self.behavior.get_status() {
            Ok(sm) => (Style::InputLine, sm),
            Err(sm) => (Style::InputLineError, sm),
        };

        let (x_pos, start_index) = if area.width >= status_msg.len() as isize {
            (area.width - status_msg.len() as isize, 0)
        } else {
            (0, area.width - status_msg.len() as isize)
        };

        rb.print_style(area.left as usize, area.top as usize, style,
                 &rex_utils::string_with_repeat(' ', area.width as usize));
        rb.print_style(x_pos as usize, area.top as usize, style,
              &status_msg[start_index as usize..]);
        rb.print_style(area.left as usize, area.top as usize, style,
                 &format!("{}{} ", prefix, str::from_utf8(&self.data).unwrap()));
        if has_focus {
            rb.set_cursor(prefix.len() as isize + self.input_pos, (area.top as isize));
        }
    }
}

enum RadixType {
    DecRadix,
    HexRadix,
    OctRadix,
}

signal_decl!{GotoEvent(isize)}

pub struct GotoInputLineBehavior {
    radix: RadixType,
    is_valid: bool,
    pub on_done: GotoEvent,
    pub on_cancel: Canceled,
}

impl GotoInputLineBehavior {
    pub fn new() -> GotoInputLineBehavior {
        GotoInputLineBehavior {
            radix: RadixType::DecRadix,
            is_valid: true,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_radix(&mut self, r: RadixType) {
        self.radix = r;
    }

    fn get_pos(&mut self, data: &[u8]) -> Option<isize> {
        let radix = match self.radix {
            RadixType::DecRadix => 10,
            RadixType::HexRadix => 16,
            RadixType::OctRadix => 8,
        };

        match str::from_utf8(&data) {
            Ok(gs) => isize::from_str_radix(&gs, radix).ok(),
            Err(_) => None
        }
    }

    fn do_goto(&mut self, data: &[u8]) {
        match self.get_pos(data) {
            Some(pos) => {
                self.on_done.signal(pos)
            }
            None => {
                self.on_cancel.signal(Some(format!("Bad position!")));
            }
        };
    }
}

impl InputLineBehavior for GotoInputLineBehavior {
    fn get_prefix(&self) -> &str {
        match self.radix {
            RadixType::DecRadix => "Goto (Dec):",
            RadixType::HexRadix => "Goto (Hex):",
            RadixType::OctRadix => "Goto (Oct):",
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if self.is_valid {
            Ok("")
        } else {
            Err("Invalid position")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.is_valid = self.get_pos(data).is_some();
    }

    fn do_enter(&mut self, data: &[u8]) {
        if self.is_valid {
            self.do_goto(data);
        }
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'd' => {
                self.set_radix(RadixType::DecRadix);
            }
            'h' => {
                self.set_radix(RadixType::HexRadix);
            }
            'o' => {
                self.set_radix(RadixType::OctRadix);
            }
            _ => ()
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum DataType {
    AsciiStr,
    UnicodeStr,
    HexStr,
}

signal_decl!{FindEvent(Vec<u8>)}

pub struct FindInputLine {
    data_type: DataType,
    is_valid: bool,
    pub on_find: FindEvent,
    pub on_cancel: Canceled,
}

impl FindInputLine {
    pub fn new() -> FindInputLine {
        FindInputLine {
            data_type: DataType::AsciiStr,
            is_valid: true,
            on_find: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_search_data_type(&mut self, dt: DataType) {
        self.data_type = dt;
    }

    fn parse_hex(&self, data: &[u8]) -> Option<Vec<u8>> {
        str::from_utf8(data).unwrap().from_hex().ok()
    }

    fn do_find(&mut self, data: &[u8]) {
        let ll = self.parse_hex(data);

        let needle: Vec<u8> = match self.data_type {
            DataType::AsciiStr => data.clone().into(),
            DataType::UnicodeStr => data.clone().into(),
            DataType::HexStr => {
                match ll {
                    Some(n) => n,
                    None => {
                        self.on_cancel.signal(Some(format!("Bad hex value")));
                        return;
                    }
                }
            }
        };

        self.on_find.signal(needle);
    }
}

impl InputLineBehavior for FindInputLine {
    fn get_prefix(&self) -> &str {
        match self.data_type {
            DataType::AsciiStr => "Find(Ascii): ",
            DataType::UnicodeStr => "Find(Uni): ",
            DataType::HexStr => "Find(Hex): ",
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if self.is_valid {
            Ok("")
        } else {
            Err("Invalid Hex Value")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.is_valid = (self.data_type != DataType::HexStr) || self.parse_hex(data).is_some();
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.do_find(data);
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'a' => {
                self.set_search_data_type(DataType::AsciiStr);
            }
            'u' => {
                self.set_search_data_type(DataType::UnicodeStr);
            }
            'h' => {
                self.set_search_data_type(DataType::HexStr);
            }
            _ => ()
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum PathInputType {
    Open,
    Save
}

signal_decl!{PathEvent(PathBuf)}

pub struct PathInputLine<FS: Filesystem> {
    pub on_done: PathEvent,
    pub on_cancel: Canceled,
    input_type: PathInputType,
    res: Option<String>,

    _fs: PhantomData<FS>
}

impl<FS: Filesystem> PathInputLine<FS> {
    pub fn new(input_type: PathInputType) -> PathInputLine<FS> {
        PathInputLine {
            input_type: input_type,
            on_done: Default::default(),
            on_cancel: Default::default(),
            res: None,

            _fs: PhantomData,
        }
    }
}

impl<FS: Filesystem> InputLineBehavior for PathInputLine<FS> {
    fn get_prefix(&self) -> &str {
        if self.input_type == PathInputType::Open {
            "Open: "
        } else {
            "Save: "
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if let Some(ref s) = self.res {
            Err(s)
        } else {
            Ok("")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.res = if self.input_type == PathInputType::Open {
            FS::can_open(Path::new(str::from_utf8(data).unwrap())).err().map(|e| format!("{}", e))
        } else {
            FS::can_save(Path::new(str::from_utf8(data).unwrap())).err().map(|e| format!("{}", e))
        }
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(PathBuf::from(str::from_utf8(data).unwrap()));
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}

signal_decl!{ConfigSetEvent(String)}

pub struct ConfigSetLine {
    pub on_done: ConfigSetEvent,
    pub on_cancel: Canceled,
    prefix: String,
}

impl ConfigSetLine {
    pub fn new(prefix: String, value: Value) -> ConfigSetLine {
        ConfigSetLine {
            prefix: prefix,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }
}

impl InputLineBehavior for ConfigSetLine {
    fn get_prefix(&self) -> &str {
        &self.prefix
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(str::from_utf8(&data).unwrap().to_owned());
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}
<|endoftext|>


<commit_before>use wpilib::wpilib_hal;

pub trait Robot: Sized {
    fn run(self);

    fn new() -> Self;
}

#[macro_export]
macro_rules! start_robot_class {
    ($robot_class:ident) => {
        fn main() {
            unsafe {
                let status = wpilib_hal::HAL_Initialize(0);
                if status != 0 {
                    panic!("WPILib HAL failed to initialize with error {}", status);
                }
                // Report the language as something other than the supported ones
                wpilib_hal::HAL_Report(2, 6, 0, std::ptr::null());
                let robot = $robot_class::new();
                robot.run();
            }
        }
    }
}
<commit_msg>Fix initialization sequence<commit_after>use wpilib::wpilib_hal::*;
use std::ffi;

pub trait Robot: Sized {
    fn run(self);

    fn new() -> Self;

    fn main() {
        // Initialize HAL
        unsafe {
            let status = HAL_Initialize(0);
            if status != 1 {
                panic!("WPILib HAL failed to initialize!");
            }
        }
        let robot = Self::new();
        robot.run();
    }
}
<|endoftext|>


<commit_before>use wpilib::wpilib_hal::*;
use std::ffi;

pub trait Robot: Sized {
    fn run(self);

    fn new() -> Self;

    fn main() {
        // Initialize HAL
        unsafe {
            let status = HAL_Initialize(0);
            if status != 1 {
                panic!("WPILib HAL failed to initialize!");
            }
        }
        let robot = Self::new();
        robot.run();
    }
}
<commit_msg>Fix unused use in robot base<commit_after>use wpilib::wpilib_hal::*;

pub trait Robot: Sized {
    fn run(self);

    fn new() -> Self;

    fn main() {
        // Initialize HAL
        unsafe {
            let status = HAL_Initialize(0);
            if status != 1 {
                panic!("WPILib HAL failed to initialize!");
            }
        }
        let robot = Self::new();
        robot.run();
    }
}
<|endoftext|>


<commit_before>//! Initialization of the signed distance function near the level set.
use super::min;
use std;

/// Computes the signed distance function from a plane given as the _zero_ level set of a
/// linear function on a tetrahedron at 4 points with unit coordinates starting at (0, 0, 0) and
/// ending at (1, 1, 1), and in between exactly one coordinate changes from 0 to 1.
///
/// Inputs are `u`, the values at the vertices.
///
/// The function returns the values of the (non-signed) distance function or `None` if the zero
/// level set does not pass through the tetrahedron.
pub fn tetrahedron_dist<F>(mut u: [f64; 4], mut dual_norm: F, perm: [usize; 3]) -> Option<[f64; 4]>
where
    F: FnMut([f64; 3]) -> f64,
{
    let mut n_pos = 0;
    let mut n_neg = 0;
    for u in &mut u {
        if *u > 0. {
            n_pos += 1;
        } else if *u < 0. {
            n_neg += 1;
        }
    }
    // check if sign differs (level set goes throught the triangle)
    if n_neg == 4 || n_pos == 4 {
        return None;
    }

    // everything is zero
    if n_neg + n_pos == 0 {
        return Some([0.; 4]);
    }

    let g = [u[1] - u[0], u[2] - u[1], u[3] - u[2]];
    let g = [g[perm[0]], g[perm[1]], g[perm[2]]];
    let g_norm_rcp = 1. / dual_norm(g);

    // FIXME: this requires for norm to be even
    // Support triangular anisotropies?
    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)
}

/// Initializes the distance around the free boundary.
///
/// Based on the level set function with values `u` given on a regular grid, it computes the
/// distance from the _zero_ level set in the nodes of the triangles through which the level set
/// passes.  Stores the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every cube into six tetrahedra and computes the distance on each of them.
pub fn init_dist_3d<F>(d: &mut [f64], u: &[f64], dim: (usize, usize, usize), mut dual_norm: F)
where
    F: FnMut([f64; 3]) -> f64,
{
    let (ni, nj, nk) = dim;
    assert_eq!(ni * nj * nk, u.len());
    assert_eq!(ni * nj * nk, d.len());
    let (si, sj, _sk) = (nj * nk, nk, 1);

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    macro_rules! tetra {
        ($s:expr, [$v0:expr, $v1:expr, $v2:expr, $v3:expr], $perm:expr) => {
            let (s0, s1, s2, s3) = (
                $s - $v0.0 * si - $v0.1 * sj - $v0.2,
                $s - $v1.0 * si - $v1.1 * sj - $v1.2,
                $s - $v2.0 * si - $v2.1 * sj - $v2.2,
                $s - $v3.0 * si - $v3.1 * sj - $v3.2,
            );
            let v = [u[s0], u[s1], u[s2], u[s3]];

            let r = tetrahedron_dist(v, &mut dual_norm, $perm);

            if let Some(r) = r {
                d[s0] = min(d[s0], r[0]);
                d[s1] = min(d[s1], r[1]);
                d[s2] = min(d[s2], r[2]);
                d[s3] = min(d[s3], r[3]);
            }
        };
    }

    for i in 1..ni {
        for j in 1..nj {
            let s = i * si + j * sj;
            let v = [u[s], u[s - si], u[s - sj], u[s - si - sj]];
            let mut all_pos_prev = v.iter().all(|&v| v > 0.);
            let mut all_neg_prev = v.iter().all(|&v| v < 0.);
            for k in 1..nk {
                let s = i * si + j * sj + k;
                let v = [u[s], u[s - si], u[s - sj], u[s - si - sj]];
                let mut all_pos = v.iter().all(|&v| v > 0.);
                let mut all_neg = v[0] < 0. && v[1] < 0. && v[2] < 0. && v[3] < 0.;

                if !((all_pos_prev && all_pos) || (all_neg_prev && all_neg)) {
                    tetra!(s, [(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1)], [0, 1, 2]);
                    tetra!(s, [(0, 0, 0), (1, 0, 0), (1, 0, 1), (1, 1, 1)], [0, 2, 1]);
                    tetra!(s, [(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 1, 1)], [1, 0, 2]);
                    tetra!(s, [(0, 0, 0), (0, 1, 0), (0, 1, 1), (1, 1, 1)], [2, 0, 1]);
                    tetra!(s, [(0, 0, 0), (0, 0, 1), (1, 0, 1), (1, 1, 1)], [1, 2, 0]);
                    tetra!(s, [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)], [2, 1, 0]);
                }
                all_pos_prev = all_pos;
                all_neg_prev = all_neg;
            }
        }
    }
}

/// Compute the anisotropic distance to the zero level set of a function on a axes-aligned
/// right triangle. The right angle is assumed to be at vertex 1.
///
/// `perm` specifies which leg of the triangle corresponds to the directions e₁ and e₂:
///
/// `[0, 1]`: 0-1 leg is parallel to e₁, 1-2 leg is parallel to e₂
/// `[1, 0]`: 0-1 leg is parallel to e₂, 1-2 leg is parallel to e₁
///
/// ```text
/// [0, 1]    [1, 0]
/// ------    ------
///
///     2      1--2
///    /|      | /
///   / |      |/
///  0--1      0
/// ```
///
fn triangle_dist<F>(mut u: [f64; 3], perm: [usize; 2], mut dual_norm: F) -> Option<[f64; 3]>
where
    F: FnMut([f64; 2]) -> f64,
{
    // check if sign differs (level set goes throught the triangle)
    if (u[0] > 0. && u[1] > 0. && u[2] > 0.) || (u[0] < 0. && u[1] < 0. && u[2] < 0.) {
        return None;
    }

    let g = [u[1] - u[0], u[2] - u[1]];
    let g = [g[perm[0]], g[perm[1]]];
    let norm = dual_norm(g);
    // all values are zero
    if norm == 0. {
        return Some([0., 0., 0.]);
    }
    let g_norm_rcp = 1. / norm;

    // TODO: This supports only even norms. Do we want to support triangle norms, for instance?
    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)
}

/// As `init_dist_2d`, but for general anisotropic norm.
///
/// `dual_norm` is the __dual__ norm. It must be a positively one-homogeneous function.
pub fn init_dist_2d<F>(d: &mut [f64], u: &[f64], dim: (usize, usize), mut dual_norm: F)
where
    F: FnMut([f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    assert_eq!(nx * ny, u.len());
    assert_eq!(nx * ny, d.len());

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    for j in 1..nx {
        for i in 1..ny {
            let s = j * ny + i;
            let v = [s - ny - 1, s - ny, s];
            let r = triangle_dist([u[v[0]], u[v[1]], u[v[2]]], [1, 0], &mut dual_norm);
            if let Some(e) = r {
                for i in 0..3 {
                    d[v[i]] = min(e[i], d[v[i]]);
                }
            }
            let v = [s - ny - 1, s - 1, s];
            let r = triangle_dist([u[v[0]], u[v[1]], u[v[2]]], [0, 1], &mut dual_norm);
            if let Some(e) = r {
                for i in 0..3 {
                    d[v[i]] = min(e[i], d[v[i]]);
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::norm::{DualNorm, EuclideanNorm};

    #[test]
    fn simple_triangles() {
        let eucl_triangle_dist = |v| triangle_dist(v, [0, 1], |p| EuclideanNorm.dual_norm(p));
        assert_eq!(eucl_triangle_dist([0., 0., 0.]), Some([0., 0., 0.]));
        assert_eq!(eucl_triangle_dist([1., 1., 1.]), None);
        assert_eq!(eucl_triangle_dist([-1., -1., -1.]), None);
        assert_eq!(
            eucl_triangle_dist([0., 1., 0.]),
            Some([0., 1. / (2f64).sqrt(), 0.])
        );
        assert_eq!(eucl_triangle_dist([0., -1., -1.]), Some([0., 1., 1.]));
        assert_eq!(eucl_triangle_dist([0., 1., 1.]), Some([0., 1., 1.]));
        assert_eq!(eucl_triangle_dist([1., 1., 0.]), Some([1., 1., 0.]));
        assert_eq!(eucl_triangle_dist([-1., 0., 0.]), Some([1., 0., 0.]));
        assert_eq!(
            eucl_triangle_dist([1., 0., 1.]),
            Some([1. / (2f64).sqrt(), 0., 1. / (2f64).sqrt()])
        );
    }

    #[test]
    fn anisotropic_norm_2d() {
        // Du = (1, 0)
        let u = [0., 0., 1., 1.];
        let mut d = [0.; 4];
        init_dist_2d(&mut d, &u, (2, 2), |p| p[0].abs().max(2. * p[1].abs()));

        assert_eq!(d, [0., 0., 1., 1.]);

        // Du = (0, 1)
        let u = [0., 1., 0., 1.];
        let mut d = [0.; 4];
        init_dist_2d(&mut d, &u, (2, 2), |p| p[0].abs().max(2. * p[1].abs()));

        assert_eq!(d, [0., 0.5, 0., 0.5]);
    }

    #[test]
    fn anisotropic_norm_3d() {
        // Du = (1, 0, 0)
        let u = [0., 0., 0., 0., 1., 1., 1., 1.];
        let mut d = [0.; 8];
        init_dist_3d(&mut d, &u, (2, 2, 2), |p| {
            p[0].abs().max(2. * p[1].abs()).max(4. * p[2].abs())
        });

        assert_eq!(d, [0., 0., 0., 0., 1., 1., 1., 1.]);

        // Du = (0, 1, 0)
        let u = [0., 0., 1., 1., 0., 0., 1., 1.];
        let mut d = [0.; 8];
        init_dist_3d(&mut d, &u, (2, 2, 2), |p| {
            p[0].abs().max(2. * p[1].abs()).max(4. * p[2].abs())
        });

        assert_eq!(d, [0., 0., 0.5, 0.5, 0., 0., 0.5, 0.5]);

        // Du = (0, 0, 1)
        let u = [0., 1., 0., 1., 0., 1., 0., 1.];
        let mut d = [0.; 8];
        init_dist_3d(&mut d, &u, (2, 2, 2), |p| {
            p[0].abs().max(2. * p[1].abs()).max(4. * p[2].abs())
        });

        assert_eq!(d, [0., 0.25, 0., 0.25, 0., 0.25, 0., 0.25]);
    }
}
<commit_msg>Streamline the macro<commit_after>//! Initialization of the signed distance function near the level set.
use super::min;
use std;

/// Computes the signed distance function from a plane given as the _zero_ level set of a linear
/// function on a tetrahedron with 4 vertices with unit coordinates starting at (0, 0, 0) and
/// ending at (1, 1, 1), and in between exactly one coordinate changes from 0 to 1.
///
/// Inputs are `u`, the values at the vertices.
///
/// `perm[a]` specifies on which step the coordinate `a` changes. For example, the first coordinate
/// changes from vertex `perm[0]` to vertex `perm[0] + 1`.
///
/// The function returns the values of the (non-signed) distance function or `None` if the zero
/// level set does not pass through the tetrahedron.
pub fn tetrahedron_dist<F>(mut u: [f64; 4], mut dual_norm: F, perm: [usize; 3]) -> Option<[f64; 4]>
where
    F: FnMut([f64; 3]) -> f64,
{
    let mut n_pos = 0;
    let mut n_neg = 0;
    for u in &mut u {
        if *u > 0. {
            n_pos += 1;
        } else if *u < 0. {
            n_neg += 1;
        }
    }
    // check if sign differs (level set goes throught the triangle)
    if n_neg == 4 || n_pos == 4 {
        return None;
    }

    // everything is zero
    if n_neg + n_pos == 0 {
        return Some([0.; 4]);
    }

    let g = [u[1] - u[0], u[2] - u[1], u[3] - u[2]];
    let g = [g[perm[0]], g[perm[1]], g[perm[2]]];
    let g_norm_rcp = 1. / dual_norm(g);

    // FIXME: this requires for norm to be even
    // Support triangular anisotropies?
    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)
}

/// Initializes the distance around the free boundary.
///
/// Based on the level set function with values `u` given on a regular grid, it computes the
/// distance from the _zero_ level set in the nodes of the triangles through which the level set
/// passes.  Stores the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every cube into six tetrahedra and computes the distance on each of them.
pub fn init_dist_3d<F>(d: &mut [f64], u: &[f64], dim: (usize, usize, usize), mut dual_norm: F)
where
    F: FnMut([f64; 3]) -> f64,
{
    let (ni, nj, nk) = dim;
    assert_eq!(ni * nj * nk, u.len());
    assert_eq!(ni * nj * nk, d.len());
    let (si, sj, sk) = (nj * nk, nk, 1);

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    macro_rules! tetra {
        ($s:expr, [$pi:expr, $pj:expr, $pk:expr]) => {
            // $pi specifies at which step the i-th coordinate changes, etc.
            let offset = |step|
                            if $pi == step { si } else { 0 } +
                            if $pj == step { sj } else { 0 } +
                            if $pk == step { sk } else { 0 };

            let s0 = $s;
            let s1 = s0 - offset(0);
            let s2 = s1 - offset(1);
            let s3 = s2 - offset(2);
            let v = [u[s0], u[s1], u[s2], u[s3]];

            let r = tetrahedron_dist(v, &mut dual_norm, [$pi, $pj, $pk]);

            if let Some(r) = r {
                d[s0] = min(d[s0], r[0]);
                d[s1] = min(d[s1], r[1]);
                d[s2] = min(d[s2], r[2]);
                d[s3] = min(d[s3], r[3]);
            }
        };
    }

    for i in 1..ni {
        for j in 1..nj {
            let s = i * si + j * sj;
            let v = [u[s], u[s - si], u[s - sj], u[s - si - sj]];
            let mut all_pos_prev = v.iter().all(|&v| v > 0.);
            let mut all_neg_prev = v.iter().all(|&v| v < 0.);
            for k in 1..nk {
                let s = i * si + j * sj + k;
                let v = [u[s], u[s - si], u[s - sj], u[s - si - sj]];
                let mut all_pos = v.iter().all(|&v| v > 0.);
                let mut all_neg = v[0] < 0. && v[1] < 0. && v[2] < 0. && v[3] < 0.;

                if !((all_pos_prev && all_pos) || (all_neg_prev && all_neg)) {
                    tetra!(s, [0, 1, 2]);
                    tetra!(s, [0, 2, 1]);
                    tetra!(s, [1, 0, 2]);
                    tetra!(s, [2, 0, 1]);
                    tetra!(s, [1, 2, 0]);
                    tetra!(s, [2, 1, 0]);
                }
                all_pos_prev = all_pos;
                all_neg_prev = all_neg;
            }
        }
    }
}

/// Compute the anisotropic distance to the zero level set of a function on a axes-aligned
/// right triangle. The right angle is assumed to be at vertex 1.
///
/// `perm` specifies which leg of the triangle corresponds to the directions e₁ and e₂:
///
/// `[0, 1]`: 0-1 leg is parallel to e₁, 1-2 leg is parallel to e₂
/// `[1, 0]`: 0-1 leg is parallel to e₂, 1-2 leg is parallel to e₁
///
/// ```text
/// [0, 1]    [1, 0]
/// ------    ------
///
///     2      1--2
///    /|      | /
///   / |      |/
///  0--1      0
/// ```
///
fn triangle_dist<F>(mut u: [f64; 3], perm: [usize; 2], mut dual_norm: F) -> Option<[f64; 3]>
where
    F: FnMut([f64; 2]) -> f64,
{
    // check if sign differs (level set goes throught the triangle)
    if (u[0] > 0. && u[1] > 0. && u[2] > 0.) || (u[0] < 0. && u[1] < 0. && u[2] < 0.) {
        return None;
    }

    let g = [u[1] - u[0], u[2] - u[1]];
    let g = [g[perm[0]], g[perm[1]]];
    let norm = dual_norm(g);
    // all values are zero
    if norm == 0. {
        return Some([0., 0., 0.]);
    }
    let g_norm_rcp = 1. / norm;

    // TODO: This supports only even norms. Do we want to support triangle norms, for instance?
    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)
}

/// As `init_dist_2d`, but for general anisotropic norm.
///
/// `dual_norm` is the __dual__ norm. It must be a positively one-homogeneous function.
pub fn init_dist_2d<F>(d: &mut [f64], u: &[f64], dim: (usize, usize), mut dual_norm: F)
where
    F: FnMut([f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    assert_eq!(nx * ny, u.len());
    assert_eq!(nx * ny, d.len());

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    for j in 1..nx {
        for i in 1..ny {
            let s = j * ny + i;
            let v = [s - ny - 1, s - ny, s];
            let r = triangle_dist([u[v[0]], u[v[1]], u[v[2]]], [1, 0], &mut dual_norm);
            if let Some(e) = r {
                for i in 0..3 {
                    d[v[i]] = min(e[i], d[v[i]]);
                }
            }
            let v = [s - ny - 1, s - 1, s];
            let r = triangle_dist([u[v[0]], u[v[1]], u[v[2]]], [0, 1], &mut dual_norm);
            if let Some(e) = r {
                for i in 0..3 {
                    d[v[i]] = min(e[i], d[v[i]]);
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::norm::{DualNorm, EuclideanNorm};

    #[test]
    fn simple_triangles() {
        let eucl_triangle_dist = |v| triangle_dist(v, [0, 1], |p| EuclideanNorm.dual_norm(p));
        assert_eq!(eucl_triangle_dist([0., 0., 0.]), Some([0., 0., 0.]));
        assert_eq!(eucl_triangle_dist([1., 1., 1.]), None);
        assert_eq!(eucl_triangle_dist([-1., -1., -1.]), None);
        assert_eq!(
            eucl_triangle_dist([0., 1., 0.]),
            Some([0., 1. / (2f64).sqrt(), 0.])
        );
        assert_eq!(eucl_triangle_dist([0., -1., -1.]), Some([0., 1., 1.]));
        assert_eq!(eucl_triangle_dist([0., 1., 1.]), Some([0., 1., 1.]));
        assert_eq!(eucl_triangle_dist([1., 1., 0.]), Some([1., 1., 0.]));
        assert_eq!(eucl_triangle_dist([-1., 0., 0.]), Some([1., 0., 0.]));
        assert_eq!(
            eucl_triangle_dist([1., 0., 1.]),
            Some([1. / (2f64).sqrt(), 0., 1. / (2f64).sqrt()])
        );
    }

    #[test]
    fn anisotropic_norm_2d() {
        // Du = (1, 0)
        let u = [0., 0., 1., 1.];
        let mut d = [0.; 4];
        init_dist_2d(&mut d, &u, (2, 2), |p| p[0].abs().max(2. * p[1].abs()));

        assert_eq!(d, [0., 0., 1., 1.]);

        // Du = (0, 1)
        let u = [0., 1., 0., 1.];
        let mut d = [0.; 4];
        init_dist_2d(&mut d, &u, (2, 2), |p| p[0].abs().max(2. * p[1].abs()));

        assert_eq!(d, [0., 0.5, 0., 0.5]);
    }

    #[test]
    fn anisotropic_norm_3d() {
        // Du = (1, 0, 0)
        let u = [0., 0., 0., 0., 1., 1., 1., 1.];
        let mut d = [0.; 8];
        init_dist_3d(&mut d, &u, (2, 2, 2), |p| {
            p[0].abs().max(2. * p[1].abs()).max(4. * p[2].abs())
        });

        assert_eq!(d, [0., 0., 0., 0., 1., 1., 1., 1.]);

        // Du = (0, 1, 0)
        let u = [0., 0., 1., 1., 0., 0., 1., 1.];
        let mut d = [0.; 8];
        init_dist_3d(&mut d, &u, (2, 2, 2), |p| {
            p[0].abs().max(2. * p[1].abs()).max(4. * p[2].abs())
        });

        assert_eq!(d, [0., 0., 0.5, 0.5, 0., 0., 0.5, 0.5]);

        // Du = (0, 0, 1)
        let u = [0., 1., 0., 1., 0., 1., 0., 1.];
        let mut d = [0.; 8];
        init_dist_3d(&mut d, &u, (2, 2, 2), |p| {
            p[0].abs().max(2. * p[1].abs()).max(4. * p[2].abs())
        });

        assert_eq!(d, [0., 0.25, 0., 0.25, 0., 0.25, 0., 0.25]);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::error::Error;
use std::fmt;

pub type ProtobufResult<T> = Result<T, ProtobufError>;

#[derive(Debug)]
pub enum ProtobufError {
    IoError(io::Error),
    WireError(String),
    MessageNotInitialized { message: &'static str },
}

impl ProtobufError {
    pub fn message_not_initialized(message: &'static str) -> ProtobufError {
        ProtobufError::MessageNotInitialized {
            message: message
        }
    }
}

impl fmt::Display for ProtobufError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl Error for ProtobufError {
    fn description(&self) -> &str {
        match self {
            // not sure that cause should be included in message
            &ProtobufError::IoError(ref e) => e.description(),
            &ProtobufError::WireError(ref e) => &e,
            &ProtobufError::MessageNotInitialized { .. } => "not all message fields set",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ProtobufError::IoError(ref e) => Some(e),
            &ProtobufError::WireError(..) => None,
            &ProtobufError::MessageNotInitialized { .. } => None,
        }
    }
}
<commit_msg>Implement From<io::Error> for ProtobufError<commit_after>use std::io;
use std::error::Error;
use std::fmt;

pub type ProtobufResult<T> = Result<T, ProtobufError>;

#[derive(Debug)]
pub enum ProtobufError {
    IoError(io::Error),
    WireError(String),
    MessageNotInitialized { message: &'static str },
}

impl ProtobufError {
    pub fn message_not_initialized(message: &'static str) -> ProtobufError {
        ProtobufError::MessageNotInitialized {
            message: message
        }
    }
}

impl fmt::Display for ProtobufError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl Error for ProtobufError {
    fn description(&self) -> &str {
        match self {
            // not sure that cause should be included in message
            &ProtobufError::IoError(ref e) => e.description(),
            &ProtobufError::WireError(ref e) => &e,
            &ProtobufError::MessageNotInitialized { .. } => "not all message fields set",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ProtobufError::IoError(ref e) => Some(e),
            &ProtobufError::WireError(..) => None,
            &ProtobufError::MessageNotInitialized { .. } => None,
        }
    }
}

impl From<io::Error> for ProtobufError {
    fn from(err: io::Error) -> Self {
        ProtobufError::IoError(err)
    }
}
<|endoftext|>


<commit_before>//! Utility functions for Header implementations.

use language_tags::LanguageTag;
use std::str;
use std::str::FromStr;
use std::fmt::{self, Display};
use url::percent_encoding;

use header::Raw;
use header::shared::Charset;

/// Reads a single raw string when parsing a header.
pub fn from_one_raw_str<T: str::FromStr>(raw: &Raw) -> ::Result<T> {
    if let Some(line) = raw.one() {
        if !line.is_empty() {
            return from_raw_str(line)
        }
    }
    Err(::Error::Header)
}

/// Reads a raw string into a value.
pub fn from_raw_str<T: str::FromStr>(raw: &[u8]) -> ::Result<T> {
    let s = try!(str::from_utf8(raw)).trim();
    T::from_str(s).or(Err(::Error::Header))
}

/// Reads a comma-delimited raw header into a Vec.
#[inline]
pub fn from_comma_delimited<T: str::FromStr>(raw: &Raw) -> ::Result<Vec<T>> {
    let mut result = Vec::new();
    for s in raw {
        let s = try!(str::from_utf8(s.as_ref()));
        result.extend(s.split(',')
                      .filter_map(|x| match x.trim() {
                          "" => None,
                          y => Some(y)
                      })
                      .filter_map(|x| x.trim().parse().ok()))
    }
    Ok(result)
}

/// Format an array into a comma-delimited string.
pub fn fmt_comma_delimited<T: Display>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result {
    for (i, part) in parts.iter().enumerate() {
        if i != 0 {
            try!(f.write_str(", "));
        }
        try!(Display::fmt(part, f));
    }
    Ok(())
}

/// An extended header parameter value (i.e., tagged with a character set and optionally,
/// a language), as defined in [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2).
#[derive(Clone, Debug, PartialEq)]
pub struct ExtendedValue {
    /// The character set that is used to encode the `value` to a string.
    pub charset: Charset,
    /// The human language details of the `value`, if available.
    pub language_tag: Option<LanguageTag>,
    /// The parameter value, as expressed in octets.
    pub value: Vec<u8>,
}

/// Parses extended header parameter values (`ext-value`), as defined in
/// [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2).
///
/// Extended values are denoted by parameter names that end with `*`.
///
/// ## ABNF
/// ```plain
/// ext-value     = charset  "'" [ language ] "'" value-chars
///               ; like RFC 2231's <extended-initial-value>
///               ; (see [RFC2231], Section 7)
///
/// charset       = "UTF-8" / "ISO-8859-1" / mime-charset
///
/// mime-charset  = 1*mime-charsetc
/// mime-charsetc = ALPHA / DIGIT
///               / "!" / "#" / "$" / "%" / "&"
///               / "+" / "-" / "^" / "_" / "`"
///               / "{" / "}" / "~"
///               ; as <mime-charset> in Section 2.3 of [RFC2978]
///               ; except that the single quote is not included
///               ; SHOULD be registered in the IANA charset registry
///
/// language      = <Language-Tag, defined in [RFC5646], Section 2.1>
///
/// value-chars   = *( pct-encoded / attr-char )
///
/// pct-encoded   = "%" HEXDIG HEXDIG
///               ; see [RFC3986], Section 2.1
///
/// attr-char     = ALPHA / DIGIT
///               / "!" / "#" / "$" / "&" / "+" / "-" / "."
///               / "^" / "_" / "`" / "|" / "~"
///               ; token except ( "*" / "'" / "%" )
/// ```
pub fn parse_extended_value(val: &str) -> ::Result<ExtendedValue> {

    // Break into three pieces separated by the single-quote character
    let mut parts = val.splitn(3,'\'');

    // Interpret the first piece as a Charset
    let charset: Charset = match parts.next() {
        None => return Err(::Error::Header),
        Some(n) => try!(FromStr::from_str(n)),
    };

    // Interpret the second piece as a language tag
    let lang: Option<LanguageTag> = match parts.next() {
        None => return Err(::Error::Header),
        Some("") => None,
        Some(s) => match s.parse() {
            Ok(lt) => Some(lt),
            Err(_) => return Err(::Error::Header),
        }
    };

    // Interpret the third piece as a sequence of value characters
    let value: Vec<u8> = match parts.next() {
        None => return Err(::Error::Header),
        Some(v) => percent_encoding::percent_decode(v.as_bytes()).collect(),
    };

    Ok(ExtendedValue {
        charset: charset,
        language_tag: lang,
        value: value,
    })
}

impl Display for ExtendedValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let encoded_value =
            percent_encoding::percent_encode(&self.value[..], self::percent_encoding_http::HTTP_VALUE);
        if let Some(ref lang) = self.language_tag {
            write!(f, "{}'{}'{}", self.charset, lang, encoded_value)
        } else {
            write!(f, "{}''{}", self.charset, encoded_value)
        }
    }
}

/// Percent encode a sequence of bytes with a character set defined in
/// https://tools.ietf.org/html/rfc5987#section-3.2
pub fn http_percent_encode(f: &mut fmt::Formatter, bytes: &[u8]) -> fmt::Result {
    let encoded = percent_encoding::percent_encode(bytes, self::percent_encoding_http::HTTP_VALUE);
    fmt::Display::fmt(&encoded, f)
}

mod percent_encoding_http {
    use std::fmt;
    use url::percent_encoding;

    define_encode_set! {
        /// This encode set is used for HTTP header values and is defined at
        /// https://tools.ietf.org/html/rfc5987#section-3.2
        pub HTTP_VALUE = [percent_encoding::SIMPLE_ENCODE_SET] | {
            ' ', '"', '%', '\'', '(', ')', '*', ',', '/', ':', ';', '<', '-', '>', '?',
            '[', '\\', ']', '{', '}'
        }
    }

    impl fmt::Debug for HTTP_VALUE {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            f.pad("HTTP_VALUE")
        }
    }
}

#[cfg(test)]
mod tests {
    use header::shared::Charset;
    use super::{ExtendedValue, parse_extended_value};
    use language_tags::LanguageTag;

    #[test]
    fn test_parse_extended_value_with_encoding_and_language_tag() {
        let expected_language_tag = "en".parse::<LanguageTag>().unwrap();
        // RFC 5987, Section 3.2.2
        // Extended notation, using the Unicode character U+00A3 (POUND SIGN)
        let result = parse_extended_value("iso-8859-1'en'%A3%20rates");
        assert!(result.is_ok());
        let extended_value = result.unwrap();
        assert_eq!(Charset::Iso_8859_1, extended_value.charset);
        assert!(extended_value.language_tag.is_some());
        assert_eq!(expected_language_tag, extended_value.language_tag.unwrap());
        assert_eq!(vec![163, b' ', b'r', b'a', b't', b'e', b's'], extended_value.value);
    }

    #[test]
    fn test_parse_extended_value_with_encoding() {
        // RFC 5987, Section 3.2.2
        // Extended notation, using the Unicode characters U+00A3 (POUND SIGN)
        // and U+20AC (EURO SIGN)
        let result = parse_extended_value("UTF-8''%c2%a3%20and%20%e2%82%ac%20rates");
        assert!(result.is_ok());
        let extended_value = result.unwrap();
        assert_eq!(Charset::Ext("UTF-8".to_string()), extended_value.charset);
        assert!(extended_value.language_tag.is_none());
        assert_eq!(vec![194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a', b't', b'e', b's'], extended_value.value);
    }

    #[test]
    fn test_parse_extended_value_missing_language_tag_and_encoding() {
        // From: https://greenbytes.de/tech/tc2231/#attwithfn2231quot2
        let result = parse_extended_value("foo%20bar.html");
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_extended_value_partially_formatted() {
        let result = parse_extended_value("UTF-8'missing third part");
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_extended_value_partially_formatted_blank() {
        let result = parse_extended_value("blank second part'");
        assert!(result.is_err());
    }

    #[test]
    fn test_fmt_extended_value_with_encoding_and_language_tag() {
        let extended_value = ExtendedValue {
            charset: Charset::Iso_8859_1,
            language_tag: Some("en".parse().expect("Could not parse language tag")),
            value: vec![163, b' ', b'r', b'a', b't', b'e', b's'],
        };
        assert_eq!("ISO-8859-1'en'%A3%20rates", format!("{}", extended_value));
    }

    #[test]
    fn test_fmt_extended_value_with_encoding() {
        let extended_value = ExtendedValue {
            charset: Charset::Ext("UTF-8".to_string()),
            language_tag: None,
            value: vec![194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a',
                        b't', b'e', b's'],
        };
        assert_eq!("UTF-8''%C2%A3%20and%20%E2%82%AC%20rates",
                   format!("{}", extended_value));
    }
}
<commit_msg>perf(header): move a branch out of a loop in fmt_comma_delimited<commit_after>//! Utility functions for Header implementations.

use language_tags::LanguageTag;
use std::str;
use std::str::FromStr;
use std::fmt::{self, Display};
use url::percent_encoding;

use header::Raw;
use header::shared::Charset;

/// Reads a single raw string when parsing a header.
pub fn from_one_raw_str<T: str::FromStr>(raw: &Raw) -> ::Result<T> {
    if let Some(line) = raw.one() {
        if !line.is_empty() {
            return from_raw_str(line)
        }
    }
    Err(::Error::Header)
}

/// Reads a raw string into a value.
pub fn from_raw_str<T: str::FromStr>(raw: &[u8]) -> ::Result<T> {
    let s = try!(str::from_utf8(raw)).trim();
    T::from_str(s).or(Err(::Error::Header))
}

/// Reads a comma-delimited raw header into a Vec.
#[inline]
pub fn from_comma_delimited<T: str::FromStr>(raw: &Raw) -> ::Result<Vec<T>> {
    let mut result = Vec::new();
    for s in raw {
        let s = try!(str::from_utf8(s.as_ref()));
        result.extend(s.split(',')
                      .filter_map(|x| match x.trim() {
                          "" => None,
                          y => Some(y)
                      })
                      .filter_map(|x| x.trim().parse().ok()))
    }
    Ok(result)
}

/// Format an array into a comma-delimited string.
pub fn fmt_comma_delimited<T: Display>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result {
    let mut iter = parts.iter();
    if let Some(part) = iter.next() {
        try!(Display::fmt(part, f));
    }
    for part in iter {
        try!(f.write_str(", "));
        try!(Display::fmt(part, f));
    }
    Ok(())
}

/// An extended header parameter value (i.e., tagged with a character set and optionally,
/// a language), as defined in [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2).
#[derive(Clone, Debug, PartialEq)]
pub struct ExtendedValue {
    /// The character set that is used to encode the `value` to a string.
    pub charset: Charset,
    /// The human language details of the `value`, if available.
    pub language_tag: Option<LanguageTag>,
    /// The parameter value, as expressed in octets.
    pub value: Vec<u8>,
}

/// Parses extended header parameter values (`ext-value`), as defined in
/// [RFC 5987](https://tools.ietf.org/html/rfc5987#section-3.2).
///
/// Extended values are denoted by parameter names that end with `*`.
///
/// ## ABNF
/// ```plain
/// ext-value     = charset  "'" [ language ] "'" value-chars
///               ; like RFC 2231's <extended-initial-value>
///               ; (see [RFC2231], Section 7)
///
/// charset       = "UTF-8" / "ISO-8859-1" / mime-charset
///
/// mime-charset  = 1*mime-charsetc
/// mime-charsetc = ALPHA / DIGIT
///               / "!" / "#" / "$" / "%" / "&"
///               / "+" / "-" / "^" / "_" / "`"
///               / "{" / "}" / "~"
///               ; as <mime-charset> in Section 2.3 of [RFC2978]
///               ; except that the single quote is not included
///               ; SHOULD be registered in the IANA charset registry
///
/// language      = <Language-Tag, defined in [RFC5646], Section 2.1>
///
/// value-chars   = *( pct-encoded / attr-char )
///
/// pct-encoded   = "%" HEXDIG HEXDIG
///               ; see [RFC3986], Section 2.1
///
/// attr-char     = ALPHA / DIGIT
///               / "!" / "#" / "$" / "&" / "+" / "-" / "."
///               / "^" / "_" / "`" / "|" / "~"
///               ; token except ( "*" / "'" / "%" )
/// ```
pub fn parse_extended_value(val: &str) -> ::Result<ExtendedValue> {

    // Break into three pieces separated by the single-quote character
    let mut parts = val.splitn(3,'\'');

    // Interpret the first piece as a Charset
    let charset: Charset = match parts.next() {
        None => return Err(::Error::Header),
        Some(n) => try!(FromStr::from_str(n)),
    };

    // Interpret the second piece as a language tag
    let lang: Option<LanguageTag> = match parts.next() {
        None => return Err(::Error::Header),
        Some("") => None,
        Some(s) => match s.parse() {
            Ok(lt) => Some(lt),
            Err(_) => return Err(::Error::Header),
        }
    };

    // Interpret the third piece as a sequence of value characters
    let value: Vec<u8> = match parts.next() {
        None => return Err(::Error::Header),
        Some(v) => percent_encoding::percent_decode(v.as_bytes()).collect(),
    };

    Ok(ExtendedValue {
        charset: charset,
        language_tag: lang,
        value: value,
    })
}

impl Display for ExtendedValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let encoded_value =
            percent_encoding::percent_encode(&self.value[..], self::percent_encoding_http::HTTP_VALUE);
        if let Some(ref lang) = self.language_tag {
            write!(f, "{}'{}'{}", self.charset, lang, encoded_value)
        } else {
            write!(f, "{}''{}", self.charset, encoded_value)
        }
    }
}

/// Percent encode a sequence of bytes with a character set defined in
/// https://tools.ietf.org/html/rfc5987#section-3.2
pub fn http_percent_encode(f: &mut fmt::Formatter, bytes: &[u8]) -> fmt::Result {
    let encoded = percent_encoding::percent_encode(bytes, self::percent_encoding_http::HTTP_VALUE);
    fmt::Display::fmt(&encoded, f)
}

mod percent_encoding_http {
    use std::fmt;
    use url::percent_encoding;

    define_encode_set! {
        /// This encode set is used for HTTP header values and is defined at
        /// https://tools.ietf.org/html/rfc5987#section-3.2
        pub HTTP_VALUE = [percent_encoding::SIMPLE_ENCODE_SET] | {
            ' ', '"', '%', '\'', '(', ')', '*', ',', '/', ':', ';', '<', '-', '>', '?',
            '[', '\\', ']', '{', '}'
        }
    }

    impl fmt::Debug for HTTP_VALUE {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            f.pad("HTTP_VALUE")
        }
    }
}

#[cfg(test)]
mod tests {
    use header::shared::Charset;
    use super::{ExtendedValue, parse_extended_value};
    use language_tags::LanguageTag;

    #[test]
    fn test_parse_extended_value_with_encoding_and_language_tag() {
        let expected_language_tag = "en".parse::<LanguageTag>().unwrap();
        // RFC 5987, Section 3.2.2
        // Extended notation, using the Unicode character U+00A3 (POUND SIGN)
        let result = parse_extended_value("iso-8859-1'en'%A3%20rates");
        assert!(result.is_ok());
        let extended_value = result.unwrap();
        assert_eq!(Charset::Iso_8859_1, extended_value.charset);
        assert!(extended_value.language_tag.is_some());
        assert_eq!(expected_language_tag, extended_value.language_tag.unwrap());
        assert_eq!(vec![163, b' ', b'r', b'a', b't', b'e', b's'], extended_value.value);
    }

    #[test]
    fn test_parse_extended_value_with_encoding() {
        // RFC 5987, Section 3.2.2
        // Extended notation, using the Unicode characters U+00A3 (POUND SIGN)
        // and U+20AC (EURO SIGN)
        let result = parse_extended_value("UTF-8''%c2%a3%20and%20%e2%82%ac%20rates");
        assert!(result.is_ok());
        let extended_value = result.unwrap();
        assert_eq!(Charset::Ext("UTF-8".to_string()), extended_value.charset);
        assert!(extended_value.language_tag.is_none());
        assert_eq!(vec![194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a', b't', b'e', b's'], extended_value.value);
    }

    #[test]
    fn test_parse_extended_value_missing_language_tag_and_encoding() {
        // From: https://greenbytes.de/tech/tc2231/#attwithfn2231quot2
        let result = parse_extended_value("foo%20bar.html");
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_extended_value_partially_formatted() {
        let result = parse_extended_value("UTF-8'missing third part");
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_extended_value_partially_formatted_blank() {
        let result = parse_extended_value("blank second part'");
        assert!(result.is_err());
    }

    #[test]
    fn test_fmt_extended_value_with_encoding_and_language_tag() {
        let extended_value = ExtendedValue {
            charset: Charset::Iso_8859_1,
            language_tag: Some("en".parse().expect("Could not parse language tag")),
            value: vec![163, b' ', b'r', b'a', b't', b'e', b's'],
        };
        assert_eq!("ISO-8859-1'en'%A3%20rates", format!("{}", extended_value));
    }

    #[test]
    fn test_fmt_extended_value_with_encoding() {
        let extended_value = ExtendedValue {
            charset: Charset::Ext("UTF-8".to_string()),
            language_tag: None,
            value: vec![194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a',
                        b't', b'e', b's'],
        };
        assert_eq!("UTF-8''%C2%A3%20and%20%E2%82%AC%20rates",
                   format!("{}", extended_value));
    }
}
<|endoftext|>