<commit_before>use std::collections::HashMap;
use super::entity::{Entity};
use super::components;
use super::component_ref::{ComponentRef, ComponentRefMut};
use super::stats;
use super::world::{self, WorldState};

/// Entity component system.
#[derive(RustcDecodable, RustcEncodable)]
pub struct Ecs {
    next_idx: usize,
    reusable_idxs: Vec<usize>,
    // Could use Bitv for active, but I can't bother to write the serializer...
    active: Vec<bool>,
    parent: HashMap<usize, usize>,
}

impl Ecs {
    pub fn new() -> Ecs {
        Ecs {
            next_idx: 0,
            reusable_idxs: vec![],
            active: vec![],
            parent: HashMap::new(),
        }
    }

    pub fn new_entity(&mut self, parent: Option<Entity>) -> Entity {
        // Get the entity idx, reuse old ones to keep the indexing compact.
        let idx = match self.reusable_idxs.pop() {
            None => {
                let ret = self.next_idx;
                self.next_idx += 1;
                ret
            }
            Some(idx) => idx
        };

        if let Some(Entity(p_idx)) = parent {
            assert!(self.active[p_idx]);
            self.parent.insert(idx, p_idx);
        }

        if self.active.len() <= idx {
            self.active.resize(idx + 1, false);
        }
        assert!(!self.active[idx]);
        self.active[idx] = true;

        Entity(idx)
    }

    /// Return whether given entity exists in the system.
    pub fn exists(&self, Entity(idx): Entity) -> bool { self.active[idx] }

    /// Delete an entity from the entity component system.
    ///
    /// XXX: The user is currently responsible for never using an entity
    /// handle again after delete_entity has been called on it. Using an
    /// entity handle after deletion may return another entity's contents.
    pub fn delete(&mut self, Entity(idx): Entity) {
        assert!(self.active[idx]);

        self.parent.remove(&idx);
        self.reusable_idxs.push(idx);
        self.active[idx] = false;
    }

    /// Return an iterator for the entities. The iterator will not be
    /// invalidated if entities are added or removed during iteration. The
    /// iterator also won't maintain a lock on the world singleton outside
    /// calling next.
    ///
    /// XXX: It is currently unspecified whether entities added during
    /// iteration will show up in the iteration or not.
    pub fn iter(&self) -> EntityIter {
        EntityIter(0)
    }

    /// Return the optional parent entity of an entity.
    pub fn parent(&self, Entity(idx): Entity) -> Option<Entity> {
        self.parent.get(&idx).map(|&idx| Entity(idx))
    }

    /// Change the parent of a live entity
    pub fn _reparent(&mut self, Entity(idx): Entity, Entity(new_parent_idx): Entity) {
        self.parent.insert(idx, new_parent_idx);
    }
}

pub struct EntityIter(usize);

impl Iterator for EntityIter {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        world::with(|w| {
            let &mut EntityIter(ref mut idx) = self;
            loop {
                if *idx >= w.ecs.active.len() { return None; }
                let ret = Entity(*idx);
                *idx += 1;
                if !w.ecs.active[*idx - 1] { continue; }
                return Some(ret);
            }
        })
    }
}

////////////////////////////////////////////////////////////////////////

