<commit_before>use cppn_ext::cppn::{Cppn, CppnNode};
use cppn_ext::position::Position;
use cppn_ext::activation_function::ActivationFunction;
use weight::Weight;
use primal_bit::BitVec;
use substrate::{Substrate, Node};

/// Calculates the behavioral bitvector for `cppn` and all possible inputs `position_pairs`.

fn behavioral_bitvec<P, AF>(cppn: &mut Cppn<CppnNode<AF>, Weight, ()>,
                            position_pairs: &[(P, P)])
                            -> BitVec
    where P: Position,
          AF: ActivationFunction
{
    let outcnt = cppn.output_count();
    assert!(outcnt > 0);
    let mut bitvec = BitVec::from_elem(outcnt * position_pairs.len(), false);
    let mut bitpos = 0;

    for &(ref position1, ref position2) in position_pairs {
        let inputs = [position1.coords(), position2.coords()];
        cppn.process(&inputs[..]);
        for outp in 0..outcnt {
            let output = cppn.read_output(outp).unwrap();
            if output >= 0.0 {
                bitvec.set(bitpos, true);
            }
            bitpos += 1;
        }
    }

    bitvec
}

pub struct BehavioralBitvec {
    bitvec: BitVec,
    bitpos: usize,
}

impl BehavioralBitvec {
    pub fn new(n: usize) -> Self {
         BehavioralBitvec {
             bitvec: BitVec::from_elem(n, false),
             bitpos: 0,
         }
    }

    #[inline]
    pub fn push(&mut self, output: f64) {
       if output >= 0.0 {
           self.bitvec.set(self.bitpos, true);
       }
       self.bitpos += 1;
    }
}

pub trait NetworkBuilderVisitor<P, T> where P: Position {
    fn add_node(&mut self, node: &Node<P, T>, param: f64);
    fn add_link(&mut self, source_node: &Node<P, T>, target_node: &Node<P, T>, weight1: f64, weight2: f64);
}

const CPPN_OUTPUT_LINK_WEIGHT1: usize = 0;
const CPPN_OUTPUT_LINK_WEIGHT2: usize = 1;
const CPPN_OUTPUT_LINK_EXPRESSION: usize = 2;
const CPPN_OUTPUT_NODE_WEIGHT: usize = 3;

/// Develops a network out of the CPPN
///
/// Returns the BehavioralBitvec and Connection Cost of the developed network
fn develop_cppn<P, AF, T, V>(cppn: &mut Cppn<CppnNode<AF>, Weight, ()>, null_position: &P, nodes: &[Node<P, T>], links: &[(&Node<P, T>, &Node<P, T>)],
    visitor: &mut V, leo_threshold: f64) -> (BehavioralBitvec, f64)
    where P: Position,
    AF: ActivationFunction,
    V: NetworkBuilderVisitor<P, T> {

    // our CPPN has four outputs: link weight 1, link weight 2, link expression output, node weight
    assert!(cppn.output_count() == 4);
    assert!(cppn.input_count() == 6);

    let mut bitvec = BehavioralBitvec::new(4 * (nodes.len() + links.len()));
    let mut connection_cost = 0.0;

    // First visit all nodes

    for node in nodes.iter() {
        let inputs = [node.position.coords(), null_position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        visitor.add_node(node, node_weight)
    }

    for &(source_node, target_node) in links.iter() {
        let inputs = [source_node.position.coords(), target_node.position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        if link_expression > leo_threshold {
            let distance_sq = source_node.position.distance_square(&target_node.position);
            debug_assert!(distance_sq >= 0.0);
            connection_cost += distance_sq;
            visitor.add_link(source_node, target_node, link_weight1, link_weight2);
        }
    }

    return (bitvec, connection_cost);
}
<commit_msg>Remove behavioral_bitvec() and reformat<commit_after>use cppn_ext::cppn::{Cppn, CppnNode};
use cppn_ext::position::Position;
use cppn_ext::activation_function::ActivationFunction;
use weight::Weight;
use primal_bit::BitVec;
use substrate::{Substrate, Node};

pub struct BehavioralBitvec {
    bitvec: BitVec,
    bitpos: usize,
}

impl BehavioralBitvec {
    pub fn new(n: usize) -> Self {
        BehavioralBitvec {
            bitvec: BitVec::from_elem(n, false),
            bitpos: 0,
        }
    }

    #[inline]
    pub fn push(&mut self, output: f64) {
        if output >= 0.0 {
            self.bitvec.set(self.bitpos, true);
        }
        self.bitpos += 1;
    }
}

pub trait NetworkBuilderVisitor<P, T> where P: Position {
    fn add_node(&mut self, node: &Node<P, T>, param: f64);
    fn add_link(&mut self,
                source_node: &Node<P, T>,
                target_node: &Node<P, T>,
                weight1: f64,
                weight2: f64);
}

const CPPN_OUTPUT_LINK_WEIGHT1: usize = 0;
const CPPN_OUTPUT_LINK_WEIGHT2: usize = 1;
const CPPN_OUTPUT_LINK_EXPRESSION: usize = 2;
const CPPN_OUTPUT_NODE_WEIGHT: usize = 3;

/// Develops a network out of the CPPN
///
/// Returns the BehavioralBitvec and Connection Cost of the developed network

fn develop_cppn<P, AF, T, V>(cppn: &mut Cppn<CppnNode<AF>, Weight, ()>,
                             null_position: &P,
                             nodes: &[Node<P, T>],
                             links: &[(&Node<P, T>, &Node<P, T>)],
                             visitor: &mut V,
                             leo_threshold: f64)
                             -> (BehavioralBitvec, f64)
    where P: Position,
          AF: ActivationFunction,
          V: NetworkBuilderVisitor<P, T>
{

    // our CPPN has four outputs: link weight 1, link weight 2, link expression output, node weight
    assert!(cppn.output_count() == 4);
    assert!(cppn.input_count() == 6);

    let mut bitvec = BehavioralBitvec::new(4 * (nodes.len() + links.len()));
    let mut connection_cost = 0.0;

    // First visit all nodes

    for node in nodes.iter() {
        let inputs = [node.position.coords(), null_position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        visitor.add_node(node, node_weight)
    }

    for &(source_node, target_node) in links.iter() {
        let inputs = [source_node.position.coords(), target_node.position.coords()];
        cppn.process(&inputs[..]);

        let link_weight1 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT1).unwrap();
        let link_weight2 = cppn.read_output(CPPN_OUTPUT_LINK_WEIGHT2).unwrap();
        let link_expression = cppn.read_output(CPPN_OUTPUT_LINK_EXPRESSION).unwrap();
        let node_weight = cppn.read_output(CPPN_OUTPUT_NODE_WEIGHT).unwrap();

        bitvec.push(link_weight1);
        bitvec.push(link_weight2);
        bitvec.push(link_expression);
        bitvec.push(node_weight);

        if link_expression > leo_threshold {
            let distance_sq = source_node.position.distance_square(&target_node.position);
            debug_assert!(distance_sq >= 0.0);
            connection_cost += distance_sq;
            visitor.add_link(source_node, target_node, link_weight1, link_weight2);
        }
    }

    return (bitvec, connection_cost);
}
<|endoftext|>


<commit_before>use humantime;
use std::fmt;
use std::result::Result as StdResult;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

/// A UTC timestamp. Used for serialization to and from the plist date type.
#[derive(Clone, Copy, Hash, PartialEq)]
pub struct Date {
    inner: SystemTime,
}

impl Date {
    pub(crate) fn from_rfc3339(date: &str) -> Result<Self, ()> {
        Ok(Date {
            inner: humantime::parse_rfc3339(date).map_err(|_| ())?,
        })
    }

    pub(crate) fn to_rfc3339(&self) -> String {
        format!("{}", humantime::format_rfc3339(self.inner))
    }

    pub(crate) fn from_seconds_since_plist_epoch(timestamp: f64) -> Result<Date, ()> {
        // `timestamp` is the number of seconds since the plist epoch of 1/1/2001 00:00:00.
        // `PLIST_EPOCH_UNIX_TIMESTAMP` is the unix timestamp of the plist epoch.
        const PLIST_EPOCH_UNIX_TIMESTAMP: u64 = 978_307_200;
        let plist_epoch = UNIX_EPOCH + Duration::from_secs(PLIST_EPOCH_UNIX_TIMESTAMP);

        if !timestamp.is_finite() {
            return Err(());
        }

        let is_negative = timestamp < 0.0;
        let timestamp = timestamp.abs();
        let seconds = timestamp.floor() as u64;
        let subsec_nanos = (timestamp.fract() * 1e9) as u32;

        let dur_since_plist_epoch = Duration::new(seconds, subsec_nanos);

        let inner = if is_negative {
            plist_epoch - dur_since_plist_epoch
        } else {
            plist_epoch + dur_since_plist_epoch
        };

        Ok(Date { inner })
    }
}

impl fmt::Debug for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        let rfc3339 = humantime::format_rfc3339(self.inner);
        <humantime::Rfc3339Timestamp as fmt::Display>::fmt(&rfc3339, f)
    }
}

