<commit_before>#![feature(collections)]
#![feature(unicode)]

//modules

mod config;
mod word;

//extern crates

extern crate rand;
extern crate rustc_serialize;
extern crate regex;

//use

use config::*;
use word::*;
use std::io::prelude::*;
//use rustc_serialize::*;    //commented out as it is only used to emit test configs
use std::fs::File;
use rand::distributions::Weighted;

//static variables

static CONFIG_FILE_NAME: &'static str = "main_config.json";

//functions

fn main() {
    let config: WordGeneratorConfig = load_config(&CONFIG_FILE_NAME);

    //comment other code and uncomment these to emit a new test config
    //let mut file = File::create(&CONFIG_FILE_NAME).unwrap();

    /*match file.write(json::encode(&config).unwrap().as_bytes()) {
        Ok(_) => (),
        Err(err) => panic!("Error writing test config: {}", err),
    }*/

    let mut first_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut last_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut normal_syllable_list : Vec<Weighted<String>> = Vec::new();

    //generate weighted lists of syllable configurations in each syllable position

    for syllable in &config.syllables {
        let syllable_weighted : Weighted<String> = Weighted{
            weight: syllable.weight as u32,
            item: syllable.string.clone()
        };
        //if the syllable is eligible for all positions
        if !(syllable.only_first_syllable || syllable.only_last_syllable) {
            normal_syllable_list.push(syllable_weighted.clone());
            first_syllable_list.push(syllable_weighted.clone());
            last_syllable_list.push(syllable_weighted.clone());
        }
        //these need to be separate ifs, as marking only first + only last syllable means it can be used for either
        if syllable.only_first_syllable {
            first_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_last_syllable {
            last_syllable_list.push(syllable_weighted.clone());
        }

    }

    let grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = transform_graphemes(&config.graphemes);

    let word_factory : WordFactory = WordFactory {
        first_syllable_list : first_syllable_list,
        normal_syllable_list : normal_syllable_list,
        last_syllable_list : last_syllable_list,
        graphemes : grapheme_groups,
        generate_settings : config.generate_settings.clone(),
        rewrites : config.rewrites.clone(),
        rejects : config.rejects.clone(),
    };

    let mut file = File::create(&config.output_settings.output_file).unwrap();

    for word in generate_word_list(&config, &word_factory) {
        //if the word has been rejected then ignore it and don't print it
        if word.syllable_rejects.len() > 0 || word.grapheme_rejects.len() > 0 {
            continue;
        }
        match file.write(get_word_graphemes(&word).as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
        match file.write("\n".as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
    }
}

fn generate_word_list(config : &WordGeneratorConfig, word_factory : &WordFactory) -> Vec<Word> {
    let mut word_list : Vec<Word> = Vec::new();

    for _ in 0..config.output_settings.word_count {

        let mut word : Word = Word {
            syllables : String::new(),
            graphemes : String::new(),
            syllable_rewrite_history : Vec::new(),
            grapheme_rewrite_history : Vec::new(),
            syllable_rejects : Vec::new(),
            grapheme_rejects : Vec::new()
        };

        word_factory.generate_syllables(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_syllables(&mut word);
            word_factory.mark_syllable_rejects(&mut word);
        } else {
            word_factory.mark_syllable_rejects(&mut word);
            word_factory.rewrite_syllables(&mut word);
        };

        word_factory.generate_graphemes(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_graphemes(&mut word);
            word_factory.mark_grapheme_rejects(&mut word);
        } else {
            word_factory.mark_grapheme_rejects(&mut word);
            word_factory.rewrite_graphemes(&mut word);
        };
        word_list.push(word);
    }
    word_list
}

//unwraps a list of GraphemeGroups into a tuple list of String and Vec<Weighted<String>>, mostly due to requirement of Weighted for random weighted samples later
fn transform_graphemes(graphemes : &Vec<GraphemeGroup>) -> Vec<(String, Vec<Weighted<String>>)> {

    let mut grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = Vec::new();

    for group in graphemes {
        let mut graphemes_converted : Vec<Weighted<String>> = Vec::new();

        graphemes_converted.extend(
            group.graphemes.iter().map(
                |g: &Grapheme| Weighted{weight: g.weight as u32, item: g.string.clone() }
                )
            );
        grapheme_groups.push((group.name.clone(), graphemes_converted));
    }
    grapheme_groups
}
<commit_msg>rewrote comments in main.rs for clarity<commit_after>#![feature(collections)]
#![feature(unicode)]

//modules

mod config;
mod word;

//extern crates

extern crate rand;
extern crate rustc_serialize;
extern crate regex;

//use

use config::*;
use word::*;
use std::io::prelude::*;
//use rustc_serialize::*;    //commented out as it is only used to emit test configs
use std::fs::File;
use rand::distributions::Weighted;

//static variables

static CONFIG_FILE_NAME: &'static str = "main_config.json";

//functions

fn main() {
    let config: WordGeneratorConfig = load_config(&CONFIG_FILE_NAME);

    //comment other code and uncomment these to emit a new test config
    //let mut file = File::create(&CONFIG_FILE_NAME).unwrap();

    /*match file.write(json::encode(&config).unwrap().as_bytes()) {
        Ok(_) => (),
        Err(err) => panic!("Error writing test config: {}", err),
    }*/

    let mut first_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut last_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut normal_syllable_list : Vec<Weighted<String>> = Vec::new();

    //In-memory, syllables are stored as 'first-only', 'last only', and 'rest of the word' syllable lists.
    //Aside from the impracticality of iterating and manipulating the config data directly every time I
    //want to pick a syllable, I chose this structure as it made implementing syllable construction
    //straightforward while allowing syllables to be constrained to first or last positions. This may end
    //up getting removed later.

    for syllable in &config.syllables {
        let syllable_weighted : Weighted<String> = Weighted{
            weight: syllable.weight as u32,
            item: syllable.string.clone()
        };
        if !(syllable.only_first_syllable || syllable.only_last_syllable) {
            normal_syllable_list.push(syllable_weighted.clone());
            first_syllable_list.push(syllable_weighted.clone());
            last_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_first_syllable {
            first_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_last_syllable {
            last_syllable_list.push(syllable_weighted.clone());
        }

    }

    //transform_graphemes is used to convert Graphemes to Weighted<String>s. This is done because
    let grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = transform_graphemes(&config.graphemes);

    let word_factory : WordFactory = WordFactory {
        first_syllable_list : first_syllable_list,
        normal_syllable_list : normal_syllable_list,
        last_syllable_list : last_syllable_list,
        graphemes : grapheme_groups,
        generate_settings : config.generate_settings.clone(),
        rewrites : config.rewrites.clone(),
        rejects : config.rejects.clone(),
    };

    let mut file = File::create(&config.output_settings.output_file).unwrap();

    //todo: rewrite to generate config-specified number of words even in the case of rejects, this discards rejected words and doesn't replace them
    for word in generate_word_list(&config, &word_factory) {
        if word.syllable_rejects.len() > 0 || word.grapheme_rejects.len() > 0 {
            continue;
        }
        match file.write(get_word_graphemes(&word).as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
        match file.write("\n".as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
    }
}

fn generate_word_list(config : &WordGeneratorConfig, word_factory : &WordFactory) -> Vec<Word> {
    let mut word_list : Vec<Word> = Vec::new();

    for _ in 0..config.output_settings.word_count {

        let mut word : Word = Word {
            syllables : String::new(),
            graphemes : String::new(),
            syllable_rewrite_history : Vec::new(),
            grapheme_rewrite_history : Vec::new(),
            syllable_rejects : Vec::new(),
            grapheme_rejects : Vec::new()
        };

        word_factory.generate_syllables(&mut word);

        //at first glance this doesnt look like it's doing much - marking rejects operate on the final
        //word string so rewriting before or after will make a difference
        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_syllables(&mut word);
            word_factory.mark_syllable_rejects(&mut word);
        } else {
            word_factory.mark_syllable_rejects(&mut word);
            word_factory.rewrite_syllables(&mut word);
        };

        word_factory.generate_graphemes(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_graphemes(&mut word);
            word_factory.mark_grapheme_rejects(&mut word);
        } else {
            word_factory.mark_grapheme_rejects(&mut word);
            word_factory.rewrite_graphemes(&mut word);
        };
        word_list.push(word);
    }
    word_list
}

//unwraps a list of GraphemeGroups into a tuple list of String and Vec<Weighted<String>>
//Stored as a separate structure because JSON data would not be stored as desired for config otherwise
fn transform_graphemes(graphemes : &Vec<GraphemeGroup>) -> Vec<(String, Vec<Weighted<String>>)> {

    let mut grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = Vec::new();

    for group in graphemes {
        let mut graphemes_converted : Vec<Weighted<String>> = Vec::new();

        graphemes_converted.extend(
            group.graphemes.iter().map(
                |g: &Grapheme| Weighted{weight: g.weight as u32, item: g.string.clone() }
                )
            );
        grapheme_groups.push((group.name.clone(), graphemes_converted));
    }
    grapheme_groups
}
<|endoftext|>


<commit_before>use LalafellBot;
use config::Listener;
use listeners::ReceivesEvents;
use discord::model::{Event, Channel, ChannelId};

use xivdb::error::*;

use serde_json;

use std::sync::Arc;

pub struct TagInstructions {
  bot: Arc<LalafellBot>,
  config: TagInstructionsConfig
}

impl TagInstructions {
  pub fn new(bot: Arc<LalafellBot>, listener: &Listener) -> Result<TagInstructions> {
    let config = match listener.config {
      Some(ref c) => serde_json::from_value(c.clone()).chain_err(|| "could not parse tag_instructions configuration")?,
      None => return Err("missing configuration for tag_instructions listener".into())
    };
    Ok(TagInstructions {
      bot: bot,
      config: config
    })
  }
}

impl ReceivesEvents for TagInstructions {
  fn receive(&self, event: &Event) {
    let destination = ChannelId(self.config.channel);
    let event_data = match *event {
      Event::ServerMemberAdd(_, ref member) => Some(member.clone()),
      Event::MessageCreate(ref m) => {
        let chan = match self.bot.discord.get_channel(m.channel_id) {
          Ok(Channel::Public(c)) => c,
          _ => return
        };
        if chan.id != destination {
          return;
        }
        if m.content.to_lowercase().starts_with("!autotag ") {
          return;
        }
        self.bot.discord.get_member(chan.server_id, m.author.id).ok()
      },
      _ => return
    };
    let member = match event_data {
      Some(e) => e,
      None => return
    };

    if !member.roles.is_empty() {
      return;
    }

    let send = format!("Welcome to the lala world linkshell, {}!\nIn order to talk with the rest of us, please tag yourself using the command below.\n`!autotag server character`\nFor example, you might send `!autotag Adamantoise Duvicauroix Priorfaix`",
                       member.user.mention());
    self.bot.discord.send_embed(destination, "", |e| e.description(&send)).ok();
  }
}

#[derive(Debug, Deserialize)]
pub struct TagInstructionsConfig {
  channel: u64
}
<commit_msg>feat: add customizable tag_instructions message<commit_after>use LalafellBot;
use config::Listener;
use listeners::ReceivesEvents;
use discord::model::{Event, Channel, ChannelId};

use xivdb::error::*;

use serde_json;

use std::sync::Arc;

pub struct TagInstructions {
  bot: Arc<LalafellBot>,
  config: TagInstructionsConfig
}

impl TagInstructions {
  pub fn new(bot: Arc<LalafellBot>, listener: &Listener) -> Result<TagInstructions> {
    let config = match listener.config {
      Some(ref c) => serde_json::from_value(c.clone()).chain_err(|| "could not parse tag_instructions configuration")?,
      None => return Err("missing configuration for tag_instructions listener".into())
    };
    Ok(TagInstructions {
      bot: bot,
      config: config
    })
  }
}

impl ReceivesEvents for TagInstructions {
  fn receive(&self, event: &Event) {
    let destination = ChannelId(self.config.channel);
    let event_data = match *event {
      Event::ServerMemberAdd(_, ref member) => Some(member.clone()),
      Event::MessageCreate(ref m) => {
        let chan = match self.bot.discord.get_channel(m.channel_id) {
          Ok(Channel::Public(c)) => c,
          _ => return
        };
        if chan.id != destination {
          return;
        }
        if m.content.to_lowercase().starts_with("!autotag ") {
          return;
        }
        self.bot.discord.get_member(chan.server_id, m.author.id).ok()
      },
      _ => return
    };
    let member = match event_data {
      Some(e) => e,
      None => return
    };

    if !member.roles.is_empty() {
      return;
    }

    let message = self.config.message
      .replace("{mention}", &member.user.mention().to_string());
    self.bot.discord.send_embed(destination, "", |e| e.description(&message)).ok();
  }
}

#[derive(Debug, Deserialize)]
pub struct TagInstructionsConfig {
  channel: u64,
  message: String
}
<|endoftext|>


<commit_before>#![feature(collections)]

// Implements http://rosettacode.org/wiki/Longest_common_subsequence

/// Returns the longest common subsequence of a and b.
fn longest_common_subsequence(a: &str, b: &str) -> String {
    let mut lengths = Vec::with_capacity(a.len() + 1);
    for i in 0..a.len() + 1 {
        lengths.push(Vec::with_capacity(b.len() + 1));
        for _ in 0..b.len() + 1 {
            lengths[i].push(0);
        }
    }

    for i in 0..a.len() {
        for j in 0..b.len() {
            if a.char_at(i) == b.char_at(j) {
                lengths[i + 1][j + 1] = lengths[i][j] + 1;
            } else {
                lengths[i + 1][j + 1] = std::cmp::max(
                        lengths[i + 1][j], lengths[i][j + 1]);
            }
        }
    }

    let mut lcs = String::new();
    let mut i = a.len();
    let mut j = b.len();

    while i != 0 && j != 0 {
        if lengths[i][j] == lengths[i - 1][j] {
            i -= 1;
        } else if lengths[i][j] == lengths[i][j - 1] {
            j -= 1;
        } else {
            lcs.push(a.char_at(i - 1));
            i -= 1;
            j -= 1;
        }
    }

    lcs.chars().rev().collect()
}

// Demonstration code
#[cfg(not(test))]
fn main() {
    println!("{}", longest_common_subsequence("abc", "abcd"));
    println!("{}", longest_common_subsequence("ABCDGH", "AEDFHR"));
    println!("{}", longest_common_subsequence("AGGTAB", "GXTXAYB"));
    println!("{}", longest_common_subsequence("", "abcdefg"));
    println!("{}", longest_common_subsequence("abc", ""));
    println!("{}", longest_common_subsequence("abcdefg", "abc"));
    println!("{}", longest_common_subsequence("aaaa", "aaaaaa"));
}

#[test]
fn test_longest_common_subsequence() {
    assert_eq!(longest_common_subsequence("abc", "abcdefg"), "abc");
    assert_eq!(longest_common_subsequence("ABCDGH", "AEDFHR"), "ADH");
    assert_eq!(longest_common_subsequence("AGGTAB", "GXTXAYB"), "GTAB");
    assert_eq!(longest_common_subsequence("", "abcdefg"), "");
    assert_eq!(longest_common_subsequence("abc", ""), "");
    assert_eq!(longest_common_subsequence("abcdefg", "abc"), "abc");
    assert_eq!(longest_common_subsequence("aaaa", "aaaaaa"), "aaaa");
}
<commit_msg>replaced 2d vector init loop with macro<commit_after>// Implements http://rosettacode.org/wiki/Longest_common_subsequence
#![feature(collections)]

/// Returns the longest common subsequence of a and b.
fn longest_common_subsequence(a: &str, b: &str) -> String {
    let mut lengths = vec![vec![0; b.len() + 1]; a.len() + 1];

    for i in 0..a.len() {
        for j in 0..b.len() {
            if a.char_at(i) == b.char_at(j) {
                lengths[i + 1][j + 1] = lengths[i][j] + 1;
            } else {
                lengths[i + 1][j + 1] = std::cmp::max(
                        lengths[i + 1][j], lengths[i][j + 1]);
            }
        }
    }

    let mut lcs = String::new();
    let mut i = a.len();
    let mut j = b.len();

    while i != 0 && j != 0 {
        if lengths[i][j] == lengths[i - 1][j] {
            i -= 1;
        } else if lengths[i][j] == lengths[i][j - 1] {
            j -= 1;
        } else {
            lcs.push(a.char_at(i - 1));
            i -= 1;
            j -= 1;
        }
    }

    lcs.chars().rev().collect()
}

// Demonstration code
#[cfg(not(test))]
fn main() {
    println!("{}", longest_common_subsequence("abc", "abcd"));
    println!("{}", longest_common_subsequence("ABCDGH", "AEDFHR"));
    println!("{}", longest_common_subsequence("AGGTAB", "GXTXAYB"));
    println!("{}", longest_common_subsequence("", "abcdefg"));
    println!("{}", longest_common_subsequence("abc", ""));
    println!("{}", longest_common_subsequence("abcdefg", "abc"));
    println!("{}", longest_common_subsequence("aaaa", "aaaaaa"));
}

#[test]
fn test_longest_common_subsequence() {
    assert_eq!(longest_common_subsequence("abc", "abcdefg"), "abc");
    assert_eq!(longest_common_subsequence("ABCDGH", "AEDFHR"), "ADH");
    assert_eq!(longest_common_subsequence("AGGTAB", "GXTXAYB"), "GTAB");
    assert_eq!(longest_common_subsequence("", "abcdefg"), "");
    assert_eq!(longest_common_subsequence("abc", ""), "");
    assert_eq!(longest_common_subsequence("abcdefg", "abc"), "abc");
    assert_eq!(longest_common_subsequence("aaaa", "aaaaaa"), "aaaa");
}
<|endoftext|>


<commit_before>//! Data types for addresses to nodes in DICOM networks.

use std::{
    net::{AddrParseError, SocketAddr, ToSocketAddrs},
    str::FromStr,
};

use snafu::{ResultExt, Snafu};

/// A specification for a full address to the target SCP:
/// an application entity title, plus a network socket address.
///
/// These addresses can be serialized and parsed
/// with the syntax `{ae_title}@{socket_address}`.
///
/// For the version of the struct without a mandatory AE title,
/// see [`AeAddr`].
///
/// # Example
///
/// ```
/// # use dicom_ul::FullAeAddr;
/// # use std::net::SocketAddr;
/// #
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let addr: FullAeAddr = "SCP-STORAGE@127.0.0.1:104".parse()?;
/// assert_eq!(addr.ae_title(), "SCP-STORAGE");
/// assert_eq!(addr.socket_addr(), SocketAddr::from(([127, 0, 0, 1], 104)));
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct FullAeAddr {
    ae_title: String,
    socket_addr: std::net::SocketAddr,
}

impl FullAeAddr {
    /// Create an AE address from its bare constituent parts.
    pub fn new(ae_title: impl Into<String>, socket_addr: SocketAddr) -> Self {
        FullAeAddr {
            ae_title: ae_title.into(),
            socket_addr,
        }
    }

    /// Retrieve the application entity title portion.
    pub fn ae_title(&self) -> &str {
        &self.ae_title
    }

    /// Retrieve the socket address portion.
    pub fn socket_addr(&self) -> std::net::SocketAddr {
        self.socket_addr
    }
}

impl From<(String, SocketAddr)> for FullAeAddr {
    fn from((ae_title, socket_addr): (String, SocketAddr)) -> Self {
        Self::new(ae_title, socket_addr)
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Snafu)]
pub enum ParseAeAddressError {
    /// Missing `@` in full AE address
    MissingPart,

    /// Could not parse socket address
    ParseSocketAddress { source: AddrParseError },
}

impl FromStr for FullAeAddr {
    type Err = ParseAeAddressError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some((ae_title, addr)) = s.split_once('@') {
            Ok(FullAeAddr {
                ae_title: ae_title.to_string(),
                socket_addr: addr.parse().context(ParseSocketAddressSnafu)?,
            })
        } else {
            Err(ParseAeAddressError::MissingPart)
        }
    }
}

impl ToSocketAddrs for FullAeAddr {
    type Iter = std::option::IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
        self.socket_addr.to_socket_addrs()
    }
}

/// A specification for an address to the target SCP:
/// a network socket address
/// which may also include an application entity title.
///
/// These addresses can be serialized and parsed
/// with the syntax `{ae_title}@{socket_address}`,
/// where the
///
/// For the version of the struct in which the AE title part is mandatory,
/// see [`FullAeAddr`].
///
/// # Example
///
/// ```
/// # use dicom_ul::{AeAddr, FullAeAddr};
/// # use std::net::SocketAddr;
/// #
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let addr: AeAddr = "SCP-STORAGE@127.0.0.1:104".parse()?;
/// assert_eq!(addr.ae_title(), Some("SCP-STORAGE"));
/// assert_eq!(addr.socket_addr(), SocketAddr::from(([127, 0, 0, 1], 104)));
///
/// // AE title can be missing
/// let addr: AeAddr = "192.168.1.99:1045".parse()?;
/// assert_eq!(addr.ae_title(), None);
/// // but can be provided later
/// let full_addr: FullAeAddr = addr.with_ae_title("SCP-QUERY");
/// assert_eq!(full_addr.ae_title(), "SCP-QUERY");
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct AeAddr {
    ae_title: Option<String>,
    socket_addr: std::net::SocketAddr,
}

impl AeAddr {
    /// Create an AE address from its bare constituent parts.
    pub fn new(ae_title: impl Into<String>, socket_addr: SocketAddr) -> Self {
        AeAddr {
            ae_title: Some(ae_title.into()),
            socket_addr,
        }
    }

    /// Create an AE address containing only a socket address.
    pub fn new_socket_addr(socket_addr: SocketAddr) -> Self {
        AeAddr {
            ae_title: None,
            socket_addr,
        }
    }

    /// Retrieve the application entity title portion, if present.
    pub fn ae_title(&self) -> Option<&str> {
        self.ae_title.as_ref().map(String::as_str)
    }

    /// Retrieve the socket address portion.
    pub fn socket_addr(&self) -> std::net::SocketAddr {
        self.socket_addr
    }

    /// Create a new address with the full application entity target,
    /// discarding any potentially existing AE title.
    pub fn with_ae_title(self, ae_title: impl Into<String>) -> FullAeAddr {
        FullAeAddr {
            ae_title: ae_title.into(),
            socket_addr: self.socket_addr,
        }
    }

    /// Create a new address with the full application entity target,
    /// using the given AE title if it is missing.
    pub fn with_default_ae_title(self, ae_title: impl Into<String>) -> FullAeAddr {
        FullAeAddr {
            ae_title: self.ae_title.unwrap_or_else(|| ae_title.into()),
            socket_addr: self.socket_addr,
        }
    }
}

/// This conversion provides an address without an AE title.
impl From<SocketAddr> for AeAddr {
    fn from(socket_addr: SocketAddr) -> Self {
        AeAddr {
            ae_title: None,
            socket_addr,
        }
    }
}

impl From<FullAeAddr> for AeAddr {
    fn from(full: FullAeAddr) -> Self {
        AeAddr {
            ae_title: Some(full.ae_title),
            socket_addr: full.socket_addr,
        }
    }
}

impl FromStr for AeAddr {
    type Err = std::net::AddrParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some((ae_title, address)) = s.split_once('@') {
            Ok(AeAddr {
                ae_title: Some(ae_title.to_string()),
                socket_addr: address.parse()?,
            })
        } else {
            Ok(AeAddr {
                ae_title: None,
                socket_addr: s.parse()?,
            })
        }
    }
}

impl ToSocketAddrs for AeAddr {
    type Iter = std::option::IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
        self.socket_addr.to_socket_addrs()
    }
}
<commit_msg>[ul] Improve address module<commit_after>//! Data types for addresses to nodes in DICOM networks.

use std::{
    net::{AddrParseError, SocketAddr, ToSocketAddrs},
    str::FromStr,
};

use snafu::{ResultExt, Snafu};

/// A specification for a full address to the target SCP:
/// an application entity title, plus a network socket address.
///
/// These addresses can be serialized and parsed
/// with the syntax `{ae_title}@{socket_address}`.
///
/// For the version of the struct without a mandatory AE title,
/// see [`AeAddr`].
///
/// # Example
///
/// ```
/// # use dicom_ul::FullAeAddr;
/// # use std::net::SocketAddr;
/// #
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let addr: FullAeAddr = "SCP-STORAGE@127.0.0.1:104".parse()?;
/// assert_eq!(addr.ae_title(), "SCP-STORAGE");
/// assert_eq!(addr.socket_addr(), SocketAddr::from(([127, 0, 0, 1], 104)));
/// assert_eq!(&addr.to_string(), "SCP-STORAGE@127.0.0.1:104");
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct FullAeAddr {
    ae_title: String,
    socket_addr: std::net::SocketAddr,
}

impl FullAeAddr {
    /// Create an AE address from its bare constituent parts.
    pub fn new(ae_title: impl Into<String>, socket_addr: SocketAddr) -> Self {
        FullAeAddr {
            ae_title: ae_title.into(),
            socket_addr,
        }
    }

    /// Retrieve the application entity title portion.
    pub fn ae_title(&self) -> &str {
        &self.ae_title
    }

    /// Retrieve the socket address portion.
    pub fn socket_addr(&self) -> std::net::SocketAddr {
        self.socket_addr
    }
}

impl From<(String, SocketAddr)> for FullAeAddr {
    fn from((ae_title, socket_addr): (String, SocketAddr)) -> Self {
        Self::new(ae_title, socket_addr)
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Snafu)]
pub enum ParseAeAddressError {
    /// Missing `@` in full AE address
    MissingPart,

    /// Could not parse socket address
    ParseSocketAddress { source: AddrParseError },
}

impl FromStr for FullAeAddr {
    type Err = ParseAeAddressError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some((ae_title, addr)) = s.split_once('@') {
            Ok(FullAeAddr {
                ae_title: ae_title.to_string(),
                socket_addr: addr.parse().context(ParseSocketAddressSnafu)?,
            })
        } else {
            Err(ParseAeAddressError::MissingPart)
        }
    }
}

impl ToSocketAddrs for FullAeAddr {
    type Iter = std::option::IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
        self.socket_addr.to_socket_addrs()
    }
}