// The one big macro for defining the full set of available entity components
// in one place.
macro_rules! components {
    {
        // Declare the list of types which are included as components in the
        // game's entity component system. Also declare the non-mutable and
        // mutable accessor names for them. Example
        //
        // ```notrust
        //     [Mesh, meshes, meshes_mut],
        // ```
        $([$comp:ty, $access:ident, $access_mut:ident],)+
    } => {
        // The master container for all the components.
#[derive(RustcEncodable, RustcDecodable)]
        pub struct Comps {
            $($access: HashMap<usize, Option<$comp>>,)+
        }

        /// Container for all regular entity components.
        impl Comps {
            pub fn new() -> Comps {
                Comps {
                    $($access: HashMap::new(),)+
                }
            }

            /// Remove the given entity from all the contained components.
            pub fn remove(&mut self, Entity(idx): Entity) {
                $(self.$access.remove(&idx);)+
            }
        }

        // Implement the Componet trait for the type, this provides an uniform
        // syntax for adding component values to entities used by the entity
        // factory.
        $(
            impl Component for $comp {
                // XXX: Figure out how to move self into the closure to
                // get rid of the .clone.
                fn add_to(self, e: Entity) { world::with_mut(|w| w.$access_mut().insert(e, self.clone())) }
            }
        )+

        // Implement the trait for accessing all the components that
        // WorldState will implement
        pub trait ComponentAccess<'a> {
            $(
            fn $access(&'a self) -> ComponentRef<'a, $comp>;
            fn $access_mut(&'a mut self) -> ComponentRefMut<'a, $comp>;
            )+
        }

        impl<'a> ComponentAccess<'a> for WorldState {
            $(
            fn $access(&'a self) -> ComponentRef<'a, $comp> {
                ComponentRef::new(&self.ecs, &self.comps.$access)
            }
            fn $access_mut(&'a mut self) -> ComponentRefMut<'a, $comp> {
                ComponentRefMut::new(&mut self.ecs, &mut self.comps.$access)
            }
            )+
        }
    }
}

pub trait Component {
    /// Create an uniform syntax for attaching components to entities to allow
    /// a fluent API for constructing prototypes.
    fn add_to(self, e: Entity);
}

// Component loadout for the game.
components! {
    [components::IsPrototype, prototypes, prototypes_mut],
    [components::Desc, descs, descs_mut],
    [components::MapMemory, map_memories, map_memories_mut],
    [stats::Stats, stats, stats_mut],
    [components::Spawn, spawns, spawns_mut],
    [components::Health, healths, healths_mut],
    [components::Brain, brains, brains_mut],
    [components::Item, items, items_mut],
    [components::StatsCache, stats_caches, stats_caches_mut],
}
<commit_msg>Fix typo<commit_after>use std::collections::HashMap;
use super::entity::{Entity};
use super::components;
use super::component_ref::{ComponentRef, ComponentRefMut};
use super::stats;
use super::world::{self, WorldState};

/// Entity component system.
#[derive(RustcDecodable, RustcEncodable)]
pub struct Ecs {
    next_idx: usize,
    reusable_idxs: Vec<usize>,
    // Could use Bitv for active, but I can't bother to write the serializer...
    active: Vec<bool>,
    parent: HashMap<usize, usize>,
}

impl Ecs {
    pub fn new() -> Ecs {
        Ecs {
            next_idx: 0,
            reusable_idxs: vec![],
            active: vec![],
            parent: HashMap::new(),
        }
    }

    pub fn new_entity(&mut self, parent: Option<Entity>) -> Entity {
        // Get the entity idx, reuse old ones to keep the indexing compact.
        let idx = match self.reusable_idxs.pop() {
            None => {
                let ret = self.next_idx;
                self.next_idx += 1;
                ret
            }
            Some(idx) => idx
        };

        if let Some(Entity(p_idx)) = parent {
            assert!(self.active[p_idx]);
            self.parent.insert(idx, p_idx);
        }

        if self.active.len() <= idx {
            self.active.resize(idx + 1, false);
        }
        assert!(!self.active[idx]);
        self.active[idx] = true;

        Entity(idx)
    }

    /// Return whether given entity exists in the system.
    pub fn exists(&self, Entity(idx): Entity) -> bool { self.active[idx] }

    /// Delete an entity from the entity component system.
    ///
    /// XXX: The user is currently responsible for never using an entity
    /// handle again after delete_entity has been called on it. Using an
    /// entity handle after deletion may return another entity's contents.
    pub fn delete(&mut self, Entity(idx): Entity) {
        assert!(self.active[idx]);

        self.parent.remove(&idx);
        self.reusable_idxs.push(idx);
        self.active[idx] = false;
    }

    /// Return an iterator for the entities. The iterator will not be
    /// invalidated if entities are added or removed during iteration. The
    /// iterator also won't maintain a lock on the world singleton outside
    /// calling next.
    ///
    /// XXX: It is currently unspecified whether entities added during
    /// iteration will show up in the iteration or not.
    pub fn iter(&self) -> EntityIter {
        EntityIter(0)
    }

    /// Return the optional parent entity of an entity.
    pub fn parent(&self, Entity(idx): Entity) -> Option<Entity> {
        self.parent.get(&idx).map(|&idx| Entity(idx))
    }

    /// Change the parent of a live entity
    pub fn _reparent(&mut self, Entity(idx): Entity, Entity(new_parent_idx): Entity) {
        self.parent.insert(idx, new_parent_idx);
    }
}

pub struct EntityIter(usize);

impl Iterator for EntityIter {
    type Item = Entity;
    fn next(&mut self) -> Option<Entity> {
        world::with(|w| {
            let &mut EntityIter(ref mut idx) = self;
            loop {
                if *idx >= w.ecs.active.len() { return None; }
                let ret = Entity(*idx);
                *idx += 1;
                if !w.ecs.active[*idx - 1] { continue; }
                return Some(ret);
            }
        })
    }
}

////////////////////////////////////////////////////////////////////////

// The one big macro for defining the full set of available entity components
// in one place.
macro_rules! components {
    {
        // Declare the list of types which are included as components in the
        // game's entity component system. Also declare the non-mutable and
        // mutable accessor names for them. Example
        //
        // ```notrust
        //     [Mesh, meshes, meshes_mut],
        // ```
        $([$comp:ty, $access:ident, $access_mut:ident],)+
    } => {
        // The master container for all the components.
#[derive(RustcEncodable, RustcDecodable)]
        pub struct Comps {
            $($access: HashMap<usize, Option<$comp>>,)+
        }

        /// Container for all regular entity components.
        impl Comps {
            pub fn new() -> Comps {
                Comps {
                    $($access: HashMap::new(),)+
                }
            }

            /// Remove the given entity from all the contained components.
            pub fn remove(&mut self, Entity(idx): Entity) {
                $(self.$access.remove(&idx);)+
            }
        }

        // Implement the Component trait for the type, this provides an uniform
        // syntax for adding component values to entities used by the entity
        // factory.
        $(
            impl Component for $comp {
                // XXX: Figure out how to move self into the closure to
                // get rid of the .clone.
                fn add_to(self, e: Entity) { world::with_mut(|w| w.$access_mut().insert(e, self.clone())) }
            }
        )+

        // Implement the trait for accessing all the components that
        // WorldState will implement
        pub trait ComponentAccess<'a> {
            $(
            fn $access(&'a self) -> ComponentRef<'a, $comp>;
            fn $access_mut(&'a mut self) -> ComponentRefMut<'a, $comp>;
            )+
        }

        impl<'a> ComponentAccess<'a> for WorldState {
            $(
            fn $access(&'a self) -> ComponentRef<'a, $comp> {
                ComponentRef::new(&self.ecs, &self.comps.$access)
            }
            fn $access_mut(&'a mut self) -> ComponentRefMut<'a, $comp> {
                ComponentRefMut::new(&mut self.ecs, &mut self.comps.$access)
            }
            )+
        }
    }
}

pub trait Component {
    /// Create an uniform syntax for attaching components to entities to allow
    /// a fluent API for constructing prototypes.
    fn add_to(self, e: Entity);
}

// Component loadout for the game.
components! {
    [components::IsPrototype, prototypes, prototypes_mut],
    [components::Desc, descs, descs_mut],
    [components::MapMemory, map_memories, map_memories_mut],
    [stats::Stats, stats, stats_mut],
    [components::Spawn, spawns, spawns_mut],
    [components::Health, healths, healths_mut],
    [components::Brain, brains, brains_mut],
    [components::Item, items, items_mut],
    [components::StatsCache, stats_caches, stats_caches_mut],
}
<|endoftext|>


<commit_before>use menu::MenuTree;
use view::MenuPopup;
use view::KeyEventView;
use theme::ColorStyle;
use printer::Printer;
use view::Position;
use event::*;

use std::rc::Rc;

/// Current state of the menubar
#[derive(PartialEq, Debug)]
enum State {
    /// The menubar is inactive.
    Inactive,
    /// The menubar is actively selected.
    ///
    /// It will receive input.
    Selected,
    /// The menubar is still visible, but a submenu is open.
    ///
    /// It will not receive input.
    Submenu,
}

pub struct Menubar {
    pub menus: Vec<(String, Rc<MenuTree>)>,
    pub autohide: bool,
    pub focus: usize,
    state: State,
}

impl Menubar {
    pub fn new() -> Self {
        Menubar {
            menus: Vec::new(),
            autohide: true,
            state: State::Inactive,
            focus: 0,
        }
    }

    pub fn take_focus(&mut self) {
        self.state = State::Selected;
    }

    pub fn receive_events(&self) -> bool {
        self.state == State::Selected
    }

    pub fn visible(&self) -> bool {
        !self.autohide || self.state != State::Inactive
    }

    pub fn add(&mut self, title: &str, menu: MenuTree) -> &mut Self {
        self.menus.push((title.to_string(), Rc::new(menu)));
        self
    }

    pub fn draw(&mut self, printer: &Printer) {
        // Draw the bar at the top
        printer.with_color(ColorStyle::Primary, |printer| {
            printer.print_hline((0, 0), printer.size.x, " ");
        });

        // TODO: draw the rest
        let mut offset = 1;
        for (i, &(ref title, _)) in self.menus.iter().enumerate() {
            // We don't want to show HighlightInactive when we're not selected,
            // because it's ugly on the menubar.
            let selected = (self.state != State::Inactive) &&
                           (i == self.focus);
            printer.with_selection(selected, |printer| {
                printer.print((offset, 0), &format!(" {} ", title));
                offset += title.len() + 2;
            });
        }
    }

    pub fn on_event(&mut self, event: Event) -> Option<Callback> {
        match event {
            Event::Key(Key::Esc) => self.state = State::Inactive,
            Event::Key(Key::Left) => {
                if self.focus > 0 {
                    self.focus -= 1
                } else {
                    self.focus = self.menus.len() - 1
                }
            }
            Event::Key(Key::Right) => {
                if self.focus + 1 < self.menus.len() {
                    self.focus += 1
                } else {
                    self.focus = 0
                }
            }
            Event::Key(Key::Down) |
            Event::Key(Key::Enter) => {
                // First, we need a new Rc to send the callback,
                // since we don't know when it will be called.
                let menu = self.menus[self.focus].1.clone();
                self.state = State::Submenu;
                let offset = (self.menus[..self.focus]
                                  .iter()
                                  .map(|&(ref title, _)| title.len() + 2)
                                  .fold(0, |a, b| a + b),
                              if self.autohide {
                    1
                } else {
                    0
                });
                return Some(Rc::new(move |s| {
                    // Since the closure will be called multiple times,
                    // we also need a new Rc on every call.
                    s.screen_mut()
                     .add_layer_at(Position::absolute(offset),
                                   KeyEventView::new(MenuPopup::new(menu.clone())
                                       .on_dismiss(|s| s.select_menubar())
                                       .on_action(|s| {
                                           s.menubar().state = State::Inactive
                                       }))
                                   .register(Key::Right, |s| {
                                       s.pop_layer();
                                       // Act as if we sent "Left" then "Enter"
                                       s.select_menubar();
                                       s.menubar().on_event(Event::Key(Key::Right));
                                       if let Some(cb) = s.menubar().on_event(Event::Key(Key::Down)) {
                                           cb(s);
                                       }
                                   })
                                   .register(Key::Left, |s| {
                                       s.pop_layer();
                                       // Act as if we sent "Left" then "Enter"
                                       s.select_menubar();
                                       s.menubar().on_event(Event::Key(Key::Left));
                                       if let Some(cb) = s.menubar().on_event(Event::Key(Key::Down)) {
                                           cb(s);
                                       }
                                   }));
                }));
            }
            _ => (),
        }
        None
    }
}
<commit_msg>Add `impl Default for Menubar`<commit_after>use menu::MenuTree;
use view::MenuPopup;
use view::KeyEventView;
use theme::ColorStyle;
use printer::Printer;
use view::Position;
use event::*;

use std::rc::Rc;

/// Current state of the menubar
#[derive(PartialEq, Debug)]
enum State {
    /// The menubar is inactive.
    Inactive,
    /// The menubar is actively selected.
    ///
    /// It will receive input.
    Selected,
    /// The menubar is still visible, but a submenu is open.
    ///
    /// It will not receive input.
    Submenu,
}

pub struct Menubar {
    pub menus: Vec<(String, Rc<MenuTree>)>,
    pub autohide: bool,
    pub focus: usize,
    state: State,
}

impl Default for Menubar {
    fn default() -> Self {
        Self::new()
    }
}

impl Menubar {
    pub fn new() -> Self {
        Menubar {
            menus: Vec::new(),
            autohide: true,
            state: State::Inactive,
            focus: 0,
        }
    }

    pub fn take_focus(&mut self) {
        self.state = State::Selected;
    }

    pub fn receive_events(&self) -> bool {
        self.state == State::Selected
    }

    pub fn visible(&self) -> bool {
        !self.autohide || self.state != State::Inactive
    }

    pub fn add(&mut self, title: &str, menu: MenuTree) -> &mut Self {
        self.menus.push((title.to_string(), Rc::new(menu)));
        self
    }

    pub fn draw(&mut self, printer: &Printer) {
        // Draw the bar at the top
        printer.with_color(ColorStyle::Primary, |printer| {
            printer.print_hline((0, 0), printer.size.x, " ");
        });

        // TODO: draw the rest
        let mut offset = 1;
        for (i, &(ref title, _)) in self.menus.iter().enumerate() {
            // We don't want to show HighlightInactive when we're not selected,
            // because it's ugly on the menubar.
            let selected = (self.state != State::Inactive) &&
                           (i == self.focus);
            printer.with_selection(selected, |printer| {
                printer.print((offset, 0), &format!(" {} ", title));
                offset += title.len() + 2;
            });
        }
    }

    pub fn on_event(&mut self, event: Event) -> Option<Callback> {
        match event {
            Event::Key(Key::Esc) => self.state = State::Inactive,
            Event::Key(Key::Left) => {
                if self.focus > 0 {
                    self.focus -= 1
                } else {
                    self.focus = self.menus.len() - 1
                }
            }
            Event::Key(Key::Right) => {
                if self.focus + 1 < self.menus.len() {
                    self.focus += 1
                } else {
                    self.focus = 0
                }
            }
            Event::Key(Key::Down) |
            Event::Key(Key::Enter) => {
                // First, we need a new Rc to send the callback,
                // since we don't know when it will be called.
                let menu = self.menus[self.focus].1.clone();
                self.state = State::Submenu;
                let offset = (self.menus[..self.focus]
                                  .iter()
                                  .map(|&(ref title, _)| title.len() + 2)
                                  .fold(0, |a, b| a + b),
                              if self.autohide {
                    1
                } else {
                    0
                });
                return Some(Rc::new(move |s| {
                    // Since the closure will be called multiple times,
                    // we also need a new Rc on every call.
                    s.screen_mut()
                     .add_layer_at(Position::absolute(offset),
                                   KeyEventView::new(MenuPopup::new(menu.clone())
                                       .on_dismiss(|s| s.select_menubar())
                                       .on_action(|s| {
                                           s.menubar().state = State::Inactive
                                       }))
                                   .register(Key::Right, |s| {
                                       s.pop_layer();
                                       // Act as if we sent "Left" then "Enter"
                                       s.select_menubar();
                                       s.menubar().on_event(Event::Key(Key::Right));
                                       if let Some(cb) = s.menubar().on_event(Event::Key(Key::Down)) {
                                           cb(s);
                                       }
                                   })
                                   .register(Key::Left, |s| {
                                       s.pop_layer();
                                       // Act as if we sent "Left" then "Enter"
                                       s.select_menubar();
                                       s.menubar().on_event(Event::Key(Key::Left));
                                       if let Some(cb) = s.menubar().on_event(Event::Key(Key::Down)) {
                                           cb(s);
                                       }
                                   }));
                }));
            }
            _ => (),
        }
        None
    }
}
<|endoftext|>


<commit_before>//! Generic message handling.
//!
//! This module provides the ability to read SBD messages from and write SBD messages to streams.

use std::fs::File;
use std::io::Read;
use std::path::Path;

use byteorder::{ReadBytesExt, BigEndian};

use {Error, Result};
use information_element::InformationElement;

/// An SBD message.
#[derive(Debug, Default)]
pub struct Message {
    protocol_revision_number: u8,
    overall_message_length: u16,
    information_elements: Vec<InformationElement>,
}

impl Message {

    /// Reads in a message from a file path.
    ///
    /// # Examples
    ///
    /// ```
    /// use sbd::message::Message;
    /// let message = Message::from_path("data/0-mo.sbd").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Message> {
        let file = try!(File::open(path));
        Message::read_from(file)
    }

    /// Reads in a message from an object that implements `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use sbd::message::Message;
    /// let mut file = File::open("data/0-mo.sbd").unwrap();
    /// let message = Message::read_from(file).unwrap();
    pub fn read_from<R: Read>(mut readable: R) -> Result<Message> {
        let mut message: Message = Default::default();
        message.protocol_revision_number = try!(readable.read_u8());
        if message.protocol_revision_number != 1 {
            return Err(Error::InvalidProtocolRevisionNumber(message.protocol_revision_number));
        }
        Ok(message)
    }
}

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

    use std::fs::File;

    #[test]
    fn from_path() {
        Message::from_path("data/0-mo.sbd").unwrap();
    }

    #[test]
    fn from_read() {
        let file = File::open("data/0-mo.sbd").unwrap();
        Message::read_from(file).unwrap();
    }

    #[test]
    fn from_path_that_doesnt_exist() {
        assert!(Message::from_path("notafile.sbd").is_err());
    }

    #[test]
    fn from_path_that_is_not_an_sbd_message() {
        assert!(Message::from_path("data/1-invalid.sbd").is_err());
    }
}
<commit_msg>Add len() method to message<commit_after>//! Generic message handling.
//!
//! This module provides the ability to read SBD messages from and write SBD messages to streams.

use std::fs::File;
use std::io::Read;
use std::path::Path;

use byteorder::{ReadBytesExt, BigEndian};

use {Error, Result};
use information_element::InformationElement;

/// An SBD message.
#[derive(Debug, Default)]
pub struct Message {
    protocol_revision_number: u8,
    overall_message_length: u16,
    information_elements: Vec<InformationElement>,
}

impl Message {

    /// Reads in a message from a file path.
    ///
    /// # Examples
    ///
    /// ```
    /// use sbd::message::Message;
    /// let message = Message::from_path("data/0-mo.sbd").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Message> {
        let file = try!(File::open(path));
        Message::read_from(file)
    }

    /// Reads in a message from an object that implements `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use sbd::message::Message;
    /// let mut file = File::open("data/0-mo.sbd").unwrap();
    /// let message = Message::read_from(file).unwrap();
    pub fn read_from<R: Read>(mut readable: R) -> Result<Message> {
        let mut message: Message = Default::default();
        message.protocol_revision_number = try!(readable.read_u8());
        message.overall_message_length = try!(readable.read_u16::<BigEndian>());
        if message.protocol_revision_number != 1 {
            return Err(Error::InvalidProtocolRevisionNumber(message.protocol_revision_number));
        }
        Ok(message)
    }

    /// Returns the overall message length of the SBD message.
    ///
    /// This value *includes* the initial three bytes, whereas the `overall_message_length`
    /// value in the SBD header does *not* include those bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// use sbd::message::Message;
    /// let message = Message::from_path("data/0-mo.sbd").unwrap();
    /// assert_eq!(59, message.len());
    /// ```
    pub fn len(&self) -> usize {
        self.overall_message_length as usize + 3
    }
}

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

    use std::fs::File;

    #[test]
    fn from_path() {
        Message::from_path("data/0-mo.sbd").unwrap();
    }

    #[test]
    fn from_read() {
        let file = File::open("data/0-mo.sbd").unwrap();
        Message::read_from(file).unwrap();
    }

    #[test]
    fn from_path_that_doesnt_exist() {
        assert!(Message::from_path("notafile.sbd").is_err());
    }

    #[test]
    fn from_path_that_is_not_an_sbd_message() {
        assert!(Message::from_path("data/1-invalid.sbd").is_err());
    }

    #[test]
    fn len() {
        let message = Message::from_path("data/0-mo.sbd").unwrap();
        assert_eq!(59, message.len());
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::File;

use command::command::{
    Attribute,
    Envelope,
    Flags,
    InternalDate,
    RFC822,
    Body,
    BodyPeek,
    BodyStructure,
    UID
};
use command::command::{
    AllRFC822,
    HeaderRFC822,
    SizeRFC822,
    TextRFC822
};
use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    pub path: String,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    pub deleted: bool,
    size: uint,
    raw_contents: String,
    raw_header: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(arg_path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(arg_path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();
        let size = raw_contents.as_slice().len();

        let mut path = arg_path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let path_flags = path.next();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.
        let flags = match path_flags {
            None => Vec::new(),
            Some(flags) => {
                let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
                let mut vec_flags: Vec<Flag> = Vec::new();
                for flag in unparsed_flags.chars() {
                    let parsed_flag = match flag {
                        'D' => Some(Draft),
                        'F' => Some(Flagged),
                        'R' => Some(Answered),
                        'S' => Some(Seen),
                        _ => None
                    };
                    match parsed_flag {
                        Some(enum_flag) => vec_flags.push(enum_flag),
                        None => { }
                    }
                }
                vec_flags
            }
        };

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].clone().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"Received".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["Content-Type".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            path: arg_path.display().to_string(),
            headers: headers,
            body: body,
            flags: flags,
            deleted: false,
            size: size,
            raw_contents: raw_contents.clone(),
            raw_header: raw_header.to_string()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }

    pub fn fetch(&self, attributes: &Vec<Attribute>) -> String {
        let mut res = String::new();
        for attr in attributes.iter() {
            let attr_str = match attr {
                &Envelope => { "".to_string() },
                &Flags => { "".to_string() },
                &InternalDate => { "".to_string() },
                &RFC822(ref attr) => {
                    let rfc_attr = match attr {
                        &AllRFC822 => { "".to_string() },
                        &HeaderRFC822 => { format!(".HEADER {{{}}}\n{}", self.raw_header.len(), self.raw_header) },
                        &SizeRFC822 => { format!(".SIZE {}", self.size) },
                        &TextRFC822 => { "".to_string() }
                    };
                    format!("RFC822{}", rfc_attr)
                },
                &Body(ref section, ref octets) => { "".to_string() },
                &BodyPeek(ref section, ref octets) => { "".to_string() },
                &BodyStructure => { "".to_string() },
                &UID => { "".to_string() }
            };
            res = format!("{} {}", res, attr_str);
        }
        res
    }
}
<commit_msg>Work on FETCH ENVELOPE<commit_after>use std::ascii::OwnedAsciiExt;
use std::collections::HashMap;
use std::io::File;

use command::command::{
    Attribute,
    Envelope,
    Flags,
    InternalDate,
    RFC822,
    Body,
    BodyPeek,
    BodyStructure,
    UID
};
use command::command::{
    AllRFC822,
    HeaderRFC822,
    SizeRFC822,
    TextRFC822
};
use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    pub path: String,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    pub deleted: bool,
    size: uint,
    raw_contents: String,
    raw_header: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(arg_path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(arg_path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();
        let size = raw_contents.as_slice().len();

        let mut path = arg_path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let path_flags = path.next();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.
        let flags = match path_flags {
            None => Vec::new(),
            Some(flags) => {
                let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
                let mut vec_flags: Vec<Flag> = Vec::new();
                for flag in unparsed_flags.chars() {
                    let parsed_flag = match flag {
                        'D' => Some(Draft),
                        'F' => Some(Flagged),
                        'R' => Some(Answered),
                        'S' => Some(Seen),
                        _ => None
                    };
                    match parsed_flag {
                        Some(enum_flag) => vec_flags.push(enum_flag),
                        None => { }
                    }
                }
                vec_flags
            }
        };

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].to_string().into_ascii_upper().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"RECEIVED".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["CONTENT-TYPE".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            path: arg_path.display().to_string(),
            headers: headers,
            body: body,
            flags: flags,
            deleted: false,
            size: size,
            raw_contents: raw_contents.clone(),
            raw_header: raw_header.to_string()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }

    pub fn fetch(&self, attributes: &Vec<Attribute>) -> String {
        let mut res = String::new();
        for attr in attributes.iter() {
            let attr_str = match attr {
                &Envelope => { format!("ENVELOPE {}", self.get_envelope()) },
                &Flags => { "".to_string() },
                &InternalDate => { "".to_string() },
                &RFC822(ref attr) => {
                    let rfc_attr = match attr {
                        &AllRFC822 => { "".to_string() },
                        &HeaderRFC822 => { format!(".HEADER {{{}}}\n{}", self.raw_header.len(), self.raw_header) },
                        &SizeRFC822 => { format!(".SIZE {}", self.size) },
                        &TextRFC822 => { "".to_string() }
                    };
                    format!("RFC822{}", rfc_attr)
                },
                &Body(ref section, ref octets) => { "".to_string() },
                &BodyPeek(ref section, ref octets) => { "".to_string() },
                &BodyStructure => { "".to_string() },
                &UID => { "".to_string() }
            };
            res = format!("{} {}", res, attr_str);
        }
        res
    }

    /**
     * RFC3501 - 7.4.2 - P.76-77
     *
     * Returns a parenthesized list that described the envelope structure of a
     * message.
     * Computed by parsing the [RFC-2822] header into the component parts,
     * defaulting various fields as necessary.
     *
     * Requires (in the following order): date, subject, from, sender, reply-to,
     * to, cc, bcc, in-reply-to, and message-id.
     * The date, subject, in-reply-to, and message-id fields are strings.
     * The from, sender, reply-to, to, cc, and bcc fields are parenthesized
     * lists of address structures.
     */
    fn get_envelope(&self) -> String {
        let date = self.get_quoted_field_or_nil("DATE".to_string());
        let subject = self.get_quoted_field_or_nil("SUBJECT".to_string());
        let from = self.get_parenthesized_addresses("FROM".to_string());
        let sender = self.get_parenthesized_addresses("SENDER".to_string());
        let reply_to = self.get_parenthesized_addresses("REPLY-TO".to_string());
        let to = self.get_parenthesized_addresses("TO".to_string());
        let cc = self.get_parenthesized_addresses("CC".to_string());
        let bcc = self.get_parenthesized_addresses("BCC".to_string());
        let in_reply_to = self.get_quoted_field_or_nil("IN-REPLY-TO".to_string());
        let message_id = self.get_quoted_field_or_nil("MESSAGE-ID".to_string());

        format!(
            "({} {} {} {} {} {} {} {} {} {})",
            date,
            subject,
            from,
            sender,
            reply_to,
            to,
            cc,
            bcc,
            in_reply_to,
            message_id)
    }

    fn get_quoted_field_or_nil(&self, key: String) -> String {
        match self.headers.find(&key) {
            Some(v) => format!("\"{}\"", v),
            None => "NIL".to_string()
        }
    }

    fn get_parenthesized_addresses(&self, key: String) -> String {
        let addresses = match self.headers.find(&key) {
            Some(v) => v,
            None => return "NIL".to_string()
        };

        "NIL".to_string()
    }
}
<|endoftext|>


<commit_before>//! All keys in leveldb are compared by their binary value unless
//! defined otherwise.
//!
//! Comparators allow to override this comparison.
//! The ordering of keys introduced by the compartor influences iteration order.
//! Databases written with one Comparator cannot be opened with another.
use leveldb_sys::*;
use libc::{size_t, c_void, c_char};
use libc;
use std::mem;
use std::slice;
use std::cmp::Ordering;
use database::key::Key;
use database::key::from_u8;
use std::marker::PhantomData;

/// A comparator has two important functions:
///
/// * the name function returns a fixed name to detect errors when
///   opening databases with a different name
/// * The comparison implementation
pub trait Comparator {
    /// The type that the comparator compares.
    type K: Key;

    /// Return the name of the Comparator
    fn name(&self) -> *const c_char;
    /// compare two keys. This must implement a total ordering.
    fn compare(&self, a: &Self::K, b: &Self::K) -> Ordering;
    /// whether the comparator is the `DefaultComparator`
    fn null() -> bool {
        false
    }
}

/// OrdComparator is a comparator comparing Keys that implement `Ord`
pub struct OrdComparator<K: Key + Ord> {
    name: String,
    marker: PhantomData<K>,
}

impl<K: Key + Ord> OrdComparator<K> {
    /// Create a new OrdComparator
    pub fn new(name: &str) -> OrdComparator<K> {
        OrdComparator {
            marker: PhantomData,
            name: name.to_string(),
        }
    }
}

/// DefaultComparator is the a stand in for "no comparator set"
#[derive(Copy,Clone)]
pub struct DefaultComparator;

trait InternalComparator : Comparator where Self: Sized {

    extern "C" fn name(state: *mut c_void) -> *const c_char {
        let x: &Self = unsafe { &*(state as *mut Self) };
        x.name()
    }

    extern "C" fn compare(state: *mut c_void,
                          a: *const i8,
                          a_len: size_t,
                          b: *const i8,
                          b_len: size_t)
                          -> i32 {
        unsafe {
            let a_slice = slice::from_raw_parts::<u8>(a as *const u8, a_len as usize);
            let b_slice = slice::from_raw_parts::<u8>(b as *const u8, b_len as usize);
            let x: &Self = &*(state as *mut Self);
            let a_key = from_u8::<<Self as Comparator>::K>(a_slice);
            let b_key = from_u8::<<Self as Comparator>::K>(b_slice);
            match x.compare(&a_key, &b_key) {
                Ordering::Less => -1,
                Ordering::Equal => 0,
                Ordering::Greater => 1,
            }
        }
    }

    extern "C" fn destructor(state: *mut c_void) {
        let _x: Box<Self> = unsafe { mem::transmute(state) };
         // let the Box fall out of scope and run the T's destructor
    }
}

impl<C: Comparator> InternalComparator for C {}

#[allow(missing_docs)]
pub fn create_comparator<K: Key, T: Comparator<K = K>>(x: Box<T>) -> *mut leveldb_comparator_t {
    unsafe {
        leveldb_comparator_create(mem::transmute(x),
                                  <T as InternalComparator>::destructor,
                                  <T as InternalComparator>::compare,
                                  <T as InternalComparator>::name)
    }
}

impl<K: Key + Ord> Comparator for OrdComparator<K> {
  type K = K;

    fn name(&self) -> *const c_char {
        let slice: &str = self.name.as_ref();
        slice.as_ptr() as *const c_char
    }

    fn compare(&self, a: &K, b: &K) -> Ordering {
        a.cmp(b)
    }
}

impl Comparator for DefaultComparator {
  type K = i32;

    fn name(&self) -> *const c_char {
        "default_comparator".as_ptr() as *const c_char
    }

    fn compare(&self, _a: &i32, _b: &i32) -> Ordering {
        Ordering::Equal
    }

    fn null() -> bool {
        true
    }
}
<commit_msg>Mark internal comparator unsafe<commit_after>//! All keys in leveldb are compared by their binary value unless
//! defined otherwise.
//!
//! Comparators allow to override this comparison.
//! The ordering of keys introduced by the compartor influences iteration order.
//! Databases written with one Comparator cannot be opened with another.
use leveldb_sys::*;
use libc::{size_t, c_void, c_char};
use libc;
use std::mem;
use std::slice;
use std::cmp::Ordering;
use database::key::Key;
use database::key::from_u8;
use std::marker::PhantomData;

/// A comparator has two important functions:
///
/// * the name function returns a fixed name to detect errors when
///   opening databases with a different name
/// * The comparison implementation
pub trait Comparator {
    /// The type that the comparator compares.
    type K: Key;

    /// Return the name of the Comparator
    fn name(&self) -> *const c_char;
    /// compare two keys. This must implement a total ordering.
    fn compare(&self, a: &Self::K, b: &Self::K) -> Ordering;
    /// whether the comparator is the `DefaultComparator`
    fn null() -> bool {
        false
    }
}

/// OrdComparator is a comparator comparing Keys that implement `Ord`
pub struct OrdComparator<K: Key + Ord> {
    name: String,
    marker: PhantomData<K>,
}

impl<K: Key + Ord> OrdComparator<K> {
    /// Create a new OrdComparator
    pub fn new(name: &str) -> OrdComparator<K> {
        OrdComparator {
            marker: PhantomData,
            name: name.to_string(),
        }
    }
}

/// DefaultComparator is the a stand in for "no comparator set"
#[derive(Copy,Clone)]
pub struct DefaultComparator;

unsafe trait InternalComparator : Comparator where Self: Sized {

    extern "C" fn name(state: *mut c_void) -> *const c_char {
        let x: &Self = unsafe { &*(state as *mut Self) };
        x.name()
    }

    extern "C" fn compare(state: *mut c_void,
                          a: *const i8,
                          a_len: size_t,
                          b: *const i8,
                          b_len: size_t)
                          -> i32 {
        unsafe {
            let a_slice = slice::from_raw_parts::<u8>(a as *const u8, a_len as usize);
            let b_slice = slice::from_raw_parts::<u8>(b as *const u8, b_len as usize);
            let x: &Self = &*(state as *mut Self);
            let a_key = from_u8::<<Self as Comparator>::K>(a_slice);
            let b_key = from_u8::<<Self as Comparator>::K>(b_slice);
            match x.compare(&a_key, &b_key) {
                Ordering::Less => -1,
                Ordering::Equal => 0,
                Ordering::Greater => 1,
            }
        }
    }

    extern "C" fn destructor(state: *mut c_void) {
        let _x: Box<Self> = unsafe { mem::transmute(state) };
         // let the Box fall out of scope and run the T's destructor
    }
}

unsafe impl<C: Comparator> InternalComparator for C {}

#[allow(missing_docs)]
pub fn create_comparator<K: Key, T: Comparator<K = K>>(x: Box<T>) -> *mut leveldb_comparator_t {
    unsafe {
        leveldb_comparator_create(mem::transmute(x),
                                  <T as InternalComparator>::destructor,
                                  <T as InternalComparator>::compare,
                                  <T as InternalComparator>::name)
    }
}

impl<K: Key + Ord> Comparator for OrdComparator<K> {
  type K = K;

    fn name(&self) -> *const c_char {
        let slice: &str = self.name.as_ref();
        slice.as_ptr() as *const c_char
    }

    fn compare(&self, a: &K, b: &K) -> Ordering {
        a.cmp(b)
    }
}

impl Comparator for DefaultComparator {
  type K = i32;

    fn name(&self) -> *const c_char {
        "default_comparator".as_ptr() as *const c_char
    }

    fn compare(&self, _a: &i32, _b: &i32) -> Ordering {
        Ordering::Equal
    }

    fn null() -> bool {
        true
    }
}
<|endoftext|>


<commit_before>use super::RawOutcome;
use crate::core::{FilterList, LowercaseText};
use crate::utils::is_stop_char;
use crate::{Lang, Script};

use once_cell::sync::Lazy;
use std::collections::HashMap;

const AFR: &str = "abcdefghijklmnopqrstuvwxyzáèéêëíîïóôúû";
const AKA: &str = "abdefghiklmnoprstuwyɔɛ";
const AZE: &str = "abcdefghijklmnopqrstuvxyzçöüğışə̇";
const CAT: &str = "abcdefghijklmnopqrstuvwxyz·àçèéíïòóúü";
const CES: &str = "abcdefghijklmnopqrstuvwxyzáéóúýčďěňřšťůž";
const DAN: &str = "abcdefghijklmnopqrstuvwxyzåæø";
const DEU: &str = "abcdefghijklmnopqrstuvwxyzßäöü";
const ENG: &str = "abcdefghijklmnopqrstuvwxyz";
const EPO: &str = "abcdefghijklmnoprstuvzĉĝĥĵŝŭ";
const EST: &str = "abcdefghijklmnopqrstuvwxyzäõöü";
const FIN: &str = "abcdefghijklmnopqrstuvwxyzäöšž";
const FRA: &str = "abcdefghijklmnopqrstuvwxyzàâçèéêëîïôùûüÿœ";
const HRV: &str = "abcdefghijklmnopqrstuvwxyzćčđšž";
const HUN: &str = "abcdefghijklmnopqrstuvwxyzáéíóöúüőű";
const IND: &str = "abcdefghijklmnopqrstuvwxyz";
const ITA: &str = "abcdefghijklmnopqrstuvwxyzàèéìòù";
const JAV: &str = "abcdefghijklmnopqrstuvwxyzèé";
const LAT: &str = "abcdefghijklmnopqrstuvwxyz";
const LAV: &str = "abcdefghijklmnopqrstuvwxyzāčēģīķļņōŗšūž";
const LIT: &str = "abcdefghijklmnopqrstuvwxyząčėęįšūųž";
const NLD: &str = "abcdefghijklmnopqrstuvwxyzàèéëïĳ";
const NOB: &str = "abcdefghijklmnopqrstuvwxyzåæø";
const POL: &str = "abcdefghijklmnopqrstuvwxyzóąćęłńśźż";
const POR: &str = "abcdefghijklmnopqrstuvwxyzàáâãçéêíóôõú";
const RON: &str = "abcdefghijklmnopqrstuvwxyzâîăşţ";
const SLK: &str = "abcdefghijklmnopqrstuvwxyzáäéíóôúýčďĺľňŕšťž";
const SLV: &str = "abcdefghijklmnopqrstuvwxyzčšž";
const SNA: &str = "abcdefghijklmnopqrstuvwxyz";
const SPA: &str = "abcdefghijklmnopqrstuvwxyz¡¿áéíñóúü";
const SWE: &str = "abcdefghijklmnopqrstuvwxyzäåö";
const TGL: &str = "abcdefghijklmnopqrstuvwxyzáéíñóú";
const TUK: &str = "abdefghijklmnoprstuwyzäçöüýňşž";
const TUR: &str = "abcdefghijklmnopqrstuvwxyzçöüğış̇";
const UZB: &str = "abcdefghijklmnopqrstuvxyzʻ";
const VIE: &str =
    "abcdefghijklmnopqrstuvwxyzàáâãèéêìíòóôõùúýăđĩũơưạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ";
const ZUL: &str = "abcdefghijklmnopqrstuvwxyz";

const LATIN_ALPHABETS: &[(Lang, &str)] = &[
    (Lang::Afr, AFR),
    (Lang::Aka, AKA),
    (Lang::Aze, AZE),
    (Lang::Cat, CAT),
    (Lang::Ces, CES),
    (Lang::Dan, DAN),
    (Lang::Deu, DEU),
    (Lang::Eng, ENG),
    (Lang::Epo, EPO),
    (Lang::Est, EST),
    (Lang::Fin, FIN),
    (Lang::Fra, FRA),
    (Lang::Hrv, HRV),
    (Lang::Hun, HUN),
    (Lang::Ind, IND),
    (Lang::Ita, ITA),
    (Lang::Jav, JAV),
    (Lang::Lat, LAT),
    (Lang::Lav, LAV),
    (Lang::Lit, LIT),
    (Lang::Nld, NLD),
    (Lang::Nob, NOB),
    (Lang::Pol, POL),
    (Lang::Por, POR),
    (Lang::Ron, RON),
    (Lang::Slk, SLK),
    (Lang::Slv, SLV),
    (Lang::Sna, SNA),
    (Lang::Spa, SPA),
    (Lang::Swe, SWE),
    (Lang::Tgl, TGL),
    (Lang::Tuk, TUK),
    (Lang::Tur, TUR),
    (Lang::Uzb, UZB),
    (Lang::Vie, VIE),
    (Lang::Zul, ZUL),
];

/// Inverted map binding a character to a set of languages.
pub static ALPHABET_LANG_MAP: Lazy<Vec<(char, Vec<Lang>)>> = Lazy::new(|| {
    let mut map = HashMap::new();

    for (lang, alphabet) in LATIN_ALPHABETS {
        for c in alphabet.chars() {
            let entry = map.entry(c).or_insert_with(Vec::new);
            entry.push(*lang);
        }
    }

    let mut char_lang = Vec::new();

    for (ch, languages) in map {
        char_lang.push((ch, languages));
    }

    char_lang
});

pub fn alphabet_calculate_scores(text: &LowercaseText, filter_list: &FilterList) -> RawOutcome {
    let char_lang = &*ALPHABET_LANG_MAP;
    let max_raw_score = text.chars().filter(|&ch| !is_stop_char(ch)).count();

    let mut raw_scores: Vec<(Lang, i32)> = Script::Latin
        .langs()
        .iter()
        .filter(|&&l| filter_list.is_allowed(l))
        .map(|&l| (l, 0i32 - max_raw_score as i32))
        .collect();

    for ch in text.chars() {
        if is_stop_char(ch) {
            continue;
        }

        if let Some((_, languages)) = char_lang.iter().find(|(c, _)| *c == ch) {
            for lang in languages {
                if let Some((_, score)) = raw_scores.iter_mut().find(|(l, _)| l == lang) {
                    *score += 2;
                }
            }
        }
    }

    raw_scores.sort_unstable_by(|a, b| b.1.cmp(&a.1));

    let raw_scores: Vec<(Lang, usize)> = raw_scores
        .into_iter()
        .map(|(l, s)| {
            let score = if s < 0 { 0usize } else { s as usize };
            (l, score)
        })
        .collect();

    let mut normalized_scores = vec![];

    for &(lang, raw_score) in &raw_scores {
        let normalized_score = raw_score as f64 / max_raw_score as f64;
        normalized_scores.push((lang, normalized_score));
    }

    RawOutcome {
        count: max_raw_score,
        raw_scores,
        scores: normalized_scores,
    }
}
<commit_msg>Clamp score in normalization loop instead of creating intermediate vec<commit_after>use super::RawOutcome;
use crate::core::{FilterList, LowercaseText};
use crate::utils::is_stop_char;
use crate::{Lang, Script};

use once_cell::sync::Lazy;
use std::collections::HashMap;

const AFR: &str = "abcdefghijklmnopqrstuvwxyzáèéêëíîïóôúû";
const AKA: &str = "abdefghiklmnoprstuwyɔɛ";
const AZE: &str = "abcdefghijklmnopqrstuvxyzçöüğışə̇";
const CAT: &str = "abcdefghijklmnopqrstuvwxyz·àçèéíïòóúü";
const CES: &str = "abcdefghijklmnopqrstuvwxyzáéóúýčďěňřšťůž";
const DAN: &str = "abcdefghijklmnopqrstuvwxyzåæø";
const DEU: &str = "abcdefghijklmnopqrstuvwxyzßäöü";
const ENG: &str = "abcdefghijklmnopqrstuvwxyz";
const EPO: &str = "abcdefghijklmnoprstuvzĉĝĥĵŝŭ";
const EST: &str = "abcdefghijklmnopqrstuvwxyzäõöü";
const FIN: &str = "abcdefghijklmnopqrstuvwxyzäöšž";
const FRA: &str = "abcdefghijklmnopqrstuvwxyzàâçèéêëîïôùûüÿœ";
const HRV: &str = "abcdefghijklmnopqrstuvwxyzćčđšž";
const HUN: &str = "abcdefghijklmnopqrstuvwxyzáéíóöúüőű";
const IND: &str = "abcdefghijklmnopqrstuvwxyz";
const ITA: &str = "abcdefghijklmnopqrstuvwxyzàèéìòù";
const JAV: &str = "abcdefghijklmnopqrstuvwxyzèé";
const LAT: &str = "abcdefghijklmnopqrstuvwxyz";
const LAV: &str = "abcdefghijklmnopqrstuvwxyzāčēģīķļņōŗšūž";
const LIT: &str = "abcdefghijklmnopqrstuvwxyząčėęįšūųž";
const NLD: &str = "abcdefghijklmnopqrstuvwxyzàèéëïĳ";
const NOB: &str = "abcdefghijklmnopqrstuvwxyzåæø";
const POL: &str = "abcdefghijklmnopqrstuvwxyzóąćęłńśźż";
const POR: &str = "abcdefghijklmnopqrstuvwxyzàáâãçéêíóôõú";
const RON: &str = "abcdefghijklmnopqrstuvwxyzâîăşţ";
const SLK: &str = "abcdefghijklmnopqrstuvwxyzáäéíóôúýčďĺľňŕšťž";
const SLV: &str = "abcdefghijklmnopqrstuvwxyzčšž";
const SNA: &str = "abcdefghijklmnopqrstuvwxyz";
const SPA: &str = "abcdefghijklmnopqrstuvwxyz¡¿áéíñóúü";
const SWE: &str = "abcdefghijklmnopqrstuvwxyzäåö";
const TGL: &str = "abcdefghijklmnopqrstuvwxyzáéíñóú";
const TUK: &str = "abdefghijklmnoprstuwyzäçöüýňşž";
const TUR: &str = "abcdefghijklmnopqrstuvwxyzçöüğış̇";
const UZB: &str = "abcdefghijklmnopqrstuvxyzʻ";
const VIE: &str =
    "abcdefghijklmnopqrstuvwxyzàáâãèéêìíòóôõùúýăđĩũơưạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ";
const ZUL: &str = "abcdefghijklmnopqrstuvwxyz";

const LATIN_ALPHABETS: &[(Lang, &str)] = &[
    (Lang::Afr, AFR),
    (Lang::Aka, AKA),
    (Lang::Aze, AZE),
    (Lang::Cat, CAT),
    (Lang::Ces, CES),
    (Lang::Dan, DAN),
    (Lang::Deu, DEU),
    (Lang::Eng, ENG),
    (Lang::Epo, EPO),
    (Lang::Est, EST),
    (Lang::Fin, FIN),
    (Lang::Fra, FRA),
    (Lang::Hrv, HRV),
    (Lang::Hun, HUN),
    (Lang::Ind, IND),
    (Lang::Ita, ITA),
    (Lang::Jav, JAV),
    (Lang::Lat, LAT),
    (Lang::Lav, LAV),
    (Lang::Lit, LIT),
    (Lang::Nld, NLD),
    (Lang::Nob, NOB),
    (Lang::Pol, POL),
    (Lang::Por, POR),
    (Lang::Ron, RON),
    (Lang::Slk, SLK),
    (Lang::Slv, SLV),
    (Lang::Sna, SNA),
    (Lang::Spa, SPA),
    (Lang::Swe, SWE),
    (Lang::Tgl, TGL),
    (Lang::Tuk, TUK),
    (Lang::Tur, TUR),
    (Lang::Uzb, UZB),
    (Lang::Vie, VIE),
    (Lang::Zul, ZUL),
];

/// Inverted map binding a character to a set of languages.
pub static ALPHABET_LANG_MAP: Lazy<Vec<(char, Vec<Lang>)>> = Lazy::new(|| {
    let mut map = HashMap::new();

    for (lang, alphabet) in LATIN_ALPHABETS {
        for c in alphabet.chars() {
            let entry = map.entry(c).or_insert_with(Vec::new);
            entry.push(*lang);
        }
    }

    let mut char_lang = Vec::new();

    for (ch, languages) in map {
        char_lang.push((ch, languages));
    }

    char_lang
});

pub fn alphabet_calculate_scores(text: &LowercaseText, filter_list: &FilterList) -> RawOutcome {
    let char_lang = &*ALPHABET_LANG_MAP;
    let max_raw_score = text.chars().filter(|&ch| !is_stop_char(ch)).count();

    let mut raw_scores: Vec<(Lang, usize)> = Script::Latin
        .langs()
        .iter()
        .filter(|&&l| filter_list.is_allowed(l))
        .map(|&l| (l, 0))
        .collect();

    for ch in text.chars() {
        if is_stop_char(ch) {
            continue;
        }

        if let Some((_, languages)) = char_lang.iter().find(|(c, _)| *c == ch) {
            for lang in languages {
                if let Some((_, score)) = raw_scores.iter_mut().find(|(l, _)| l == lang) {
                    *score += 2;
                }
            }
        }
    }

    raw_scores.sort_unstable_by(|a, b| b.1.cmp(&a.1));

    let mut normalized_scores = vec![];

    for &(lang, raw_score) in &raw_scores {
        let normalized_score =
            raw_score.saturating_sub(max_raw_score) as f64 / max_raw_score as f64;
        normalized_scores.push((lang, normalized_score));
    }

    RawOutcome {
        count: max_raw_score,
        raw_scores,
        scores: normalized_scores,
    }
}
<|endoftext|>


<commit_before>use env::Env;
use gobjects::*;
use library;
use nameutil::*;
use super::*;
use super::type_kind::*;

pub struct Info {
    pub full_name: String,
    pub class_tid: library::TypeId,
    pub kind: type_kind::TypeKind,
    pub name: String,
    pub parents: Vec<general::StatusedTypeId>,
    pub has_children: bool,
    pub has_ignored_parents: bool,
    pub functions: Vec<functions::Info>,
    pub has_constructors: bool,
    pub has_methods: bool,
}

impl Info {
    //TODO: add test in tests/ for panic
    pub fn type_<'a>(&self, library: &'a library::Library) -> &'a library::Class {
        let type_ = library.type_(self.class_tid).as_class()
            .unwrap_or_else(|| panic!("{} is not a class.", self.full_name));
        type_
    }

    ///TODO: return iterator
    pub fn constructors(&self) -> Vec<&functions::Info> {
        self.functions.iter()
            .filter(|f| f.kind == library::FunctionKind::Constructor)
            .collect()
    }

    pub fn methods(&self) -> Vec<&functions::Info> {
        self.functions.iter()
            .filter(|f| f.kind == library::FunctionKind::Method)
            .collect()
    }
}

pub fn new(env: &Env, obj: &GObject) -> Info {
    let full_name = obj.name.clone();

    let class_tid = env.library.find_type_unwrapped(0, &full_name, "Class");

    let type_ = env.library.type_(class_tid);
    let kind = type_.to_type_kind(&env.library);
    assert_eq!(kind, TypeKind::Widget);

    let name = split_namespace_name(&full_name).1.into();

    let klass = type_.to_class();
    let (parents, has_ignored_parents) = parents::analyze(env, klass);

    let has_children = klass.has_children;

    let functions = functions::analyze(env, klass, class_tid);

    let has_constructors = functions.iter().find(|f| f.kind == library::FunctionKind::Constructor).is_some();
    let has_methods = functions.iter().find(|f| f.kind == library::FunctionKind::Method).is_some();

    let has_functions = functions.iter().find(|f| f.kind == library::FunctionKind::Function).is_some();
    assert!(!has_functions, "Widget {} has functions, to do functions code generation", full_name);

    Info {
        full_name: full_name,
        class_tid: class_tid,
        kind: kind,
        name: name,
        parents: parents,
        has_children: has_children,
        has_ignored_parents: has_ignored_parents,
        functions: functions,
        has_constructors: has_constructors,
        has_methods: has_methods,
    }
}
<commit_msg>Refactoring widget analysis to use `constructors` and `methods`<commit_after>use env::Env;
use gobjects::*;
use library;
use nameutil::*;
use super::*;
use super::type_kind::*;

#[derive(Default)]
pub struct Info {
    pub full_name: String,
    pub class_tid: library::TypeId,
    pub kind: type_kind::TypeKind,
    pub name: String,
    pub parents: Vec<general::StatusedTypeId>,
    pub has_children: bool,
    pub has_ignored_parents: bool,
    pub functions: Vec<functions::Info>,
    pub has_constructors: bool,
    pub has_methods: bool,
}

impl Info {
    //TODO: add test in tests/ for panic
    pub fn type_<'a>(&self, library: &'a library::Library) -> &'a library::Class {
        let type_ = library.type_(self.class_tid).as_class()
            .unwrap_or_else(|| panic!("{} is not a class.", self.full_name));
        type_
    }

    ///TODO: return iterator
    pub fn constructors(&self) -> Vec<&functions::Info> {
        self.functions.iter()
            .filter(|f| f.kind == library::FunctionKind::Constructor)
            .collect()
    }

    pub fn methods(&self) -> Vec<&functions::Info> {
        self.functions.iter()
            .filter(|f| f.kind == library::FunctionKind::Method)
            .collect()
    }
}