impl From<SystemTime> for Date {
    fn from(date: SystemTime) -> Self {
        Date { inner: date }
    }
}

impl Into<SystemTime> for Date {
    fn into(self) -> SystemTime {
        self.inner
    }
}

#[cfg(feature = "serde")]
pub mod serde_impls {
    use serde::de::{Deserialize, Deserializer, Error, Unexpected, Visitor};
    use serde::ser::{Serialize, Serializer};
    use std::fmt;

    use Date;

    pub const DATE_NEWTYPE_STRUCT_NAME: &str = "PLIST-DATE";

    impl Serialize for Date {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            let date_str = self.to_rfc3339();
            serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
        }
    }

    struct DateNewtypeVisitor;

    impl<'de> Visitor<'de> for DateNewtypeVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date newtype")
        }

        fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_str(DateStrVisitor)
        }
    }

    struct DateStrVisitor;

    impl<'de> Visitor<'de> for DateStrVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date string")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Date::from_rfc3339(v).map_err(|()| E::invalid_value(Unexpected::Str(v), &self))
        }
    }

    impl<'de> Deserialize<'de> for Date {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
        }
    }
}
<commit_msg>Manually implement Hash for Date to keep minimum supported Rust version at 1.18.0.<commit_after>use humantime;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::result::Result as StdResult;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

/// A UTC timestamp. Used for serialization to and from the plist date type.
#[derive(Clone, Copy, PartialEq)]
pub struct Date {
    inner: SystemTime,
}

impl Date {
    pub(crate) fn from_rfc3339(date: &str) -> Result<Self, ()> {
        Ok(Date {
            inner: humantime::parse_rfc3339(date).map_err(|_| ())?,
        })
    }

    pub(crate) fn to_rfc3339(&self) -> String {
        format!("{}", humantime::format_rfc3339(self.inner))
    }

    pub(crate) fn from_seconds_since_plist_epoch(timestamp: f64) -> Result<Date, ()> {
        // `timestamp` is the number of seconds since the plist epoch of 1/1/2001 00:00:00.
        // `PLIST_EPOCH_UNIX_TIMESTAMP` is the unix timestamp of the plist epoch.
        const PLIST_EPOCH_UNIX_TIMESTAMP: u64 = 978_307_200;
        let plist_epoch = UNIX_EPOCH + Duration::from_secs(PLIST_EPOCH_UNIX_TIMESTAMP);

        if !timestamp.is_finite() {
            return Err(());
        }

        let is_negative = timestamp < 0.0;
        let timestamp = timestamp.abs();
        let seconds = timestamp.floor() as u64;
        let subsec_nanos = (timestamp.fract() * 1e9) as u32;

        let dur_since_plist_epoch = Duration::new(seconds, subsec_nanos);

        let inner = if is_negative {
            plist_epoch - dur_since_plist_epoch
        } else {
            plist_epoch + dur_since_plist_epoch
        };

        Ok(Date { inner })
    }
}

impl fmt::Debug for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        let rfc3339 = humantime::format_rfc3339(self.inner);
        <humantime::Rfc3339Timestamp as fmt::Display>::fmt(&rfc3339, f)
    }
}

// TODO: Remove manual impl once minimum Rust version reaches 1.24.0.
impl Hash for Date {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let elapsed = match self.inner.duration_since(UNIX_EPOCH) {
            Ok(elapsed) => {
                false.hash(state);
                elapsed
            }
            Err(err) => {
                true.hash(state);
                err.duration()
            }
        };
        elapsed.hash(state)
    }
}

impl From<SystemTime> for Date {
    fn from(date: SystemTime) -> Self {
        Date { inner: date }
    }
}

impl Into<SystemTime> for Date {
    fn into(self) -> SystemTime {
        self.inner
    }
}

#[cfg(feature = "serde")]
pub mod serde_impls {
    use serde::de::{Deserialize, Deserializer, Error, Unexpected, Visitor};
    use serde::ser::{Serialize, Serializer};
    use std::fmt;

    use Date;

    pub const DATE_NEWTYPE_STRUCT_NAME: &str = "PLIST-DATE";

    impl Serialize for Date {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            let date_str = self.to_rfc3339();
            serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
        }
    }

    struct DateNewtypeVisitor;

    impl<'de> Visitor<'de> for DateNewtypeVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date newtype")
        }

        fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_str(DateStrVisitor)
        }
    }

    struct DateStrVisitor;

    impl<'de> Visitor<'de> for DateStrVisitor {
        type Value = Date;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a plist date string")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Date::from_rfc3339(v).map_err(|()| E::invalid_value(Unexpected::Str(v), &self))
        }
    }

    impl<'de> Deserialize<'de> for Date {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
        }
    }
}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="overflow" sub_properties="overflow-x overflow-y"
                    spec="https://drafts.csswg.org/css-overflow/#propdef-overflow">
    use properties::longhands::{overflow_x, overflow_y};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let overflow = try!(overflow_x::parse(context, input));
        Ok(Longhands {
            overflow_x: Some(overflow),
            overflow_y: Some(overflow_y::SpecifiedValue(overflow)),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let x_and_y_equal = match (self.overflow_x, self.overflow_y) {
                (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
                    *x_value == y_container.0
                },
                (&DeclaredValue::WithVariables { .. }, &DeclaredValue::WithVariables { .. }) => true,
                (&DeclaredValue::Initial, &DeclaredValue::Initial) => true,
                (&DeclaredValue::Inherit, &DeclaredValue::Inherit) => true,
                (&DeclaredValue::Unset, &DeclaredValue::Unset) => true,
                _ => false
            };

            if x_and_y_equal {
                try!(self.overflow_x.to_css(dest));
            }
            Ok(())
        }

        // Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
        // values, they no longer use the shared property name "overflow".
        // Other shorthands do not include their name in the to_css method
        pub fn to_css_declared_with_name<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let x_and_y_equal = match (self.overflow_x, self.overflow_y) {
                (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
                    *x_value == y_container.0
                },
                (_, &DeclaredValue::WithVariables { .. }) |
                (&DeclaredValue::WithVariables { .. }, _) => {
                    // We don't serialize shorthands with variables
                    return dest.write_str("");
                },
                (&DeclaredValue::Initial, &DeclaredValue::Initial) => true,
                (&DeclaredValue::Inherit, &DeclaredValue::Inherit) => true,
                (&DeclaredValue::Unset, &DeclaredValue::Unset) => true,
                _ => false
            };

            if x_and_y_equal {
                try!(write!(dest, "overflow"));
                try!(write!(dest, ": "));
                try!(self.overflow_x.to_css(dest));
            } else {
                try!(write!(dest, "overflow-x"));
                try!(write!(dest, ": "));
                try!(self.overflow_x.to_css(dest));
                try!(write!(dest, "; "));

                try!(write!(dest, "overflow-y: "));
                try!(self.overflow_y.to_css(dest));
            }

            write!(dest, ";")
        }
    }