impl std::fmt::Display for FullAeAddr {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.ae_title)?;
        f.write_str("@")?;
        std::fmt::Display::fmt(&self.socket_addr, f)
    }
}

/// A specification for an address to the target SCP:
/// a network socket address
/// which may also include an application entity title.
///
/// These addresses can be serialized and parsed
/// with the syntax `{ae_title}@{socket_address}`,
/// where the
///
/// For the version of the struct in which the AE title part is mandatory,
/// see [`FullAeAddr`].
///
/// # Example
///
/// ```
/// # use dicom_ul::{AeAddr, FullAeAddr};
/// # use std::net::SocketAddr;
/// #
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let addr: AeAddr = "SCP-STORAGE@127.0.0.1:104".parse()?;
/// assert_eq!(addr.ae_title(), Some("SCP-STORAGE"));
/// assert_eq!(addr.socket_addr(), SocketAddr::from(([127, 0, 0, 1], 104)));
/// assert_eq!(&addr.to_string(), "127.0.0.1:104");
///
/// // AE title can be missing
/// let addr: AeAddr = "192.168.1.99:1045".parse()?;
/// assert_eq!(addr.ae_title(), None);
/// // but can be provided later
/// let full_addr: FullAeAddr = addr.with_ae_title("SCP-QUERY");
/// assert_eq!(full_addr.ae_title(), "SCP-QUERY");
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct AeAddr {
    ae_title: Option<String>,
    socket_addr: std::net::SocketAddr,
}