pub fn new(env: &Env, obj: &GObject) -> Info {
    let full_name = obj.name.clone();

    let class_tid = env.library.find_type_unwrapped(0, &full_name, "Class");

    let type_ = env.library.type_(class_tid);
    let kind = type_.to_type_kind(&env.library);
    assert_eq!(kind, TypeKind::Widget);

    let name = split_namespace_name(&full_name).1.into();

    let klass = type_.to_class();
    let (parents, has_ignored_parents) = parents::analyze(env, klass);

    let has_children = klass.has_children;

    let functions = functions::analyze(env, klass, class_tid);

    let has_functions = functions.iter().find(|f| f.kind == library::FunctionKind::Function).is_some();
    assert!(!has_functions, "Widget {} has functions, to do functions code generation", full_name);

    let mut info = Info {
        full_name: full_name,
        class_tid: class_tid,
        kind: kind,
        name: name,
        parents: parents,
        has_children: has_children,
        has_ignored_parents: has_ignored_parents,
        functions: functions,
        .. Default::default()
    };

    let has_constructors = !info.constructors().is_empty();
    let has_methods = !info.methods().is_empty();

    info.has_constructors = has_constructors;
    info.has_methods = has_methods;
    info
}
<|endoftext|>


<commit_before>use std::ops;
use std::cmp::Ordering;