</%helpers:shorthand>

macro_rules! try_parse_one {
    ($input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try($prop_module::SingleSpecifiedValue::parse) {
                $var = Some(value);
                continue;
            }
        }
    };
    ($context: expr, $input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try(|i| {
                $prop_module::SingleSpecifiedValue::parse($context, i)
            }) {
                $var = Some(value);
                continue;
            }
        }
    };
}

<%helpers:shorthand name="transition" extra_prefixes="moz webkit"
                    sub_properties="transition-property transition-duration
                                    transition-timing-function
                                    transition-delay"
                    spec="https://drafts.csswg.org/css-transitions/#propdef-transition">
    use parser::Parse;
    use properties::longhands::{transition_delay, transition_duration, transition_property};
    use properties::longhands::{transition_timing_function};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleTransition {
            transition_property: transition_property::SingleSpecifiedValue,
            transition_duration: transition_duration::SingleSpecifiedValue,
            transition_timing_function: transition_timing_function::SingleSpecifiedValue,
            transition_delay: transition_delay::SingleSpecifiedValue,
        }

        fn parse_one_transition(context: &ParserContext, input: &mut Parser) -> Result<SingleTransition,()> {
            let (mut property, mut duration) = (None, None);
            let (mut timing_function, mut delay) = (None, None);
            loop {
                try_parse_one!(input, property, transition_property);
                try_parse_one!(context, input, duration, transition_duration);
                try_parse_one!(context, input, timing_function, transition_timing_function);
                try_parse_one!(context, input, delay, transition_delay);

                break
            }

            if let Some(property) = property {
                Ok(SingleTransition {
                    transition_property: property,
                    transition_duration:
                        duration.unwrap_or_else(transition_duration::single_value::get_initial_value),
                    transition_timing_function:
                        timing_function.unwrap_or_else(transition_timing_function::single_value
                                                                                ::get_initial_specified_value),
                    transition_delay:
                        delay.unwrap_or_else(transition_delay::single_value::get_initial_value),
                })
            } else {
                Err(())
            }
        }

        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(Longhands {
                transition_property: None,
                transition_duration: None,
                transition_timing_function: None,
                transition_delay: None,
            })
        }

        let results = try!(input.parse_comma_separated(|i| parse_one_transition(context, i)));
        let (mut properties, mut durations) = (Vec::new(), Vec::new());
        let (mut timing_functions, mut delays) = (Vec::new(), Vec::new());
        for result in results {
            properties.push(result.transition_property);
            durations.push(result.transition_duration);
            timing_functions.push(result.transition_timing_function);
            delays.push(result.transition_delay);
        }

        Ok(Longhands {
            transition_property: Some(transition_property::SpecifiedValue(properties)),
            transition_duration: Some(transition_duration::SpecifiedValue(durations)),
            transition_timing_function:
                Some(transition_timing_function::SpecifiedValue(timing_functions)),
            transition_delay: Some(transition_delay::SpecifiedValue(delays)),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.transition_property.to_css(dest));
            try!(write!(dest, " "));

            try!(self.transition_duration.to_css(dest));
            try!(write!(dest, " "));

            try!(self.transition_timing_function.to_css(dest));
            try!(write!(dest, " "));

            self.transition_delay.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="animation" extra_prefixes="moz webkit"
                    sub_properties="animation-name animation-duration
                                    animation-timing-function animation-delay
                                    animation-iteration-count animation-direction
                                    animation-fill-mode animation-play-state"
                    allowed_in_keyframe_block="False"
                    spec="https://drafts.csswg.org/css-animations/#propdef-animation">
    use parser::Parse;
    use properties::longhands::{animation_name, animation_duration, animation_timing_function};
    use properties::longhands::{animation_delay, animation_iteration_count, animation_direction};
    use properties::longhands::{animation_fill_mode, animation_play_state};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleAnimation {
            animation_name: animation_name::SingleSpecifiedValue,
            animation_duration: animation_duration::SingleSpecifiedValue,
            animation_timing_function: animation_timing_function::SingleSpecifiedValue,
            animation_delay: animation_delay::SingleSpecifiedValue,
            animation_iteration_count: animation_iteration_count::SingleSpecifiedValue,
            animation_direction: animation_direction::SingleSpecifiedValue,
            animation_fill_mode: animation_fill_mode::SingleSpecifiedValue,
            animation_play_state: animation_play_state::SingleSpecifiedValue,
        }

        fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result<SingleAnimation,()> {
            let mut duration = None;
            let mut timing_function = None;
            let mut delay = None;
            let mut iteration_count = None;
            let mut direction = None;
            let mut fill_mode = None;
            let mut play_state = None;
            let mut name = None;

            // NB: Name must be the last one here so that keywords valid for other
            // longhands are not interpreted as names.
            //
            // Also, duration must be before delay, see
            // https://drafts.csswg.org/css-animations/#typedef-single-animation
            loop {
                try_parse_one!(context, input, duration, animation_duration);
                try_parse_one!(context, input, timing_function, animation_timing_function);
                try_parse_one!(context, input, delay, animation_delay);
                try_parse_one!(context, input, iteration_count, animation_iteration_count);
                try_parse_one!(input, direction, animation_direction);
                try_parse_one!(input, fill_mode, animation_fill_mode);
                try_parse_one!(input, play_state, animation_play_state);
                try_parse_one!(context, input, name, animation_name);

                break
            }

            if let Some(name) = name {
                Ok(SingleAnimation {
                    animation_name: name,
                    animation_duration:
                        duration.unwrap_or_else(animation_duration::single_value::get_initial_value),
                    animation_timing_function:
                        timing_function.unwrap_or_else(animation_timing_function::single_value
                                                                                ::get_initial_specified_value),
                    animation_delay:
                        delay.unwrap_or_else(animation_delay::single_value::get_initial_value),
                    animation_iteration_count:
                        iteration_count.unwrap_or_else(animation_iteration_count::single_value::get_initial_value),
                    animation_direction:
                        direction.unwrap_or_else(animation_direction::single_value::get_initial_value),
                    animation_fill_mode:
                        fill_mode.unwrap_or_else(animation_fill_mode::single_value::get_initial_value),
                    animation_play_state:
                        play_state.unwrap_or_else(animation_play_state::single_value::get_initial_value),
                })
            } else {
                Err(())
            }
        }

        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(Longhands {
                animation_name: None,
                animation_duration: None,
                animation_timing_function: None,
                animation_delay: None,
                animation_iteration_count: None,
                animation_direction: None,
                animation_fill_mode: None,
                animation_play_state: None,
            })
        }

        let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));

        let mut names = vec![];
        let mut durations = vec![];
        let mut timing_functions = vec![];
        let mut delays = vec![];
        let mut iteration_counts = vec![];
        let mut directions = vec![];
        let mut fill_modes = vec![];
        let mut play_states = vec![];

        for result in results.into_iter() {
            names.push(result.animation_name);
            durations.push(result.animation_duration);
            timing_functions.push(result.animation_timing_function);
            delays.push(result.animation_delay);
            iteration_counts.push(result.animation_iteration_count);
            directions.push(result.animation_direction);
            fill_modes.push(result.animation_fill_mode);
            play_states.push(result.animation_play_state);
        }

        Ok(Longhands {
            animation_name: Some(animation_name::SpecifiedValue(names)),
            animation_duration: Some(animation_duration::SpecifiedValue(durations)),
            animation_timing_function: Some(animation_timing_function::SpecifiedValue(timing_functions)),
            animation_delay: Some(animation_delay::SpecifiedValue(delays)),
            animation_iteration_count: Some(animation_iteration_count::SpecifiedValue(iteration_counts)),
            animation_direction: Some(animation_direction::SpecifiedValue(directions)),
            animation_fill_mode: Some(animation_fill_mode::SpecifiedValue(fill_modes)),
            animation_play_state: Some(animation_play_state::SpecifiedValue(play_states)),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.animation_duration.to_css(dest));
            try!(write!(dest, " "));

            // FIXME: timing function is displaying the actual mathematical name "cubic-bezier(0.25, 0.1, 0.25, 1)"
            // instead of the common name "ease"
            try!(self.animation_timing_function.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_delay.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_direction.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_fill_mode.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_iteration_count.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_play_state.to_css(dest));
            try!(write!(dest, " "));

            self.animation_name.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="scroll-snap-type" products="gecko"
                    sub_properties="scroll-snap-type-x scroll-snap-type-y"
                    spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type">
    use properties::longhands::scroll_snap_type_x;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let result = try!(scroll_snap_type_x::parse(context, input));
        Ok(Longhands {
            scroll_snap_type_x: Some(result),
            scroll_snap_type_y: Some(result),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        // Serializes into the single keyword value if both scroll-snap-type and scroll-snap-type-y are same.
        // Otherwise into an empty string. This is done to match Gecko's behaviour.
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let x_and_y_equal = match (self.scroll_snap_type_x, self.scroll_snap_type_y) {
                (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_value)) => {
                    *x_value == *y_value
                },
                (&DeclaredValue::Initial, &DeclaredValue::Initial) => true,
                (&DeclaredValue::Inherit, &DeclaredValue::Inherit) => true,
                (&DeclaredValue::Unset, &DeclaredValue::Unset) => true,
                (x, y) => { *x == *y },
            };

            if x_and_y_equal {
                self.scroll_snap_type_x.to_css(dest)
            } else {
                Ok(())
            }
        }
    }