impl AeAddr {
    /// Create an AE address from its bare constituent parts.
    pub fn new(ae_title: impl Into<String>, socket_addr: SocketAddr) -> Self {
        AeAddr {
            ae_title: Some(ae_title.into()),
            socket_addr,
        }
    }

    /// Create an AE address containing only a socket address.
    pub fn new_socket_addr(socket_addr: SocketAddr) -> Self {
        AeAddr {
            ae_title: None,
            socket_addr,
        }
    }

    /// Retrieve the application entity title portion, if present.
    pub fn ae_title(&self) -> Option<&str> {
        self.ae_title.as_deref()
    }

    /// Retrieve the socket address portion.
    pub fn socket_addr(&self) -> std::net::SocketAddr {
        self.socket_addr
    }

    /// Create a new address with the full application entity target,
    /// discarding any potentially existing AE title.
    pub fn with_ae_title(self, ae_title: impl Into<String>) -> FullAeAddr {
        FullAeAddr {
            ae_title: ae_title.into(),
            socket_addr: self.socket_addr,
        }
    }

    /// Create a new address with the full application entity target,
    /// using the given AE title if it is missing.
    pub fn with_default_ae_title(self, ae_title: impl Into<String>) -> FullAeAddr {
        FullAeAddr {
            ae_title: self.ae_title.unwrap_or_else(|| ae_title.into()),
            socket_addr: self.socket_addr,
        }
    }
}

/// This conversion provides an address without an AE title.
impl From<SocketAddr> for AeAddr {
    fn from(socket_addr: SocketAddr) -> Self {
        AeAddr {
            ae_title: None,
            socket_addr,
        }
    }
}

impl From<FullAeAddr> for AeAddr {
    fn from(full: FullAeAddr) -> Self {
        AeAddr {
            ae_title: Some(full.ae_title),
            socket_addr: full.socket_addr,
        }
    }
}

impl FromStr for AeAddr {
    type Err = std::net::AddrParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some((ae_title, address)) = s.split_once('@') {
            Ok(AeAddr {
                ae_title: Some(ae_title.to_string()),
                socket_addr: address.parse()?,
            })
        } else {
            Ok(AeAddr {
                ae_title: None,
                socket_addr: s.parse()?,
            })
        }
    }
}

impl ToSocketAddrs for AeAddr {
    type Iter = std::option::IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
        self.socket_addr.to_socket_addrs()
    }
}

impl std::fmt::Display for AeAddr {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if let Some(ae_title) = &self.ae_title {
            f.write_str(ae_title)?;
            f.write_str("@")?;
        }

        std::fmt::Display::fmt(&self.socket_addr, f)
    }
}
<|endoftext|>


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

// corresponds to lauxlib.h
use libc::{c_int, c_long, c_char, c_void, size_t};
use ffi::lua;
use ffi::lua::{lua_State, lua_CFunction, lua_Integer, lua_Number};
use ffi::luaconf::LUAL_BUFFERSIZE;
use std::ptr;

pub use super::glue::LUAL_NUMSIZES;

// extra error code for 'luaL_load'
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;

#[repr(C)]
pub struct luaL_Reg {
  name: *const c_char,
  func: lua_CFunction,
}

#[inline(always)]
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
  luaL_checkversion_(L, lua::LUA_VERSION_NUM as lua_Number, LUAL_NUMSIZES as size_t)
}

extern {
  pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: size_t);

  pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut size_t) -> *const c_char;
  pub fn luaL_argerror(L: *mut lua_State, arg: c_int, l: *const c_char) -> c_int;
  pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut size_t) -> *const c_char;
  pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut size_t) -> *const c_char;
  pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
  pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
  pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
  pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer;

  pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char);
  pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int);
  pub fn luaL_checkany(L: *mut lua_State, arg: c_int);

  pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
  pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
  pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
  pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;

  pub fn luaL_where(L: *mut lua_State, lvl: c_int) -> c_int;
  pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> c_int;

  // TODO: test this
  pub fn luaL_checkoption(L: *mut lua_State, arg: c_int, def: *const c_char, lst: [*const c_char]) -> c_int;

  pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
  pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
}

// pre-defined references
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;