use index::Index;

#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum Value {
    Bool(bool),
    String(String),
    Float(f64),
    Tuple(Tuple),
    Relation(Relation),
}
pub type Tuple = Vec<Value>;
pub type Relation = Index<Vec<Value>>; // a set of tuples
pub type Id = String; // TODO use uuid?

impl Ord for Value {
    fn cmp(&self, other: &Value) -> Ordering {
        self.partial_cmp(other).unwrap() // TODO this will panic on NaN
    }
}

impl Eq for Value {} // TODO this is unsafe for NaN

impl ops::Index<usize> for Value {
    type Output = Value;

    fn index(&self, index: usize) -> &Value {
        match *self {
            Value::Tuple(ref tuple) => tuple.index(index),
            _ => panic!("Cannot index into this non-tuple value: {:?}", self),
        }
    }
}

impl Value {
    pub fn as_str(&self) -> &str {
        match *self {
            Value::String(ref string) => &*string,
            _ => panic!("Cannot convert this to string: {:?}", self),
        }
    }

    pub fn as_slice(&self) -> &[Value] {
        match *self {
            Value::Tuple(ref tuple) => &*tuple,
            _ => panic!("Cannot convert this to tuple: {:?}", self),
        }
    }
    pub fn to_f64(&self) -> Option<f64> {
        match *self {
            Value::Float(float) => Some(float as f64),
            _ => None,
        }
    }
    pub fn to_i64(&self) -> Option<i64> {
        match *self {
            Value::Float(float) => {
                let result = float as i64;
                if (float == (result as f64)) {
                    Some(result)
                } else {
                    None
                }
            }
            _ => None,
        }
    }
    pub fn to_usize(&self) -> Option<usize> {
        match *self {
            Value::Float(float) => {
                let result = float as u64;
                if (float == (result as f64)) {
                    Some(result)
                } else {
                    None
                }
            },
            _ => None,
        }
    }
}<commit_msg>Return usize intead of u64<commit_after>use std::ops;
use std::cmp::Ordering;