</%helpers:shorthand>
<commit_msg>removed invalid FIXME<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="overflow" sub_properties="overflow-x overflow-y"
                    spec="https://drafts.csswg.org/css-overflow/#propdef-overflow">
    use properties::longhands::{overflow_x, overflow_y};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let overflow = try!(overflow_x::parse(context, input));
        Ok(Longhands {
            overflow_x: Some(overflow),
            overflow_y: Some(overflow_y::SpecifiedValue(overflow)),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let x_and_y_equal = match (self.overflow_x, self.overflow_y) {
                (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
                    *x_value == y_container.0
                },
                (&DeclaredValue::WithVariables { .. }, &DeclaredValue::WithVariables { .. }) => true,
                (&DeclaredValue::Initial, &DeclaredValue::Initial) => true,
                (&DeclaredValue::Inherit, &DeclaredValue::Inherit) => true,
                (&DeclaredValue::Unset, &DeclaredValue::Unset) => true,
                _ => false
            };

            if x_and_y_equal {
                try!(self.overflow_x.to_css(dest));
            }
            Ok(())
        }

        // Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
        // values, they no longer use the shared property name "overflow".
        // Other shorthands do not include their name in the to_css method
        pub fn to_css_declared_with_name<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let x_and_y_equal = match (self.overflow_x, self.overflow_y) {
                (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
                    *x_value == y_container.0
                },
                (_, &DeclaredValue::WithVariables { .. }) |
                (&DeclaredValue::WithVariables { .. }, _) => {
                    // We don't serialize shorthands with variables
                    return dest.write_str("");
                },
                (&DeclaredValue::Initial, &DeclaredValue::Initial) => true,
                (&DeclaredValue::Inherit, &DeclaredValue::Inherit) => true,
                (&DeclaredValue::Unset, &DeclaredValue::Unset) => true,
                _ => false
            };

            if x_and_y_equal {
                try!(write!(dest, "overflow"));
                try!(write!(dest, ": "));
                try!(self.overflow_x.to_css(dest));
            } else {
                try!(write!(dest, "overflow-x"));
                try!(write!(dest, ": "));
                try!(self.overflow_x.to_css(dest));
                try!(write!(dest, "; "));

                try!(write!(dest, "overflow-y: "));
                try!(self.overflow_y.to_css(dest));
            }

            write!(dest, ";")
        }
    }
</%helpers:shorthand>

macro_rules! try_parse_one {
    ($input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try($prop_module::SingleSpecifiedValue::parse) {
                $var = Some(value);
                continue;
            }
        }
    };
    ($context: expr, $input: expr, $var: ident, $prop_module: ident) => {
        if $var.is_none() {
            if let Ok(value) = $input.try(|i| {
                $prop_module::SingleSpecifiedValue::parse($context, i)
            }) {
                $var = Some(value);
                continue;
            }
        }
    };
}