extern {
  pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
  pub fn luaL_unref(L: *mut lua_State, t: c_int, r: c_int);

  pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char) -> c_int;
}

#[inline(always)]
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
  luaL_loadfilex(L, f, ptr::null())
}

extern {
  pub fn luaL_loadbufferx(L: *mut lua_State, buff: *const c_char, sz: size_t, name: *const c_char, mode: *const c_char) -> c_int;
  pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;

  pub fn luaL_newstate() -> *mut lua_State;

  pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;

  pub fn luaL_gsub(L: *mut lua_State, s: *const c_char, p: *const c_char, r: *const c_char) -> *const c_char;

  pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);

  pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;

  pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);

  pub fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int);
}

#[inline(always)]
#[allow(unused_variables)]
pub unsafe fn luaL_newlibtable(L: *mut lua_State, l: *const luaL_Reg) {
  // TODO: figure out how to pass an appropriate hint for the second param
  // this involves correcting the second parameter's type; in C this is
  // sizeof(l)/sizeof(l[0])
  lua::lua_createtable(L, 0, 0)
}

#[inline(always)]
pub unsafe fn luaL_newlib(L: *mut lua_State, l: *const luaL_Reg) {
  luaL_checkversion(L);
  luaL_newlibtable(L, l);
  luaL_setfuncs(L, l, 0)
}

#[inline(always)]
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
  if cond == 0 {
    luaL_argerror(L, arg, extramsg);
  }
}

#[inline(always)]
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
  luaL_checklstring(L, n, ptr::null_mut())
}

#[inline(always)]
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
  luaL_optlstring(L, n, d, ptr::null_mut())
}

// From 5.3 user manual:
// Macros to project non-default integer types (luaL_checkint, luaL_optint,
// luaL_checklong, luaL_optlong) were deprecated. Use their equivalent over
// lua_Integer with a type cast (or, when possible, use lua_Integer in your
// code).
#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checkint(L: *mut lua_State, n: c_int) -> c_int {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optint(L: *mut lua_State, n: c_int, d: c_int) -> c_int {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checklong(L: *mut lua_State, n: c_int) -> c_long {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optlong(L: *mut lua_State, n: c_int, d: c_long) -> c_long {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
  lua::lua_typename(L, lua::lua_type(L, i))
}

#[inline(always)]
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
  let status = luaL_loadfile(L, filename);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
  let status = luaL_loadstring(L, s);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
  lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
}

// luaL_opt would be implemented here but it is undocumented, so it's omitted

#[inline(always)]
pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: size_t, n: *const c_char) -> c_int {
  luaL_loadbufferx(L, s, sz, n, ptr::null())
}

#[repr(C)]
pub struct luaL_Buffer {
  b: *mut c_char,
  size: size_t,
  n: size_t,
  L: *mut lua_State,
  initb: [c_char, ..LUAL_BUFFERSIZE as uint]
}

// TODO: Test this thoroughly
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
  // (B)->n < (B) -> size || luaL_prepbuffsize((B), 1)
  if (*B).n < (*B).size {
    luaL_prepbuffsize(B, 1);
  }
  // (B)->b[(B)->n++] = (c)
  let offset = (*B).b.offset((*B).n as int);
  ptr::write(offset, c);
  (*B).n += 1;
}

#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, s: size_t) {
  (*B).n += s;
}

extern {
  pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
  pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
  pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: size_t);
  pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
  pub fn luaL_addvalue(B: *mut luaL_Buffer);
  pub fn luaL_pushresult(B: *mut luaL_Buffer);
  pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: size_t);
  pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
}

pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
  luaL_prepbuffsize(B, LUAL_BUFFERSIZE as size_t)
}

// omitted: LUA_FILEHANDLE

#[repr(C)]
pub struct luaL_Stream {
  f: *mut c_void,
  closef: lua_CFunction
}

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

// corresponds to lauxlib.h
use libc::{c_int, c_long, c_char, c_void, size_t};
use ffi::lua;
use ffi::lua::{lua_State, lua_CFunction, lua_Integer, lua_Number};
use ffi::luaconf::LUAL_BUFFERSIZE;
use std::ptr;

pub use super::glue::LUAL_NUMSIZES;

// extra error code for 'luaL_load'
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;

#[repr(C)]
pub struct luaL_Reg {
  name: *const c_char,
  func: lua_CFunction,
}

#[inline(always)]
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
  luaL_checkversion_(L, lua::LUA_VERSION_NUM as lua_Number, LUAL_NUMSIZES as size_t)
}

extern {
  pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: size_t);

  pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut size_t) -> *const c_char;
  pub fn luaL_argerror(L: *mut lua_State, arg: c_int, l: *const c_char) -> c_int;
  pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut size_t) -> *const c_char;
  pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut size_t) -> *const c_char;
  pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
  pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
  pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
  pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer;

  pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char);
  pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int);
  pub fn luaL_checkany(L: *mut lua_State, arg: c_int);

  pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
  pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
  pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
  pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;

  pub fn luaL_where(L: *mut lua_State, lvl: c_int);
  pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> c_int;

  // TODO: test this
  pub fn luaL_checkoption(L: *mut lua_State, arg: c_int, def: *const c_char, lst: [*const c_char]) -> c_int;

  pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
  pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
}

// pre-defined references
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;

extern {
  pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
  pub fn luaL_unref(L: *mut lua_State, t: c_int, r: c_int);

  pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char) -> c_int;
}

#[inline(always)]
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
  luaL_loadfilex(L, f, ptr::null())
}

extern {
  pub fn luaL_loadbufferx(L: *mut lua_State, buff: *const c_char, sz: size_t, name: *const c_char, mode: *const c_char) -> c_int;
  pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;

  pub fn luaL_newstate() -> *mut lua_State;

  pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;

  pub fn luaL_gsub(L: *mut lua_State, s: *const c_char, p: *const c_char, r: *const c_char) -> *const c_char;

  pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);

  pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;

  pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);

  pub fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int);
}

#[inline(always)]
#[allow(unused_variables)]
pub unsafe fn luaL_newlibtable(L: *mut lua_State, l: *const luaL_Reg) {
  // TODO: figure out how to pass an appropriate hint for the second param
  // this involves correcting the second parameter's type; in C this is
  // sizeof(l)/sizeof(l[0])
  lua::lua_createtable(L, 0, 0)
}

#[inline(always)]
pub unsafe fn luaL_newlib(L: *mut lua_State, l: *const luaL_Reg) {
  luaL_checkversion(L);
  luaL_newlibtable(L, l);
  luaL_setfuncs(L, l, 0)
}

#[inline(always)]
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
  if cond == 0 {
    luaL_argerror(L, arg, extramsg);
  }
}

#[inline(always)]
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
  luaL_checklstring(L, n, ptr::null_mut())
}

#[inline(always)]
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
  luaL_optlstring(L, n, d, ptr::null_mut())
}

// From 5.3 user manual:
// Macros to project non-default integer types (luaL_checkint, luaL_optint,
// luaL_checklong, luaL_optlong) were deprecated. Use their equivalent over
// lua_Integer with a type cast (or, when possible, use lua_Integer in your
// code).
#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checkint(L: *mut lua_State, n: c_int) -> c_int {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optint(L: *mut lua_State, n: c_int, d: c_int) -> c_int {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checklong(L: *mut lua_State, n: c_int) -> c_long {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optlong(L: *mut lua_State, n: c_int, d: c_long) -> c_long {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
  lua::lua_typename(L, lua::lua_type(L, i))
}

#[inline(always)]
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
  let status = luaL_loadfile(L, filename);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
  let status = luaL_loadstring(L, s);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
  lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
}

// luaL_opt would be implemented here but it is undocumented, so it's omitted

#[inline(always)]
pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: size_t, n: *const c_char) -> c_int {
  luaL_loadbufferx(L, s, sz, n, ptr::null())
}

#[repr(C)]
pub struct luaL_Buffer {
  b: *mut c_char,
  size: size_t,
  n: size_t,
  L: *mut lua_State,
  initb: [c_char, ..LUAL_BUFFERSIZE as uint]
}

// TODO: Test this thoroughly
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
  // (B)->n < (B) -> size || luaL_prepbuffsize((B), 1)
  if (*B).n < (*B).size {
    luaL_prepbuffsize(B, 1);
  }
  // (B)->b[(B)->n++] = (c)
  let offset = (*B).b.offset((*B).n as int);
  ptr::write(offset, c);
  (*B).n += 1;
}

#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, s: size_t) {
  (*B).n += s;
}

extern {
  pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
  pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
  pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: size_t);
  pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
  pub fn luaL_addvalue(B: *mut luaL_Buffer);
  pub fn luaL_pushresult(B: *mut luaL_Buffer);
  pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: size_t);
  pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
}

pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
  luaL_prepbuffsize(B, LUAL_BUFFERSIZE as size_t)
}

// omitted: LUA_FILEHANDLE

#[repr(C)]
pub struct luaL_Stream {
  f: *mut c_void,
  closef: lua_CFunction
}

// omitted: old module system compatibility
<|endoftext|>


<commit_before>// A port of selecta's scoring algorithm.
// selecta (c) 2014 John Hawthorn
// Licensed under the MIT license

use std::cmp::Ordering;
use super::eq;
use super::mat::Mat;
use super::bonus::compute_bonus;
use super::consts::*;

/// A score derived from comparing needle and haystack strings, with optional
/// match position information.
#[derive(Debug)]
pub struct Score {
    /// The computed score value
    pub value: f64,

    /// Optional vector of match positions
    pub positions: Option<Vec<usize>>
}

impl Score {
    /// Creates a new Score from the provided needle and haystack
    ///
    /// # Examples
    ///
    /// ```
    /// use rff::fuzzy::Score;
    /// let score = Score::new("abc", "abc");
    /// assert_eq!(score.value, std::f64::INFINITY);
    /// ```
    pub fn new(needle: &str, haystack: &str) -> Score {
        Scorer::new(needle, haystack).calculate().as_score()
    }

    /// Creates a new Score from the provided needle and haystack, calculating
    /// match positions.
    ///
    /// # Examples
    ///
    /// ```
    /// use rff::fuzzy::Score;
    /// let score = Score::with_positions("abc", "abc");
    /// assert_eq!(score.value, std::f64::INFINITY);
    /// assert_eq!(score.positions, Some(vec![0, 1, 2]));
    /// ```
    pub fn with_positions(needle: &str, haystack: &str) -> Score {
        Scorer::new(needle, haystack).calculate().with_positions().as_score()
    }
}

impl PartialOrd for Score {
    #[inline]
    fn partial_cmp(&self, other: &Score) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl PartialEq for Score {
    #[inline]
    fn eq(&self, other: &Score) -> bool {
        self.value == other.value
    }
}

struct Scorer<'a> {
    needle: &'a str,
    haystack: &'a str,
    len_n: usize,
    len_h: usize,
    d: Option<Mat>,
    m: Option<Mat>,
    score: f64,
    positions: Option<Vec<usize>>
}