use index::Index;

#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum Value {
    Bool(bool),
    String(String),
    Float(f64),
    Tuple(Tuple),
    Relation(Relation),
}
pub type Tuple = Vec<Value>;
pub type Relation = Index<Vec<Value>>; // a set of tuples
pub type Id = String; // TODO use uuid?

impl Ord for Value {
    fn cmp(&self, other: &Value) -> Ordering {
        self.partial_cmp(other).unwrap() // TODO this will panic on NaN
    }
}

impl Eq for Value {} // TODO this is unsafe for NaN

impl ops::Index<usize> for Value {
    type Output = Value;

    fn index(&self, index: usize) -> &Value {
        match *self {
            Value::Tuple(ref tuple) => tuple.index(index),
            _ => panic!("Cannot index into this non-tuple value: {:?}", self),
        }
    }
}

impl Value {
    pub fn as_str(&self) -> &str {
        match *self {
            Value::String(ref string) => &*string,
            _ => panic!("Cannot convert this to string: {:?}", self),
        }
    }

    pub fn as_slice(&self) -> &[Value] {
        match *self {
            Value::Tuple(ref tuple) => &*tuple,
            _ => panic!("Cannot convert this to tuple: {:?}", self),
        }
    }
    pub fn to_f64(&self) -> Option<f64> {
        match *self {
            Value::Float(float) => Some(float as f64),
            _ => None,
        }
    }
    pub fn to_i64(&self) -> Option<i64> {
        match *self {
            Value::Float(float) => {
                let result = float as i64;
                if (float == (result as f64)) {
                    Some(result)
                } else {
                    None
                }
            }
            _ => None,
        }
    }
    pub fn to_usize(&self) -> Option<usize> {
        match *self {
            Value::Float(float) => {
                let result = float as usize;
                if (float == (result as f64)) {
                    Some(result)
                } else {
                    None
                }
            },
            _ => None,
        }
    }
}<|endoftext|>