<%helpers:shorthand name="transition" extra_prefixes="moz webkit"
                    sub_properties="transition-property transition-duration
                                    transition-timing-function
                                    transition-delay"
                    spec="https://drafts.csswg.org/css-transitions/#propdef-transition">
    use parser::Parse;
    use properties::longhands::{transition_delay, transition_duration, transition_property};
    use properties::longhands::{transition_timing_function};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleTransition {
            transition_property: transition_property::SingleSpecifiedValue,
            transition_duration: transition_duration::SingleSpecifiedValue,
            transition_timing_function: transition_timing_function::SingleSpecifiedValue,
            transition_delay: transition_delay::SingleSpecifiedValue,
        }

        fn parse_one_transition(context: &ParserContext, input: &mut Parser) -> Result<SingleTransition,()> {
            let (mut property, mut duration) = (None, None);
            let (mut timing_function, mut delay) = (None, None);
            loop {
                try_parse_one!(input, property, transition_property);
                try_parse_one!(context, input, duration, transition_duration);
                try_parse_one!(context, input, timing_function, transition_timing_function);
                try_parse_one!(context, input, delay, transition_delay);

                break
            }

            if let Some(property) = property {
                Ok(SingleTransition {
                    transition_property: property,
                    transition_duration:
                        duration.unwrap_or_else(transition_duration::single_value::get_initial_value),
                    transition_timing_function:
                        timing_function.unwrap_or_else(transition_timing_function::single_value
                                                                                ::get_initial_specified_value),
                    transition_delay:
                        delay.unwrap_or_else(transition_delay::single_value::get_initial_value),
                })
            } else {
                Err(())
            }
        }

        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(Longhands {
                transition_property: None,
                transition_duration: None,
                transition_timing_function: None,
                transition_delay: None,
            })
        }

        let results = try!(input.parse_comma_separated(|i| parse_one_transition(context, i)));
        let (mut properties, mut durations) = (Vec::new(), Vec::new());
        let (mut timing_functions, mut delays) = (Vec::new(), Vec::new());
        for result in results {
            properties.push(result.transition_property);
            durations.push(result.transition_duration);
            timing_functions.push(result.transition_timing_function);
            delays.push(result.transition_delay);
        }

        Ok(Longhands {
            transition_property: Some(transition_property::SpecifiedValue(properties)),
            transition_duration: Some(transition_duration::SpecifiedValue(durations)),
            transition_timing_function:
                Some(transition_timing_function::SpecifiedValue(timing_functions)),
            transition_delay: Some(transition_delay::SpecifiedValue(delays)),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.transition_property.to_css(dest));
            try!(write!(dest, " "));

            try!(self.transition_duration.to_css(dest));
            try!(write!(dest, " "));

            try!(self.transition_timing_function.to_css(dest));
            try!(write!(dest, " "));

            self.transition_delay.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="animation" extra_prefixes="moz webkit"
                    sub_properties="animation-name animation-duration
                                    animation-timing-function animation-delay
                                    animation-iteration-count animation-direction
                                    animation-fill-mode animation-play-state"
                    allowed_in_keyframe_block="False"
                    spec="https://drafts.csswg.org/css-animations/#propdef-animation">
    use parser::Parse;
    use properties::longhands::{animation_name, animation_duration, animation_timing_function};
    use properties::longhands::{animation_delay, animation_iteration_count, animation_direction};
    use properties::longhands::{animation_fill_mode, animation_play_state};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        struct SingleAnimation {
            animation_name: animation_name::SingleSpecifiedValue,
            animation_duration: animation_duration::SingleSpecifiedValue,
            animation_timing_function: animation_timing_function::SingleSpecifiedValue,
            animation_delay: animation_delay::SingleSpecifiedValue,
            animation_iteration_count: animation_iteration_count::SingleSpecifiedValue,
            animation_direction: animation_direction::SingleSpecifiedValue,
            animation_fill_mode: animation_fill_mode::SingleSpecifiedValue,
            animation_play_state: animation_play_state::SingleSpecifiedValue,
        }

        fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result<SingleAnimation,()> {
            let mut duration = None;
            let mut timing_function = None;
            let mut delay = None;
            let mut iteration_count = None;
            let mut direction = None;
            let mut fill_mode = None;
            let mut play_state = None;
            let mut name = None;

            // NB: Name must be the last one here so that keywords valid for other
            // longhands are not interpreted as names.
            //
            // Also, duration must be before delay, see
            // https://drafts.csswg.org/css-animations/#typedef-single-animation
            loop {
                try_parse_one!(context, input, duration, animation_duration);
                try_parse_one!(context, input, timing_function, animation_timing_function);
                try_parse_one!(context, input, delay, animation_delay);
                try_parse_one!(context, input, iteration_count, animation_iteration_count);
                try_parse_one!(input, direction, animation_direction);
                try_parse_one!(input, fill_mode, animation_fill_mode);
                try_parse_one!(input, play_state, animation_play_state);
                try_parse_one!(context, input, name, animation_name);

                break
            }

            if let Some(name) = name {
                Ok(SingleAnimation {
                    animation_name: name,
                    animation_duration:
                        duration.unwrap_or_else(animation_duration::single_value::get_initial_value),
                    animation_timing_function:
                        timing_function.unwrap_or_else(animation_timing_function::single_value
                                                                                ::get_initial_specified_value),
                    animation_delay:
                        delay.unwrap_or_else(animation_delay::single_value::get_initial_value),
                    animation_iteration_count:
                        iteration_count.unwrap_or_else(animation_iteration_count::single_value::get_initial_value),
                    animation_direction:
                        direction.unwrap_or_else(animation_direction::single_value::get_initial_value),
                    animation_fill_mode:
                        fill_mode.unwrap_or_else(animation_fill_mode::single_value::get_initial_value),
                    animation_play_state:
                        play_state.unwrap_or_else(animation_play_state::single_value::get_initial_value),
                })
            } else {
                Err(())
            }
        }

        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(Longhands {
                animation_name: None,
                animation_duration: None,
                animation_timing_function: None,
                animation_delay: None,
                animation_iteration_count: None,
                animation_direction: None,
                animation_fill_mode: None,
                animation_play_state: None,
            })
        }

        let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));

        let mut names = vec![];
        let mut durations = vec![];
        let mut timing_functions = vec![];
        let mut delays = vec![];
        let mut iteration_counts = vec![];
        let mut directions = vec![];
        let mut fill_modes = vec![];
        let mut play_states = vec![];

        for result in results.into_iter() {
            names.push(result.animation_name);
            durations.push(result.animation_duration);
            timing_functions.push(result.animation_timing_function);
            delays.push(result.animation_delay);
            iteration_counts.push(result.animation_iteration_count);
            directions.push(result.animation_direction);
            fill_modes.push(result.animation_fill_mode);
            play_states.push(result.animation_play_state);
        }

        Ok(Longhands {
            animation_name: Some(animation_name::SpecifiedValue(names)),
            animation_duration: Some(animation_duration::SpecifiedValue(durations)),
            animation_timing_function: Some(animation_timing_function::SpecifiedValue(timing_functions)),
            animation_delay: Some(animation_delay::SpecifiedValue(delays)),
            animation_iteration_count: Some(animation_iteration_count::SpecifiedValue(iteration_counts)),
            animation_direction: Some(animation_direction::SpecifiedValue(directions)),
            animation_fill_mode: Some(animation_fill_mode::SpecifiedValue(fill_modes)),
            animation_play_state: Some(animation_play_state::SpecifiedValue(play_states)),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.animation_duration.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_timing_function.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_delay.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_direction.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_fill_mode.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_iteration_count.to_css(dest));
            try!(write!(dest, " "));

            try!(self.animation_play_state.to_css(dest));
            try!(write!(dest, " "));

            self.animation_name.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="scroll-snap-type" products="gecko"
                    sub_properties="scroll-snap-type-x scroll-snap-type-y"
                    spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type">
    use properties::longhands::scroll_snap_type_x;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let result = try!(scroll_snap_type_x::parse(context, input));
        Ok(Longhands {
            scroll_snap_type_x: Some(result),
            scroll_snap_type_y: Some(result),
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        // Serializes into the single keyword value if both scroll-snap-type and scroll-snap-type-y are same.
        // Otherwise into an empty string. This is done to match Gecko's behaviour.
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let x_and_y_equal = match (self.scroll_snap_type_x, self.scroll_snap_type_y) {
                (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_value)) => {
                    *x_value == *y_value
                },
                (&DeclaredValue::Initial, &DeclaredValue::Initial) => true,
                (&DeclaredValue::Inherit, &DeclaredValue::Inherit) => true,
                (&DeclaredValue::Unset, &DeclaredValue::Unset) => true,
                (x, y) => { *x == *y },
            };

            if x_and_y_equal {
                self.scroll_snap_type_x.to_css(dest)
            } else {
                Ok(())
            }
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>use imgui::{Ui,ImStr,ImString};

use std::fs;
use std::path::Path;

use app::AppState;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
        }
    }
}

impl FileState {
    fn update(&mut self) {
        let cd = self.cd.to_string();

        if self.idx > 1 { // chose a file?
            if let Some(file) = self.files.get(self.idx as usize) {
                self.cd.clear();
                self.cd.push_str(file);
                self.idx = 1;
            }
        }
        else if self.idx < 1 { // up a directory?
            if let Some(path) = Path::new(&cd).parent() {
                self.cd.clear();
                self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
                self.idx = 1;
            }
            // NOTE: this fails if we're at the top of a relative directory listing,
            // or the root of the drive/share
        }

        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path().to_str().unwrap().to_owned()
                    })
                    .collect();

                self.files.insert(0,"./".to_owned());
                self.files.insert(0,"..".to_owned());
            }
            // NOTE: we should throw a warning here if directory cannot be traversed
        }
        else { self.selected = Some(cd); }
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }

        ui.window(im_str!("Select source"))
            .always_auto_resize(true)
            .movable(true)
            .show_borders(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                self.update();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must do build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                })
                    .collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);
            })
    }

}

<commit_msg>fix and select<commit_after>use imgui::{Ui,ImStr,ImString};

use std::fs;
use std::path::Path;

use app::AppState;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
        }
    }
}