impl<'a> Scorer<'a> {
    #[inline]
    fn new(needle: &'a str, haystack: &'a str) -> Scorer<'a> {
        let len_n = needle.chars().count();
        let len_h = haystack.chars().count();

        Scorer {
            needle: needle,
            haystack: haystack,
            len_n: len_n,
            len_h: len_h,
            m: None,
            d: None,
            score: 0.0,
            positions: None
        }
    }

    #[inline]
    fn calculate(mut self) -> Scorer<'a> {
        if self.len_n == 0 {
            self.score = SCORE_MIN;
            return self;
        }

        if self.len_n == self.len_h {
            self.score = SCORE_MAX;
            return self;
        }

        if self.len_h > 1024 {
            // unreasonably large candidate
            self.score = SCORE_MIN;
            return self;
        }

        let bonus = compute_bonus(self.haystack);

        let mut m = Mat::new(self.len_n, self.len_h);
        let mut d = Mat::new(self.len_n, self.len_h);

        for (i, n) in self.needle.chars().enumerate() {
            let mut prev_score = SCORE_MIN;
            let gap_score = if i == self.len_n - 1 { SCORE_GAP_TRAILING } else { SCORE_GAP_INNER };

            for (j, h) in self.haystack.chars().enumerate() {
                if eq(n, h) {
                    let bonus_score = bonus[j];

                    let score = match i {
                        0 => ((j as f64) * SCORE_GAP_LEADING) + bonus_score,
                        _ if j > 0 => {
                            let m = m.get(i - 1, j - 1).unwrap();
                            let d = d.get(i - 1, j - 1).unwrap();

                            let m = m + bonus_score;
                            let d = d + SCORE_MATCH_CONSECUTIVE;

                            (m).max(d)
                        },
                        _ => SCORE_MIN
                    };

                    prev_score = score.max(prev_score + gap_score);

                    d.set(i, j, score);
                    m.set(i, j, prev_score);
                } else {
                    prev_score += gap_score;

                    d.set(i, j, SCORE_MIN);
                    m.set(i, j, prev_score);
                }
            }
        }

        self.score = m.get(self.len_n - 1, self.len_h - 1).unwrap_or(SCORE_MIN);

        self.m = Some(m);
        self.d = Some(d);

        self
    }

    #[inline]
    fn with_positions(mut self) -> Scorer<'a> {
        if self.len_n == self.len_h {
            self.positions = Some((0..self.len_n).collect());
        }

        if self.len_n == 0 || self.len_n == self.len_h || self.len_h > 1024 {
            return self;
        }

        let mut positions = vec![0 as usize; self.len_n];
        let mut match_required = false;

        {
            let m = self.m.as_ref().unwrap();
            let d = self.d.as_ref().unwrap();

            let mut j = self.len_h - 1;

            for i in (0..self.len_n).rev() {
                while j > (0 as usize) {
                    let last = if i > 0 && j > 0 { d.get(i - 1, j - 1).unwrap() } else { 0.0 };

                    let d = d.get(i, j).unwrap();
                    let m = m.get(i, j).unwrap();

                    if d != SCORE_MIN && (match_required || d == m) {
                        if i > 0 && j > 0 && m == last + SCORE_MATCH_CONSECUTIVE {
                            match_required = true;
                        }

                        positions[i] = j;

                        break;
                    }

                    j -= 1
                }
            }
        }

        self.positions = Some(positions);
        self
    }

    #[inline]
    fn as_score(self) -> Score {
        Score {
            value: self.score,
            positions: self.positions,
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;

    fn score(needle: &str, haystack: &str) -> Score {
        Score::new(needle, haystack)
    }

    #[test]
    fn test_eq() {
        let a = Score { value: 1.0, positions: None };
        let b = Score { value: 1.0, positions: None };
        assert_eq!(a, b);
    }

    #[test]
    fn test_cmp() {
        let a = Score { value: 2.0, positions: None };
        let b = Score { value: 1.0, positions: None };
        assert!(a > b);
        assert!(b < a);

        let b = Score { value: 2.0, positions: None };
        assert!(a == b);
    }

    #[test]
    fn relative_scores() {
        // App/Models/Order is better than App/MOdels/zRder
        assert!(score("amor", "app/models/order") > score("amor", "app/models/zrder"));

        // App/MOdels/foo is better than App/M/fOo
        assert!(score("amo", "app/m/foo") < score("amo", "app/models/foo"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // Prefer shorter scorees
        assert!(score("abce", "abcdef") > score("abce", "abc de"));

        // Prefer shorter candidates
        assert!(score("test", "tests") > score("test", "testing"));

        // Scores first letter highly
        assert!(score("test", "testing") > score("test", "/testing"));

        // Prefer shorter scorees
        assert!(score("abc", "    a b c ") > score("abc", " a  b  c "));
        assert!(score("abc", " a b c    ") > score("abc", " a  b  c "));
    }

    #[test]
    fn score_utf8() {
        assert_eq!(score("ß", "öäßéè").value, -0.02);
    }

    #[test]
    fn positions() {
        macro_rules! test_positions {
            ($needle:expr, $haystack:expr, $result:expr) => {
                let score = Score::with_positions($needle, $haystack);
                assert_eq!(score.positions, Some($result));
            }
        }

        test_positions!("amo", "app/models/foo", vec![0, 4, 5]);
        test_positions!("amor", "app/models/order", vec![0, 4, 11, 12]);
        test_positions!("as", "tags", vec![1, 3]);
        test_positions!("abc", "a/a/b/c/c", vec![2, 4, 6]);
        test_positions!("foo", "foo", vec![0, 1, 2]);
        test_positions!("drivers", "/path/to/drivers/file.txt", vec![9, 10, 11, 12, 13, 14, 15]);
    }
}
<commit_msg>Rename Scorer to ScoreBuilder<commit_after>// A port of selecta's scoring algorithm.
// selecta (c) 2014 John Hawthorn
// Licensed under the MIT license

use std::cmp::Ordering;
use super::eq;
use super::mat::Mat;
use super::bonus::compute_bonus;
use super::consts::*;

/// A score derived from comparing needle and haystack strings, with optional
/// match position information.
#[derive(Debug)]
pub struct Score {
    /// The computed score value
    pub value: f64,

    /// Optional vector of match positions
    pub positions: Option<Vec<usize>>
}

impl Score {
    /// Creates a new Score from the provided needle and haystack
    ///
    /// # Examples
    ///
    /// ```
    /// use rff::fuzzy::Score;
    /// let score = Score::new("abc", "abc");
    /// assert_eq!(score.value, std::f64::INFINITY);
    /// ```
    pub fn new(needle: &str, haystack: &str) -> Score {
        ScoreBuilder::new(needle, haystack).calculate().as_score()
    }

    /// Creates a new Score from the provided needle and haystack, calculating
    /// match positions.
    ///
    /// # Examples
    ///
    /// ```
    /// use rff::fuzzy::Score;
    /// let score = Score::with_positions("abc", "abc");
    /// assert_eq!(score.value, std::f64::INFINITY);
    /// assert_eq!(score.positions, Some(vec![0, 1, 2]));
    /// ```
    pub fn with_positions(needle: &str, haystack: &str) -> Score {
        ScoreBuilder::new(needle, haystack).calculate().with_positions().as_score()
    }
}

impl PartialOrd for Score {
    #[inline]
    fn partial_cmp(&self, other: &Score) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl PartialEq for Score {
    #[inline]
    fn eq(&self, other: &Score) -> bool {
        self.value == other.value
    }
}

struct ScoreBuilder<'a> {
    needle: &'a str,
    haystack: &'a str,
    len_n: usize,
    len_h: usize,
    d: Option<Mat>,
    m: Option<Mat>,
    score: f64,
    positions: Option<Vec<usize>>
}

impl<'a> ScoreBuilder<'a> {
    #[inline]
    fn new(needle: &'a str, haystack: &'a str) -> ScoreBuilder<'a> {
        let len_n = needle.chars().count();
        let len_h = haystack.chars().count();

        ScoreBuilder {
            needle: needle,
            haystack: haystack,
            len_n: len_n,
            len_h: len_h,
            m: None,
            d: None,
            score: 0.0,
            positions: None
        }
    }

    #[inline]
    fn calculate(mut self) -> ScoreBuilder<'a> {
        if self.len_n == 0 {
            self.score = SCORE_MIN;
            return self;
        }

        if self.len_n == self.len_h {
            self.score = SCORE_MAX;
            return self;
        }

        if self.len_h > 1024 {
            // unreasonably large candidate
            self.score = SCORE_MIN;
            return self;
        }

        let bonus = compute_bonus(self.haystack);

        let mut m = Mat::new(self.len_n, self.len_h);
        let mut d = Mat::new(self.len_n, self.len_h);

        for (i, n) in self.needle.chars().enumerate() {
            let mut prev_score = SCORE_MIN;
            let gap_score = if i == self.len_n - 1 { SCORE_GAP_TRAILING } else { SCORE_GAP_INNER };

            for (j, h) in self.haystack.chars().enumerate() {
                if eq(n, h) {
                    let bonus_score = bonus[j];

                    let score = match i {
                        0 => ((j as f64) * SCORE_GAP_LEADING) + bonus_score,
                        _ if j > 0 => {
                            let m = m.get(i - 1, j - 1).unwrap();
                            let d = d.get(i - 1, j - 1).unwrap();

                            let m = m + bonus_score;
                            let d = d + SCORE_MATCH_CONSECUTIVE;

                            (m).max(d)
                        },
                        _ => SCORE_MIN
                    };

                    prev_score = score.max(prev_score + gap_score);

                    d.set(i, j, score);
                    m.set(i, j, prev_score);
                } else {
                    prev_score += gap_score;

                    d.set(i, j, SCORE_MIN);
                    m.set(i, j, prev_score);
                }
            }
        }

        self.score = m.get(self.len_n - 1, self.len_h - 1).unwrap_or(SCORE_MIN);

        self.m = Some(m);
        self.d = Some(d);

        self
    }

    #[inline]
    fn with_positions(mut self) -> ScoreBuilder<'a> {
        if self.len_n == self.len_h {
            self.positions = Some((0..self.len_n).collect());
        }

        if self.len_n == 0 || self.len_n == self.len_h || self.len_h > 1024 {
            return self;
        }

        let mut positions = vec![0 as usize; self.len_n];
        let mut match_required = false;

        {
            let m = self.m.as_ref().unwrap();
            let d = self.d.as_ref().unwrap();

            let mut j = self.len_h - 1;

            for i in (0..self.len_n).rev() {
                while j > (0 as usize) {
                    let last = if i > 0 && j > 0 { d.get(i - 1, j - 1).unwrap() } else { 0.0 };

                    let d = d.get(i, j).unwrap();
                    let m = m.get(i, j).unwrap();

                    if d != SCORE_MIN && (match_required || d == m) {
                        if i > 0 && j > 0 && m == last + SCORE_MATCH_CONSECUTIVE {
                            match_required = true;
                        }

                        positions[i] = j;

                        break;
                    }

                    j -= 1
                }
            }
        }

        self.positions = Some(positions);
        self
    }

    #[inline]
    fn as_score(self) -> Score {
        Score {
            value: self.score,
            positions: self.positions,
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;

    fn score(needle: &str, haystack: &str) -> Score {
        Score::new(needle, haystack)
    }

    #[test]
    fn test_eq() {
        let a = Score { value: 1.0, positions: None };
        let b = Score { value: 1.0, positions: None };
        assert_eq!(a, b);
    }

    #[test]
    fn test_cmp() {
        let a = Score { value: 2.0, positions: None };
        let b = Score { value: 1.0, positions: None };
        assert!(a > b);
        assert!(b < a);

        let b = Score { value: 2.0, positions: None };
        assert!(a == b);
    }

    #[test]
    fn relative_scores() {
        // App/Models/Order is better than App/MOdels/zRder
        assert!(score("amor", "app/models/order") > score("amor", "app/models/zrder"));

        // App/MOdels/foo is better than App/M/fOo
        assert!(score("amo", "app/m/foo") < score("amo", "app/models/foo"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // GEMFIle.Lock < GEMFILe
        assert!(score("gemfil", "Gemfile.lock") < score("gemfil", "Gemfile"));

        // Prefer shorter scorees
        assert!(score("abce", "abcdef") > score("abce", "abc de"));

        // Prefer shorter candidates
        assert!(score("test", "tests") > score("test", "testing"));

        // Scores first letter highly
        assert!(score("test", "testing") > score("test", "/testing"));

        // Prefer shorter scorees
        assert!(score("abc", "    a b c ") > score("abc", " a  b  c "));
        assert!(score("abc", " a b c    ") > score("abc", " a  b  c "));
    }

    #[test]
    fn score_utf8() {
        assert_eq!(score("ß", "öäßéè").value, -0.02);
    }

    #[test]
    fn positions() {
        macro_rules! test_positions {
            ($needle:expr, $haystack:expr, $result:expr) => {
                let score = Score::with_positions($needle, $haystack);
                assert_eq!(score.positions, Some($result));
            }
        }

        test_positions!("amo", "app/models/foo", vec![0, 4, 5]);
        test_positions!("amor", "app/models/order", vec![0, 4, 11, 12]);
        test_positions!("as", "tags", vec![1, 3]);
        test_positions!("abc", "a/a/b/c/c", vec![2, 4, 6]);
        test_positions!("foo", "foo", vec![0, 1, 2]);
        test_positions!("drivers", "/path/to/drivers/file.txt", vec![9, 10, 11, 12, 13, 14, 15]);
    }
}
<|endoftext|>


<commit_before>
use buffer::{ImageBuffer, Pixel, ArrayLike};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

use std::old_io;
use std::old_io::{MemReader, IoResult};
use std::num::Int;

use color::{Rgb, Rgba};
use utils::lzw;
use utils::bitstream::LsbWriter;

use super::{Extension, Block, DisposalMethod};

#[derive(Debug, Copy)]
#[allow(unused_qualifications)]
pub enum ColorMode {
	/// Image will be encoded in multiple frames if more than 256 colors are present
	TrueColor,
	/// Number of colors will be reduced
	Indexed(u8),
}
use self::ColorMode::{TrueColor, Indexed};

pub struct Encoder<Image> {
	image: Image,
	bg_color: Option<Rgb<u8>>,
	color_mode: ColorMode
}

const TRANSPARENT: Rgba<u8> = Rgba([0, 0, 0, 0]);

impl<Container> Encoder<ImageBuffer<Rgba<u8>, Container>>
where Container: ArrayLike<u8> {
	/// Creates a new gif encoder
	pub fn new(image: ImageBuffer<Rgba<u8>, Container>,
		       bg_color: Option<Rgb<u8>>,
		       color_mode: ColorMode,
		      ) -> Encoder<ImageBuffer<Rgba<u8>, Container>> {
		Encoder {
			image: image,
			bg_color: bg_color,
			color_mode: color_mode
		}
	}

	/// Encodes the gif
	pub fn encode<W: Writer>(&mut self, w: &mut W) -> IoResult<()> {
		// Header
		try!(w.write_all(b"GIF89a"));
		// Logical screen descriptor
		let height = self.image.height();
		let width = self.image.width();
		if width > <u16 as Int>::max_value() as u32 ||
		   height > <u16 as Int>::max_value() as u32 {
		   	return Err(old_io::IoError{
		   		kind: old_io::InvalidInput,
		   		desc: "Image dimensions are to large for the gif format.",
		   		detail: None
		   	})
		}
		try!(w.write_le_u16(width as u16));
		try!(w.write_le_u16(height as u16));

		let (hist, transparent) = self.histogram();
		let num_colors = hist.len();

		try!(self.write_global_table(w, &hist[]));

		match self.color_mode {
			// Global color table has been written, just write the image data now
			TrueColor if num_colors <= 256 => {
				try!(self.write_control_ext(w, 0, transparent));
				try!(self.write_descriptor(w, None));
				try!(self.write_data_simple(w, &hist[], transparent));
			},
			TrueColor => {
				panic!("TrueColor unimplemented")
			},
			Indexed(n) if n as usize <= num_colors => {
				try!(self.write_control_ext(w, 0, transparent));
				try!(self.write_descriptor(w, None));
				try!(self.write_data_simple(w, &hist[], transparent));
			}
			Indexed(_) => {
				panic!("Indexed(n) unimplemented")
			}

		}
		w.write_u8(Block::Trailer as u8)
	}

	/// Returns a histogram of the colors in the image
	fn histogram(&self) -> (Vec<(Rgba<u8>, usize)>, Option<usize>){
		let mut hist: HashMap<_, usize> = HashMap::new();
		// Add bg_color to table
		if let Some(bg_color) = self.bg_color {
			let _ = hist.insert(bg_color.to_rgba(), 0);
		}
		for p in self.image.pixels() {
			let mut p = *p;
			// Replace transparent pixels with black, alpha = 0
			if let Some(bg_color) = self.bg_color {
				p.blend(&bg_color.to_rgba())
			} else if p[3] != 255 {
				p = TRANSPARENT;
			}
			match hist.entry(p) {
				Occupied(mut entry) => {
					let val = entry.get_mut();
					*val = *val + 1;
				},
				Vacant(entry) => {
					entry.insert(1);
				}
			}
		}
		let mut colors: Vec<(Rgba<u8>, usize)> = hist.into_iter().collect();
		// Sort color map with decreasing color freqs
		colors.sort_by(|a, b| b.1.cmp(&a.1));
		// Add bg_color to table
		let transparent = colors.iter().position(|x| x.0 == TRANSPARENT);
		(colors, transparent)
	}

	/// Write the global color table and the corresponding flags
	fn write_global_table<W: Writer>(&mut self,
									 w: &mut W,
									 hist: &[(Rgba<u8>, usize)]
									) -> IoResult<()>
	{
		let num_colors = hist.len();
		let mut flags = 0;
		flags |= 1 << 4; // sort flag
		let n = flag_n(num_colors);
		flags |= n << 4; // 2^(n+1) colors
		let (global_table, bg_index) = if num_colors <= 256 {
			flags |= 1 << 7; // glocal table flag
			flags |= n;
			let mut bg_index = 0;
			let mut table = Vec::with_capacity(3*(2 << n));
			for (i, &(color, _)) in hist.iter().enumerate() {
				let channels = &color.channels()[..3];
				if let Some(bg_color) = self.bg_color {
					if channels == bg_color.channels() {
						bg_index = i;
					}
				}
				table.push_all(channels)
			}
			// Waste some space as of gif spec
			for _ in 0..((2 << n) - num_colors) {
				table.push_all(&[0, 0, 0]);
			}
			(Some(table), bg_index as u8)
		} else if let Some(bg_color) = self.bg_color {
			flags |= 1 << 7; // glocal table flag
			let mut table = Vec::with_capacity(6);
			table.push_all(&bg_color.channels()[..2]);
			table.push_all(&[0, 0, 0]);
			(Some(table), 0)
		} else {
			(None, 0)
		};
		try!(w.write_u8(flags));
		try!(w.write_u8(bg_index));
		try!(w.write_u8(0)); // aspect ration, disregard
		if let Some(global_table) = global_table {
			try!(w.write_all(&global_table[]));
		}
		Ok(())
	}

	/// Writes the graphics control extension
	fn write_control_ext<W: Writer>(&mut self,
								    w: &mut W,
								    delay: u16,
								    transparent: Option<usize>
								   ) -> IoResult<()>
	{
		try!(w.write_u8(Block::Extension as u8));
		try!(w.write_u8(Extension::Control as u8));
		try!(w.write_u8(4)); // size
		let mut field = 0;
		field |= (DisposalMethod::None as u8) << 2;
		let idx = if let Some(idx) = transparent {
			field |=  1;
			idx as u8
		} else {
			0
		};
		try!(w.write_u8(field));
		try!(w.write_le_u16(delay));
		try!(w.write_u8(idx));
		w.write_u8(0)
	}

	/// Writes the image descriptor
	fn write_descriptor<W: Writer>(&mut self,
								    w: &mut W,
								    table_len: Option<usize>
								   ) -> IoResult<()>
	{
		try!(w.write_u8(Block::Image as u8));
		try!(w.write_le_u16(0)); // left
		try!(w.write_le_u16(0)); // top
		let height = self.image.height();
		let width = self.image.width();
		try!(w.write_le_u16(width as u16));
		try!(w.write_le_u16(height as u16));
		if let Some(len) = table_len {
			w.write_u8(flag_n(len) | 0x80)
		} else {
			w.write_u8(0)
		}
	}

	/// Writes the image to the file assuming that every pixel is in the color table
	/// If not, the index of the transparent pixel is written
	fn write_data_simple<W: Writer>(&mut self,
								    w: &mut W,
								    hist: &[(Rgba<u8>, usize)],
								    transparent: Option<usize>
								   ) -> IoResult<()>
	{
		let code_size = match flag_n(hist.len()) + 1 {
			1 => 2,
			n => n
		};
		let t_idx = match transparent { Some(i) => i as u8, None => 0 };
		let data: Vec<u8> = self.image.pixels().map(|p| {
			if let Some(idx) = hist.iter().position(|x| x.0 == *p) {
				idx as u8
			} else {
				t_idx
			}
		}).collect();
		let mut encoded_data = Vec::new();
		try!(lzw::encode(MemReader::new(data), LsbWriter::new(&mut encoded_data), code_size));
		try!(w.write_u8(code_size));
		for chunk in encoded_data.chunks(255) {
			try!(w.write_u8((chunk.len()) as u8));
			try!(w.write_all(chunk));
		}
		w.write_u8(0) // block terminator

	}
}

// Color table len converted to flag bits
fn flag_n(size: usize) -> u8 {
	match size {
		0  ...2   => 0,
		3  ...4   => 1,
		5  ...8   => 2,
		7  ...16  => 3,
		17 ...32  => 4,
		33 ...64  => 5,
		65 ...128 => 6,
		129...256 => 7,
		_ => 7
	}
}<commit_msg>Add docs.<commit_after>
use buffer::{ImageBuffer, Pixel, ArrayLike};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

use std::old_io;
use std::old_io::{MemReader, IoResult};
use std::num::Int;

use color::{Rgb, Rgba};
use utils::lzw;
use utils::bitstream::LsbWriter;

use super::{Extension, Block, DisposalMethod};

#[derive(Debug, Copy)]
#[allow(unused_qualifications)]
/// The color mode the encoder will use to encode the image.
pub enum ColorMode {
	/// Image will be encoded in multiple frames if more than 256 colors are present
	TrueColor,
	/// Number of colors will be reduced
	Indexed(u8),
}
use self::ColorMode::{TrueColor, Indexed};

/// A GIF encoder.
///
/// Encodes the image either in true color using indexed colors.
/// If the mode is set to TrueColor the image is split into multiple frames
/// when the number of colors including transparent color exceeds 256.
/// Pixels with an alpha value != 1.0 will be set to alpha = 0.
pub struct Encoder<Image> {
	image: Image,
	bg_color: Option<Rgb<u8>>,
	color_mode: ColorMode
}

const TRANSPARENT: Rgba<u8> = Rgba([0, 0, 0, 0]);

impl<Container> Encoder<ImageBuffer<Rgba<u8>, Container>>
where Container: ArrayLike<u8> {
	/// Creates a new GIF encoder
	pub fn new(image: ImageBuffer<Rgba<u8>, Container>,
		       bg_color: Option<Rgb<u8>>,
		       color_mode: ColorMode,
		      ) -> Encoder<ImageBuffer<Rgba<u8>, Container>> {
		Encoder {
			image: image,
			bg_color: bg_color,
			color_mode: color_mode
		}
	}

	/// Encodes the image
	pub fn encode<W: Writer>(&mut self, w: &mut W) -> IoResult<()> {
		// Header
		try!(w.write_all(b"GIF89a"));
		// Logical screen descriptor
		let height = self.image.height();
		let width = self.image.width();
		if width > <u16 as Int>::max_value() as u32 ||
		   height > <u16 as Int>::max_value() as u32 {
		   	return Err(old_io::IoError{
		   		kind: old_io::InvalidInput,
		   		desc: "Image dimensions are to large for the gif format.",
		   		detail: None
		   	})
		}
		try!(w.write_le_u16(width as u16));
		try!(w.write_le_u16(height as u16));

		let (hist, transparent) = self.histogram();
		let num_colors = hist.len();

		try!(self.write_global_table(w, &hist[]));

		match self.color_mode {
			// Global color table has been written, just write the image data now
			TrueColor if num_colors <= 256 => {
				try!(self.write_control_ext(w, 0, transparent));
				try!(self.write_descriptor(w, None));
				try!(self.write_data_simple(w, &hist[], transparent));
			},
			TrueColor => {
				panic!("TrueColor unimplemented")
			},
			Indexed(n) if n as usize <= num_colors => {
				try!(self.write_control_ext(w, 0, transparent));
				try!(self.write_descriptor(w, None));
				try!(self.write_data_simple(w, &hist[], transparent));
			}
			Indexed(_) => {
				panic!("Indexed(n) unimplemented")
			}

		}
		w.write_u8(Block::Trailer as u8)
	}

	/// Returns a histogram of the colors in the image
	fn histogram(&self) -> (Vec<(Rgba<u8>, usize)>, Option<usize>){
		let mut hist: HashMap<_, usize> = HashMap::new();
		// Add bg_color to table
		if let Some(bg_color) = self.bg_color {
			let _ = hist.insert(bg_color.to_rgba(), 0);
		}
		for p in self.image.pixels() {
			let mut p = *p;
			// Replace transparent pixels with black, alpha = 0
			if let Some(bg_color) = self.bg_color {
				p.blend(&bg_color.to_rgba())
			} else if p[3] != 255 {
				p = TRANSPARENT;
			}
			match hist.entry(p) {
				Occupied(mut entry) => {
					let val = entry.get_mut();
					*val = *val + 1;
				},
				Vacant(entry) => {
					entry.insert(1);
				}
			}
		}
		let mut colors: Vec<(Rgba<u8>, usize)> = hist.into_iter().collect();
		// Sort color map with decreasing color freqs
		colors.sort_by(|a, b| b.1.cmp(&a.1));
		// Add bg_color to table
		let transparent = colors.iter().position(|x| x.0 == TRANSPARENT);
		(colors, transparent)
	}

	/// Write the global color table and the corresponding flags
	fn write_global_table<W: Writer>(&mut self,
									 w: &mut W,
									 hist: &[(Rgba<u8>, usize)]
									) -> IoResult<()>
	{
		let num_colors = hist.len();
		let mut flags = 0;
		flags |= 1 << 4; // sort flag
		let n = flag_n(num_colors);
		flags |= n << 4; // 2^(n+1) colors
		let (global_table, bg_index) = if num_colors <= 256 {
			flags |= 1 << 7; // glocal table flag
			flags |= n;
			let mut bg_index = 0;
			let mut table = Vec::with_capacity(3*(2 << n));
			for (i, &(color, _)) in hist.iter().enumerate() {
				let channels = &color.channels()[..3];
				if let Some(bg_color) = self.bg_color {
					if channels == bg_color.channels() {
						bg_index = i;
					}
				}
				table.push_all(channels)
			}
			// Waste some space as of gif spec
			for _ in 0..((2 << n) - num_colors) {
				table.push_all(&[0, 0, 0]);
			}
			(Some(table), bg_index as u8)
		} else if let Some(bg_color) = self.bg_color {
			flags |= 1 << 7; // glocal table flag
			let mut table = Vec::with_capacity(6);
			table.push_all(&bg_color.channels()[..2]);
			table.push_all(&[0, 0, 0]);
			(Some(table), 0)
		} else {
			(None, 0)
		};
		try!(w.write_u8(flags));
		try!(w.write_u8(bg_index));
		try!(w.write_u8(0)); // aspect ration, disregard
		if let Some(global_table) = global_table {
			try!(w.write_all(&global_table[]));
		}
		Ok(())
	}

	/// Writes the graphics control extension
	fn write_control_ext<W: Writer>(&mut self,
								    w: &mut W,
								    delay: u16,
								    transparent: Option<usize>
								   ) -> IoResult<()>
	{
		try!(w.write_u8(Block::Extension as u8));
		try!(w.write_u8(Extension::Control as u8));
		try!(w.write_u8(4)); // size
		let mut field = 0;
		field |= (DisposalMethod::None as u8) << 2;
		let idx = if let Some(idx) = transparent {
			field |=  1;
			idx as u8
		} else {
			0
		};
		try!(w.write_u8(field));
		try!(w.write_le_u16(delay));
		try!(w.write_u8(idx));
		w.write_u8(0)
	}

	/// Writes the image descriptor
	fn write_descriptor<W: Writer>(&mut self,
								    w: &mut W,
								    table_len: Option<usize>
								   ) -> IoResult<()>
	{
		try!(w.write_u8(Block::Image as u8));
		try!(w.write_le_u16(0)); // left
		try!(w.write_le_u16(0)); // top
		let height = self.image.height();
		let width = self.image.width();
		try!(w.write_le_u16(width as u16));
		try!(w.write_le_u16(height as u16));
		if let Some(len) = table_len {
			w.write_u8(flag_n(len) | 0x80)
		} else {
			w.write_u8(0)
		}
	}

	/// Writes the image to the file assuming that every pixel is in the color table
	/// If not, the index of the transparent pixel is written
	fn write_data_simple<W: Writer>(&mut self,
								    w: &mut W,
								    hist: &[(Rgba<u8>, usize)],
								    transparent: Option<usize>
								   ) -> IoResult<()>
	{
		let code_size = match flag_n(hist.len()) + 1 {
			1 => 2,
			n => n
		};
		let t_idx = match transparent { Some(i) => i as u8, None => 0 };
		let data: Vec<u8> = self.image.pixels().map(|p| {
			if let Some(idx) = hist.iter().position(|x| x.0 == *p) {
				idx as u8
			} else {
				t_idx
			}
		}).collect();
		let mut encoded_data = Vec::new();
		try!(lzw::encode(MemReader::new(data), LsbWriter::new(&mut encoded_data), code_size));
		try!(w.write_u8(code_size));
		for chunk in encoded_data.chunks(255) {
			try!(w.write_u8((chunk.len()) as u8));
			try!(w.write_all(chunk));
		}
		w.write_u8(0) // block terminator

	}
}

// Color table len converted to flag bits
fn flag_n(size: usize) -> u8 {
	match size {
		0  ...2   => 0,
		3  ...4   => 1,
		5  ...8   => 2,
		7  ...16  => 3,
		17 ...32  => 4,
		33 ...64  => 5,
		65 ...128 => 6,
		129...256 => 7,
		_ => 7
	}
}<|endoftext|>


<commit_before>use core::fmt;
use core::ops::{Index, IndexMut};

use super::{PageSize, PhysFrame, Size4KiB};
use addr::PhysAddr;

use usize_conversions::usize_from;
use ux::*;

/// The error returned by the `PageTableEntry::frame` method.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FrameError {
    /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame.
    FrameNotPresent,
    /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame
    /// as return type, so a huge frame can't be returned.
    HugeFrame,
}

/// A 64-bit page table entry.
#[derive(Clone)]
#[repr(transparent)]
pub struct PageTableEntry {
    entry: u64,
}

impl PageTableEntry {
    /// Returns whether this entry is zero.
    pub fn is_unused(&self) -> bool {
        self.entry == 0
    }

    /// Sets this entry to zero.
    pub fn set_unused(&mut self) {
        self.entry = 0;
    }

    /// Returns the flags of this entry.
    pub fn flags(&self) -> PageTableFlags {
        PageTableFlags::from_bits_truncate(self.entry)
    }

    /// Returns the physical address mapped by this entry, might be zero.
    pub fn addr(&self) -> PhysAddr {
        PhysAddr::new(self.entry & 0x000fffff_fffff000)
    }

    /// Returns the physical frame mapped by this entry.
    ///
    /// Returns the following errors:
    ///
    /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set.
    /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the
    ///    `addr` function must be used)
    pub fn frame(&self) -> Result<PhysFrame, FrameError> {
        if !self.flags().contains(PageTableFlags::PRESENT) {
            Err(FrameError::FrameNotPresent)
        } else if self.flags().contains(PageTableFlags::HUGE_PAGE) {
            Err(FrameError::HugeFrame)
        } else {
            Ok(PhysFrame::containing_address(self.addr()))
        }
    }

    /// Map the entry to the specified physical address with the specified flags.
    pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) {
        assert!(addr.is_aligned(Size4KiB::SIZE));
        self.entry = (addr.as_u64()) | flags.bits();
    }

    /// Map the entry to the specified physical frame with the specified flags.
    pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) {
        assert!(!flags.contains(PageTableFlags::HUGE_PAGE));
        self.set_addr(frame.start_address(), flags)
    }

    /// Sets the flags of this entry.
    pub fn set_flags(&mut self, flags: PageTableFlags) {
        self.entry = self.addr().as_u64() | flags.bits();
    }
}

impl fmt::Debug for PageTableEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut f = f.debug_struct("PageTableEntry");
        f.field("addr", &self.addr());
        f.field("flags", &self.flags());
        f.finish()
    }
}