impl FileState {
    fn update(&mut self) {
        let cd = self.cd.to_string();

        if self.idx > 1 { // chose a file?
            if let Some(file) = self.files.get(self.idx as usize) {
                self.cd.clear();
                self.cd.push_str(file);
                self.idx = 1;
            }
        }
        else if self.idx < 1 { // up a directory?
            if let Some(path) = Path::new(&cd).parent() {
                self.cd.clear();
                self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
                self.idx = 1;
            }
            // NOTE: this fails if we're at the top of a relative directory listing,
            // or the root of the drive/share
        }

        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path().to_str().unwrap().to_owned()
                    })
                    .collect();

                self.files.insert(0,"./".to_owned());
                self.files.insert(0,"..".to_owned());
            }
            // NOTE: we should throw a warning here if directory cannot be traversed
        }
        else { self.selected = Some(cd); }
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }

        ui.window(im_str!("Select source"))
            .always_auto_resize(true)
            .movable(true)
            .show_borders(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                self.update();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                })
                    .collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);
            })
    }

}

<|endoftext|>


<commit_before>use std::io::{Read, Seek};
use std::mem;

use Result;
use truetype::compound::*;
use truetype::primitive::Tag;
use truetype::{Tape, Value};

/// A font.
#[derive(Default)]
pub struct Font {
    pub offset_table: OffsetTable,
    pub char_mapping: Option<CharMapping>,
    pub font_header: Option<FontHeader>,
    pub horizontal_header: Option<HorizontalHeader>,
    pub horizontal_metrics: Option<HorizontalMetrics>,
    pub maximum_profile: Option<MaximumProfile>,
    pub naming_table: Option<NamingTable>,
    pub postscript: Option<PostScript>,
    pub windows_metrics: Option<WindowsMetrics>,
}

macro_rules! checksum_and_jump(
    ($record:ident, $tape:ident, $process:expr) => ({
        if !try!($record.checksum($tape, $process)) {
            raise!("found a corrupted font table");
        }
        try!($tape.jump($record.offset as u64));
    });
    ($record:ident, $tape:ident) => (
        checksum_and_jump!($record, $tape, |_, word| word);
    );
);

impl Font {
    #[inline]
    pub fn read<T: Read + Seek>(tape: &mut T) -> Result<Font> {
        macro_rules! sort(
            ($records:expr) => ({
                let mut records = $records.iter().collect::<Vec<_>>();
                records.sort_by(|one, two| {
                    priority(Tag(one.tag)).cmp(&priority(Tag(two.tag)))
                });
                records
            });
        );

        let mut font = Font { offset_table: try!(Value::read(tape)), .. Font::default() };
        if Tag::from(font.offset_table.header.version) != Tag::from(b"OTTO") {
            raise!("the font format is invalid");
        }

        for record in sort!(font.offset_table.records) {
            macro_rules! set(
                ($field:ident, $value:expr) => ({
                    checksum_and_jump!(record, tape);
                    font.$field = Some(try!($value));
                });
                ($field:ident) => (set!($field, Value::read(tape)));
            );
            match &Tag(record.tag).into() {
                b"cmap" => set!(char_mapping),
                b"head" => {
                    checksum_and_jump!(record, tape, |i, word| if i == 2 { 0 } else { word });
                    font.font_header = Some(try!(Value::read(tape)));
                },
                b"hhea" => set!(horizontal_header),
                b"hmtx" => {
                    let header = match font.horizontal_header {
                        Some(ref table) => table,
                        _ => continue,
                    };
                    let profile = match font.maximum_profile {
                        Some(ref table) => table,
                        _ => continue,
                    };
                    set!(horizontal_metrics, HorizontalMetrics::read(tape, header, profile));
                },
                b"maxp" => set!(maximum_profile),
                b"name" => set!(naming_table),
                b"post" => set!(postscript),
                b"OS/2" => set!(windows_metrics),
                _ => {},
            }
        }

        Ok(font)
    }
}

fn priority(tag: Tag) -> usize {
    use std::collections::HashMap;
    use std::sync::{Once, ONCE_INIT};

    unsafe {
        static mut PRIORITY: *const HashMap<Tag, usize> = 0 as *const _;
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            let mut map: HashMap<Tag, usize> = HashMap::new();
            map.insert(Tag::from(b"hmtx"), 42);
            PRIORITY = mem::transmute(Box::new(map));
        });
        *(&*PRIORITY).get(&tag).unwrap_or(&0)
    }
}
<commit_msg>A cosmetic change<commit_after>use std::io::{Read, Seek};
use std::mem;

use Result;
use truetype::compound::*;
use truetype::primitive::Tag;
use truetype::{Tape, Value};

/// A font.
#[derive(Default)]
pub struct Font {
    pub offset_table: OffsetTable,
    pub char_mapping: Option<CharMapping>,
    pub font_header: Option<FontHeader>,
    pub horizontal_header: Option<HorizontalHeader>,
    pub horizontal_metrics: Option<HorizontalMetrics>,
    pub maximum_profile: Option<MaximumProfile>,
    pub naming_table: Option<NamingTable>,
    pub postscript: Option<PostScript>,
    pub windows_metrics: Option<WindowsMetrics>,
}

macro_rules! checksum_and_jump(
    ($record:ident, $tape:ident, $process:expr) => ({
        if !try!($record.checksum($tape, $process)) {
            raise!("found a corrupted font table");
        }
        try!($tape.jump($record.offset as u64));
    });
    ($record:ident, $tape:ident) => (
        checksum_and_jump!($record, $tape, |_, word| word);
    );
);

impl Font {
    #[inline]
    pub fn read<T: Read + Seek>(tape: &mut T) -> Result<Font> {
        macro_rules! sort(
            ($records:expr) => ({
                let mut records = $records.iter().collect::<Vec<_>>();
                records.sort_by(|one, two| priority(Tag(one.tag)).cmp(&priority(Tag(two.tag))));
                records
            });
        );

        let mut font = Font { offset_table: try!(Value::read(tape)), .. Font::default() };
        if Tag::from(font.offset_table.header.version) != Tag::from(b"OTTO") {
            raise!("the font format is invalid");
        }

        for record in sort!(font.offset_table.records) {
            macro_rules! set(
                ($field:ident, $value:expr) => ({
                    checksum_and_jump!(record, tape);
                    font.$field = Some(try!($value));
                });
                ($field:ident) => (set!($field, Value::read(tape)));
            );
            match &Tag(record.tag).into() {
                b"cmap" => set!(char_mapping),
                b"head" => {
                    checksum_and_jump!(record, tape, |i, word| if i == 2 { 0 } else { word });
                    font.font_header = Some(try!(Value::read(tape)));
                },
                b"hhea" => set!(horizontal_header),
                b"hmtx" => {
                    let header = match font.horizontal_header {
                        Some(ref table) => table,
                        _ => continue,
                    };
                    let profile = match font.maximum_profile {
                        Some(ref table) => table,
                        _ => continue,
                    };
                    set!(horizontal_metrics, HorizontalMetrics::read(tape, header, profile));
                },
                b"maxp" => set!(maximum_profile),
                b"name" => set!(naming_table),
                b"post" => set!(postscript),
                b"OS/2" => set!(windows_metrics),
                _ => {},
            }
        }

        Ok(font)
    }
}

fn priority(tag: Tag) -> usize {
    use std::collections::HashMap;
    use std::sync::{Once, ONCE_INIT};

    unsafe {
        static mut PRIORITY: *const HashMap<Tag, usize> = 0 as *const _;
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            let mut map: HashMap<Tag, usize> = HashMap::new();
            map.insert(Tag::from(b"hmtx"), 42);
            PRIORITY = mem::transmute(Box::new(map));
        });
        *(&*PRIORITY).get(&tag).unwrap_or(&0)
    }
}
<|endoftext|>


<commit_before>use crosswords_rs::{Crosswords, Dir, Point, PrintItem};
use std::io::{Result, Write};

const HTML_START: &'static str = r#"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<title>CW</title>
"#;
const HTML_END: &'static str = "
";

fn get_border_class(border: bool) -> &'static str {
    if border { "border" } else { "line" }
}

fn string_for(item: PrintItem, solution: bool) -> String {
    match item {
        PrintItem::VertBorder(b) =>
            format!(r#"

"#, get_border_class(b)),
        PrintItem::HorizBorder(b) =>
            format!(r#"

"#, get_border_class(b)),
        PrintItem::Cross(b) =>
            format!(r#"

"#, get_border_class(b)),
        PrintItem::Block =>
            format!(r#"

"#),
        PrintItem::CharHint(c, hint) =>
            format!(concat!(r#"
"#,
                            r#"{}"#,
                            r#"{}"#,
                            r#"
"#),
                    hint.map(|h| h.to_string()).unwrap_or("".to_string()),
                    if solution { c.to_string() } else { " ".to_string() }),
        PrintItem::LineBreak => "
".to_string(),
    }
}

fn write_hints<T: Write>(writer: &mut T, cw: &Crosswords, dir: Dir) -> Result<()> {
    try!(writeln!(writer, "

{}: ", match dir {
        Dir::Right => "Horizontal",
        Dir::Down => "Vertical",
    }));
    let mut hint_count = 0;
    for y in 0..cw.get_height() {
        for x in 0..cw.get_width() {
            let p = Point::new(x as i32, y as i32);
            if cw.has_hint_at(p) { hint_count += 1; }
            if cw.has_hint_at_dir(p, dir) {
                let word: String = cw.chars_at(p, dir).collect();
                try!(write!(writer, "{}. [{}]  ", hint_count, word));
            }
        }
    }
    try!(writeln!(writer, "
"));
    Ok(())
}

fn write_grid<T: Write, I: Iterator<Item = PrintItem>>(writer: &mut T, items: I, solution: bool)
        -> Result<()> {
    try!(writeln!(writer, "
"));
    for item in items {
        try!(writer.write_all(&string_for(item, solution).as_bytes()))
    }
    try!(writeln!(writer, "
"));
    Ok(())
}

pub fn write_html<T: Write>(writer: &mut T, cw: &Crosswords, solution: bool) -> Result<()> {
    try!(writer.write_all(HTML_START.as_bytes()));
    try!(write_grid(writer, cw.print_items(), solution));
    try!(write_hints(writer, &cw, Dir::Right));
    try!(write_hints(writer, &cw, Dir::Down));
    try!(writer.write_all(HTML_END.as_bytes()));
    Ok(())
}
<commit_msg>Cleanup HTML<commit_after>use crosswords_rs::{Crosswords, Dir, Point, PrintItem};
use std::io::{Result, Write};

const CSS: &'static str = r#"
.solution {
    font: 22px monospace;
    text-align: center;
    position: absolute;
    left: 0px;
    right: 0px;
    bottom: 0px;
}
.hint {
    font: 8px monospace;
    color: Gray;
    position: absolute;
}
.row {
    overflow: hidden;
    float: left;
}
.row > div:nth-child(even) { width: 30px; }
.row > div:nth-child(odd) { width: 2px; }
.row > div {
    float: left;
    position: relative;
}
.low { height: 2px; }
.high { height: 30px; }
.dark { background-color: DarkBlue; }
.light { background-color: LightGray; }
.blockcol { background-color: DarkBlue; }
"#;

fn get_border_class(border: bool) -> &'static str {
    if border { "dark" } else { "light" }
}

fn string_for(item: PrintItem, solution: bool) -> String {
    match item {
        PrintItem::HorizBorder(b) | PrintItem::Cross(b) =>
            format!(r#"

"#, get_border_class(b)),
        PrintItem::VertBorder(b) =>
            format!(r#"

"#, get_border_class(b)),
        PrintItem::Block =>
            format!(r#"

"#),
        PrintItem::CharHint(c, hint) =>
            format!(concat!(r#"
"#,
                            r#"{}"#,
                            r#"{}"#,
                            r#"
"#),
                    hint.map(|h| h.to_string()).unwrap_or("".to_string()),
                    if solution { c.to_string() } else { " ".to_string() }),
        PrintItem::LineBreak => r#"

"#.to_string(),
    }
}

fn write_grid<T: Write, I: Iterator<Item = PrintItem>>(writer: &mut T, items: I, solution: bool)
        -> Result<()> {
    try!(writeln!(writer, r#"
"#));
    for item in items {
        try!(writer.write_all(&string_for(item, solution).as_bytes()))
    }
    try!(writeln!(writer, "
"));
    Ok(())
}

fn write_hints<T: Write>(writer: &mut T, cw: &Crosswords, dir: Dir) -> Result<()> {
    try!(writeln!(writer, "

{}: ", match dir {
        Dir::Right => "Horizontal",
        Dir::Down => "Vertical",
    }));
    let mut hint_count = 0;
    for y in 0..cw.get_height() {
        for x in 0..cw.get_width() {
            let p = Point::new(x as i32, y as i32);
            if cw.has_hint_at(p) { hint_count += 1; }
            if cw.has_hint_at_dir(p, dir) {
                let word: String = cw.chars_at(p, dir).collect();
                try!(write!(writer, "{}. [{}]  ", hint_count, word));
            }
        }
    }
    try!(writeln!(writer, "
"));
    Ok(())
}

pub fn write_html<T: Write>(writer: &mut T, cw: &Crosswords, solution: bool) -> Result<()> {
    try!(writeln!(writer, r#"<!doctype html>"#));
    try!(writeln!(writer, r#""#));
    try!(writeln!(writer, r#"<meta charset="utf-8" />"#));
    try!(writeln!(writer, r#""#, CSS));
    try!(writeln!(writer, r#"<title>Crosswords</title>"#));
    try!(writeln!(writer, r#""#));
    try!(writeln!(writer, r#"
"#, cw.get_width() * 32 + 2));
    try!(write_grid(writer, cw.print_items(), solution));
    try!(writeln!(writer, r#"

"#));
    try!(write_hints(writer, &cw, Dir::Right));
    try!(write_hints(writer, &cw, Dir::Down));
    try!(writeln!(writer, "
"));
    Ok(())
}
<|endoftext|>


<commit_before>use futures::Stream;
use bar_properties::BarProperties;
use tokio_core::reactor::Handle;

#[derive(Clone,Debug)]
pub enum Slot {
    Left,
    Center,
    Right,
}

pub trait ItemConfig: Sized {
    type Item: Item<Config=Self>;
}

pub trait ItemCreator {
    fn create_and_into_stream(self: Box<Self>, handle: Handle, bar_props: &BarProperties)
        -> Box<Stream<Item=String, Error=::error::Error>>;
}

impl<T> ItemCreator for T
    where T: ItemConfig,
          <<T as ItemConfig>::Item as Item>::Stream: Sized + 'static,
          <<T as ItemConfig>::Item as Item>::Error: 'static,
{
    fn create_and_into_stream(self: Box<Self>, handle: Handle, bar_props: &BarProperties)
        -> Box<Stream<Item=String, Error=::error::Error>>
    {
        let item = T::Item::create(bar_props, self);
        Box::new(item.updates(handle).map_err(|e| e.into()))
    }
}

pub trait Item: Sized {
    type Config: ItemConfig<Item=Self>;
    type Stream: Stream<Item=String, Error=Self::Error>;
    type Error: Into<::error::Error>;
    fn create(bp: &BarProperties, ic: Box<Self::Config>) -> Self;
    fn updates(self, handle: Handle) -> Self::Stream;
}
<commit_msg>Remove `item.rs` as a refactoring artifact.<commit_after><|endoftext|>


<commit_before>extern crate rust_sodium;
use rust_sodium::crypto::box_::curve25519xsalsa20poly1305 as crypto_box;

pub const PUBLIC_KEY_BYTES: usize = crypto_box::PUBLICKEYBYTES;
pub const SECRET_KEY_BYTES: usize = crypto_box::SECRETKEYBYTES;

// DNSCurve's Base32 decoding table
const BASE32_DECODING_TABLE: [u8; 128] = [
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99
        ];
// decode a base32-encoded byte array into an u32.
// Panics if the array is too large.
// Returns Err(c) if a character c is not valid in a Base32 string.
fn decode_base32(encoded: &[u8]) -> Result<Vec<u8>, u8> {
    println!("{:?}", encoded.len()*5);
    let mut res = Vec::with_capacity(encoded.len()*5/8);
    let mut last_word_length = 0;
    let mut last_word = 0u16;
    for c in encoded.iter() {
        let c = c.clone();
        if c >= 128 {
            return Err(c);
        }
        let bits = BASE32_DECODING_TABLE[c as usize];
        if bits == 99 {
            return Err(c);
        }

        // Add the new bits at the left of the current word
        last_word += (bits as u16) << last_word_length;
        last_word_length += 5;

        // If the right byte of the current word is full, push the on the vector
        // and shift the current word to remove the right byte.
        if last_word_length >= 8 {
            last_word_length -= 8;
            res.push((last_word & 0b11111111) as u8);
            last_word >>= 8;
        }
    }
    if last_word > 0 {
        res.push(last_word as u8);
    }
    Ok(res)
}

#[test]
fn test_decode_base32() {
    assert_eq!(decode_base32(b"4321"), Ok(vec![0x64, 0x88]));
    decode_base32(b"2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb050");
}

/// Represents a CryptoAuth public key.
///
/// # Example
///
/// ```
/// # use fcp_cryptoauth::keys::*;
/// PublicKey::new_from_base32(b"2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb050.k");
/// ```
pub struct PublicKey {
    pub crypto_box_key: crypto_box::PublicKey,
}
impl PublicKey {
    pub fn new_from_bytes(bytes: &[u8; PUBLIC_KEY_BYTES]) -> PublicKey {
        PublicKey { crypto_box_key: crypto_box::PublicKey::from_slice(bytes).unwrap(), }
    }
    /// Returns a Public key from its Base32 representation.
    ///
    /// TODO: better errors
    pub fn new_from_base32(characters: &[u8]) -> Option<PublicKey> {
        assert_eq!(characters[characters.len()-2..], b".k".to_owned());
        if let Ok(bytes) = decode_base32(characters) {
            if let Some(key) = crypto_box::PublicKey::from_slice(&bytes) {
                Some(PublicKey { crypto_box_key: key })
            }
            else {
                None
            }
        }
        else {
            None
        }
    }

    pub fn bytes(&self) -> &[u8; PUBLIC_KEY_BYTES] {
        &self.crypto_box_key.0
    }
}

pub struct SecretKey {
    pub crypto_box_key: crypto_box::SecretKey,
}
impl SecretKey {
    pub fn new(bytes: &[u8; SECRET_KEY_BYTES]) -> SecretKey {
        SecretKey { crypto_box_key: crypto_box::SecretKey::from_slice(bytes).unwrap(), }
    }

    pub fn bytes(&self) -> &[u8; SECRET_KEY_BYTES] {
        &self.crypto_box_key.0
    }
}

pub fn gen_keypair() -> (PublicKey, SecretKey) {
    let (cb_pk, cb_sk) = crypto_box::gen_keypair();
    (PublicKey { crypto_box_key: cb_pk }, SecretKey { crypto_box_key: cb_sk })
}
<commit_msg>Fix public key parsing (forgot to ignore the .k).<commit_after>extern crate rust_sodium;
use rust_sodium::crypto::box_::curve25519xsalsa20poly1305 as crypto_box;

pub const PUBLIC_KEY_BYTES: usize = crypto_box::PUBLICKEYBYTES;
pub const SECRET_KEY_BYTES: usize = crypto_box::SECRETKEYBYTES;

// DNSCurve's Base32 decoding table
const BASE32_DECODING_TABLE: [u8; 128] = [
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99
        ];
// decode a base32-encoded byte array into an u32.
// Panics if the array is too large.
// Returns Err(c) if a character c is not valid in a Base32 string.
fn decode_base32(encoded: &[u8]) -> Result<Vec<u8>, u8> {
    let mut res = Vec::with_capacity(encoded.len()*5/8);
    let mut last_word_length = 0;
    let mut last_word = 0u16;
    for c in encoded.iter() {
        let c = c.clone();
        if c >= 128 {
            return Err(c);
        }
        let bits = BASE32_DECODING_TABLE[c as usize];
        if bits == 99 {
            return Err(c);
        }

        // Add the new bits at the left of the current word
        last_word += (bits as u16) << last_word_length;
        last_word_length += 5;

        // If the right byte of the current word is full, push the on the vector
        // and shift the current word to remove the right byte.
        if last_word_length >= 8 {
            last_word_length -= 8;
            res.push((last_word & 0b11111111) as u8);
            last_word >>= 8;
        }
    }
    if last_word > 0 {
        res.push(last_word as u8);
    }
    Ok(res)
}

#[test]
fn test_decode_base32() {
    assert_eq!(decode_base32(b"4321"), Ok(vec![0x64, 0x88]));
    decode_base32(b"2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb050");
}

/// Represents a CryptoAuth public key.
///
/// # Example
///
/// ```
/// # use fcp_cryptoauth::keys::*;
/// let key = PublicKey::new_from_base32(b"2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb050.k");
/// assert!(key.is_some());
/// ```
pub struct PublicKey {
    pub crypto_box_key: crypto_box::PublicKey,
}
impl PublicKey {
    pub fn new_from_bytes(bytes: &[u8; PUBLIC_KEY_BYTES]) -> PublicKey {
        PublicKey { crypto_box_key: crypto_box::PublicKey::from_slice(bytes).unwrap(), }
    }
    /// Returns a Public key from its Base32 representation.
    ///
    /// TODO: better errors
    pub fn new_from_base32(characters: &[u8]) -> Option<PublicKey> {
        assert!(characters.len() >= 2);
        let length: usize = characters.len()-2;
        assert_eq!(characters[length..], b".k".to_owned());
        if let Ok(bytes) = decode_base32(&characters[..length]) {
            if let Some(key) = crypto_box::PublicKey::from_slice(&bytes) {
                Some(PublicKey { crypto_box_key: key })
            }
            else {
                None
            }
        }
        else {
            None
        }
    }

    pub fn bytes(&self) -> &[u8; PUBLIC_KEY_BYTES] {
        &self.crypto_box_key.0
    }
}

pub struct SecretKey {
    pub crypto_box_key: crypto_box::SecretKey,
}
impl SecretKey {
    pub fn new(bytes: &[u8; SECRET_KEY_BYTES]) -> SecretKey {
        SecretKey { crypto_box_key: crypto_box::SecretKey::from_slice(bytes).unwrap(), }
    }

    pub fn bytes(&self) -> &[u8; SECRET_KEY_BYTES] {
        &self.crypto_box_key.0
    }
}

pub fn gen_keypair() -> (PublicKey, SecretKey) {
    let (cb_pk, cb_sk) = crypto_box::gen_keypair();
    (PublicKey { crypto_box_key: cb_pk }, SecretKey { crypto_box_key: cb_sk })
}
<|endoftext|>