bitflags! {
    /// Possible flags for a page table entry.
    pub struct PageTableFlags: u64 {
        /// Specifies whether the mapped frame or page table is loaded in memory.
        const PRESENT =         1 << 0;
        /// Controls whether writes to the mapped frames are allowed.
        ///
        /// If this bit is unset in a level 1 page table entry, the mapped frame is read-only.
        /// If this bit is unset in a higher level page table entry the complete range of mapped
        /// pages is read-only.
        const WRITABLE =        1 << 1;
        /// Controls whether accesses from userspace (i.e. ring 3) are permitted.
        const USER_ACCESSIBLE = 1 << 2;
        /// If this bit is set, a “write-through” policy is used for the cache, else a “write-back”
        /// policy is used.
        const WRITE_THROUGH =   1 << 3;
        /// Disables caching for the pointed entry is cacheable.
        const NO_CACHE =        1 << 4;
        /// Set by the CPU when the mapped frame or page table is accessed.
        const ACCESSED =        1 << 5;
        /// Set by the CPU on a write to the mapped frame.
        const DIRTY =           1 << 6;
        /// Specifies that the entry maps a huge frame instead of a page table. Only allowed in
        /// P2 or P3 tables.
        const HUGE_PAGE =       1 << 7;
        /// Indicates that the mapping is present in all address spaces, so it isn't flushed from
        /// the TLB on an address space switch.
        const GLOBAL =          1 << 8;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_9 =           1 << 9;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_10 =          1 << 10;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_11 =          1 << 11;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_52 =          1 << 52;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_53 =          1 << 53;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_54 =          1 << 54;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_55 =          1 << 55;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_56 =          1 << 56;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_57 =          1 << 57;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_58 =          1 << 58;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_59 =          1 << 59;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_60 =          1 << 60;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_61 =          1 << 61;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_62 =          1 << 62;
        /// Forbid code execution from the mapped frames.
        ///
        /// Can be only used when the no-execute page protection feature is enabled in the EFER
        /// register.
        const NO_EXECUTE =      1 << 63;
    }
}

/// The number of entries in a page table.
const ENTRY_COUNT: usize = 512;

/// Represents a page table.
///
/// Always page-sized.
///
/// This struct implements the `Index` and `IndexMut` traits, so the entries can be accessed
/// through index operations. For example, `page_table[15]` returns the 15th page table entry.
#[repr(transparent)]
pub struct PageTable {
    entries: [PageTableEntry; ENTRY_COUNT],
}

impl PageTable {
    /// Clears all entries.
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused();
        }
    }
}

impl Index<usize> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: usize) -> &Self::Output {
        &self.entries[index]
    }
}

impl IndexMut<usize> for PageTable {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.entries[index]
    }
}

impl Index<u9> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: u9) -> &Self::Output {
        &self.entries[usize_from(u16::from(index))]
    }
}

impl IndexMut<u9> for PageTable {
    fn index_mut(&mut self, index: u9) -> &mut Self::Output {
        &mut self.entries[usize_from(u16::from(index))]
    }
}

impl fmt::Debug for PageTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.entries[..].fmt(f)
    }
}
<commit_msg>Page tables must be page aligned<commit_after>use core::fmt;
use core::ops::{Index, IndexMut};

use super::{PageSize, PhysFrame, Size4KiB};
use addr::PhysAddr;

use usize_conversions::usize_from;
use ux::*;

/// The error returned by the `PageTableEntry::frame` method.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FrameError {
    /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame.
    FrameNotPresent,
    /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame
    /// as return type, so a huge frame can't be returned.
    HugeFrame,
}

/// A 64-bit page table entry.
#[derive(Clone)]
#[repr(transparent)]
pub struct PageTableEntry {
    entry: u64,
}

impl PageTableEntry {
    /// Returns whether this entry is zero.
    pub fn is_unused(&self) -> bool {
        self.entry == 0
    }

    /// Sets this entry to zero.
    pub fn set_unused(&mut self) {
        self.entry = 0;
    }

    /// Returns the flags of this entry.
    pub fn flags(&self) -> PageTableFlags {
        PageTableFlags::from_bits_truncate(self.entry)
    }

    /// Returns the physical address mapped by this entry, might be zero.
    pub fn addr(&self) -> PhysAddr {
        PhysAddr::new(self.entry & 0x000fffff_fffff000)
    }

    /// Returns the physical frame mapped by this entry.
    ///
    /// Returns the following errors:
    ///
    /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set.
    /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the
    ///    `addr` function must be used)
    pub fn frame(&self) -> Result<PhysFrame, FrameError> {
        if !self.flags().contains(PageTableFlags::PRESENT) {
            Err(FrameError::FrameNotPresent)
        } else if self.flags().contains(PageTableFlags::HUGE_PAGE) {
            Err(FrameError::HugeFrame)
        } else {
            Ok(PhysFrame::containing_address(self.addr()))
        }
    }

    /// Map the entry to the specified physical address with the specified flags.
    pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) {
        assert!(addr.is_aligned(Size4KiB::SIZE));
        self.entry = (addr.as_u64()) | flags.bits();
    }

    /// Map the entry to the specified physical frame with the specified flags.
    pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) {
        assert!(!flags.contains(PageTableFlags::HUGE_PAGE));
        self.set_addr(frame.start_address(), flags)
    }

    /// Sets the flags of this entry.
    pub fn set_flags(&mut self, flags: PageTableFlags) {
        self.entry = self.addr().as_u64() | flags.bits();
    }
}

impl fmt::Debug for PageTableEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut f = f.debug_struct("PageTableEntry");
        f.field("addr", &self.addr());
        f.field("flags", &self.flags());
        f.finish()
    }
}

bitflags! {
    /// Possible flags for a page table entry.
    pub struct PageTableFlags: u64 {
        /// Specifies whether the mapped frame or page table is loaded in memory.
        const PRESENT =         1 << 0;
        /// Controls whether writes to the mapped frames are allowed.
        ///
        /// If this bit is unset in a level 1 page table entry, the mapped frame is read-only.
        /// If this bit is unset in a higher level page table entry the complete range of mapped
        /// pages is read-only.
        const WRITABLE =        1 << 1;
        /// Controls whether accesses from userspace (i.e. ring 3) are permitted.
        const USER_ACCESSIBLE = 1 << 2;
        /// If this bit is set, a “write-through” policy is used for the cache, else a “write-back”
        /// policy is used.
        const WRITE_THROUGH =   1 << 3;
        /// Disables caching for the pointed entry is cacheable.
        const NO_CACHE =        1 << 4;
        /// Set by the CPU when the mapped frame or page table is accessed.
        const ACCESSED =        1 << 5;
        /// Set by the CPU on a write to the mapped frame.
        const DIRTY =           1 << 6;
        /// Specifies that the entry maps a huge frame instead of a page table. Only allowed in
        /// P2 or P3 tables.
        const HUGE_PAGE =       1 << 7;
        /// Indicates that the mapping is present in all address spaces, so it isn't flushed from
        /// the TLB on an address space switch.
        const GLOBAL =          1 << 8;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_9 =           1 << 9;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_10 =          1 << 10;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_11 =          1 << 11;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_52 =          1 << 52;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_53 =          1 << 53;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_54 =          1 << 54;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_55 =          1 << 55;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_56 =          1 << 56;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_57 =          1 << 57;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_58 =          1 << 58;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_59 =          1 << 59;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_60 =          1 << 60;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_61 =          1 << 61;
        /// Available to the OS, can be used to store additional data, e.g. custom flags.
        const BIT_62 =          1 << 62;
        /// Forbid code execution from the mapped frames.
        ///
        /// Can be only used when the no-execute page protection feature is enabled in the EFER
        /// register.
        const NO_EXECUTE =      1 << 63;
    }
}

/// The number of entries in a page table.
const ENTRY_COUNT: usize = 512;

/// Represents a page table.
///
/// Always page-sized.
///
/// This struct implements the `Index` and `IndexMut` traits, so the entries can be accessed
/// through index operations. For example, `page_table[15]` returns the 15th page table entry.
#[repr(align(4096))]
pub struct PageTable {
    entries: [PageTableEntry; ENTRY_COUNT],
}

impl PageTable {
    /// Clears all entries.
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused();
        }
    }
}

impl Index<usize> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: usize) -> &Self::Output {
        &self.entries[index]
    }
}

impl IndexMut<usize> for PageTable {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.entries[index]
    }
}

impl Index<u9> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: u9) -> &Self::Output {
        &self.entries[usize_from(u16::from(index))]
    }
}

impl IndexMut<u9> for PageTable {
    fn index_mut(&mut self, index: u9) -> &mut Self::Output {
        &mut self.entries[usize_from(u16::from(index))]
    }
}

impl fmt::Debug for PageTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.entries[..].fmt(f)
    }
}
<|endoftext|>


<commit_before>iface foo { fn foo(); }

impl of int for uint { fn foo() {} } //~ ERROR interface

fn main() {}
<commit_msg>test: Change the expected error message on iface-test.rs to contain "trait" instead of "interface"<commit_after>iface foo { fn foo(); }

impl of int for uint { fn foo() {} } //~ ERROR trait

fn main() {}
<|endoftext|>