<commit_before>//! Intermediate representation for C/C++ enumerations.

use super::context::{BindgenContext, TypeId};
use super::item::Item;
use super::super::codegen::EnumVariation;
use super::ty::TypeKind;
use clang;
use ir::annotations::Annotations;
use ir::item::ItemCanonicalPath;
use parse::{ClangItemParser, ParseError};
use regex_set::RegexSet;

/// An enum representing custom handling that can be given to a variant.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EnumVariantCustomBehavior {
    /// This variant will be a module containing constants.
    ModuleConstify,
    /// This variant will be constified, that is, forced to generate a constant.
    Constify,
    /// This variant will be hidden entirely from the resulting enum.
    Hide,
}

/// A C/C++ enumeration.
#[derive(Debug)]
pub struct Enum {
    /// The representation used for this enum; it should be an `IntKind` type or
    /// an alias to one.
    ///
    /// It's `None` if the enum is a forward declaration and isn't defined
    /// anywhere else, see `tests/headers/func_ptr_in_struct.h`.
    repr: Option<TypeId>,

    /// The different variants, with explicit values.
    variants: Vec<EnumVariant>,
}

impl Enum {
    /// Construct a new `Enum` with the given representation and variants.
    pub fn new(repr: Option<TypeId>, variants: Vec<EnumVariant>) -> Self {
        Enum {
            repr,
            variants,
        }
    }

    /// Get this enumeration's representation.
    pub fn repr(&self) -> Option<TypeId> {
        self.repr
    }

    /// Get this enumeration's variants.
    pub fn variants(&self) -> &[EnumVariant] {
        &self.variants
    }

    /// Construct an enumeration from the given Clang type.
    pub fn from_ty(
        ty: &clang::Type,
        ctx: &mut BindgenContext,
    ) -> Result<Self, ParseError> {
        use clang_sys::*;
        debug!("Enum::from_ty {:?}", ty);

        if ty.kind() != CXType_Enum {
            return Err(ParseError::Continue);
        }

        let declaration = ty.declaration().canonical();
        let repr = declaration.enum_type().and_then(|et| {
            Item::from_ty(&et, declaration, None, ctx).ok()
        });
        let mut variants = vec![];

        // Assume signedness since the default type by the C standard is an int.
        let is_signed = repr.and_then(
            |r| ctx.resolve_type(r).safe_canonical_type(ctx),
        ).map_or(true, |ty| match *ty.kind() {
                TypeKind::Int(ref int_kind) => int_kind.is_signed(),
                ref other => {
                    panic!("Since when enums can be non-integers? {:?}", other)
                }
            });

        let type_name = ty.spelling();
        let type_name = if type_name.is_empty() {
            None
        } else {
            Some(type_name)
        };
        let type_name = type_name.as_ref().map(String::as_str);

        let definition = declaration.definition().unwrap_or(declaration);
        definition.visit(|cursor| {
            if cursor.kind() == CXCursor_EnumConstantDecl {
                let value = if is_signed {
                    cursor.enum_val_signed().map(EnumVariantValue::Signed)
                } else {
                    cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned)
                };
                if let Some(val) = value {
                    let name = cursor.spelling();
                    let annotations = Annotations::new(&cursor);
                    let custom_behavior = ctx.parse_callbacks()
                        .and_then(|callbacks| {
                            callbacks.enum_variant_behavior(type_name, &name, val)
                        })
                        .or_else(|| {
                            let annotations = annotations.as_ref()?;
                            if annotations.hide() {
                                Some(EnumVariantCustomBehavior::Hide)
                            } else if annotations.constify_enum_variant() {
                                Some(EnumVariantCustomBehavior::Constify)
                            } else {
                                None
                            }
                        });

                    let name = ctx.parse_callbacks()
                        .and_then(|callbacks| {
                            callbacks.enum_variant_name(type_name, &name, val)
                        })
                        .or_else(|| {
                            annotations.as_ref()?.use_instead_of()?.last().cloned()
                        })
                        .unwrap_or(name);

                    let comment = cursor.raw_comment();
                    variants.push(EnumVariant::new(
                        name,
                        comment,
                        val,
                        custom_behavior,
                    ));
                }
            }
            CXChildVisit_Continue
        });
        Ok(Enum::new(repr, variants))
    }

    fn is_matching_enum(&self, ctx: &BindgenContext, enums: &RegexSet, item: &Item) -> bool {
        let path = item.canonical_path(ctx);
        let enum_ty = item.expect_type();

        let path_matches = enums.matches(&path[1..].join("::"));
        let enum_is_anon = enum_ty.name().is_none();
        let a_variant_matches = self.variants().iter().any(|v| {
            enums.matches(&v.name())
        });
        path_matches || (enum_is_anon && a_variant_matches)
    }

    /// Whether the enum was explicitly specified to be a bitfield.
    fn is_bitfield(&self, ctx: &BindgenContext, item: &Item) -> bool {
        self.is_matching_enum(ctx, &ctx.options().bitfield_enums, item)
    }

    /// Whether the enum was explicitly specified to be an constified enum
    /// module.
    fn is_constified_enum_module(&self, ctx: &BindgenContext, item: &Item) -> bool {
        self.is_matching_enum(ctx, &ctx.options().constified_enum_modules, item)
    }

    /// Whether the enum was explicitly specified to be an set of constants.
    fn is_constified_enum(&self, ctx: &BindgenContext, item: &Item) -> bool {
        self.is_matching_enum(ctx, &ctx.options().constified_enums, item)
    }

    /// Whether the enum was explicitly specified to be a Rust enum.
    fn is_rustified_enum(&self, ctx: &BindgenContext, item: &Item) -> bool {
        self.is_matching_enum(ctx, &ctx.options().rustified_enums, item)
    }

    /// Returns the final representation of the enum.
    pub fn computed_enum_variation(&self, ctx: &BindgenContext, item: &Item) -> EnumVariation {
        // ModuleConsts has higher precedence before Rust in order to avoid
        // problems with overlapping match patterns.
        if self.is_constified_enum_module(ctx, item) {
            EnumVariation::ModuleConsts
        } else if self.is_bitfield(ctx, item) {
            EnumVariation::Bitfield
        } else if self.is_rustified_enum(ctx, item) {
            EnumVariation::Rust
        } else if self.is_constified_enum(ctx, item) {
            EnumVariation::Consts
        } else {
            ctx.options().default_enum_style
        }
    }
}

/// A single enum variant, to be contained only in an enum.
#[derive(Debug)]
pub struct EnumVariant {
    /// The name of the variant.
    name: String,

    /// An optional doc comment.
    comment: Option<String>,

    /// The integer value of the variant.
    val: EnumVariantValue,

    /// The custom behavior this variant may have, if any.
    custom_behavior: Option<EnumVariantCustomBehavior>,
}

/// A constant value assigned to an enumeration variant.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EnumVariantValue {
    /// A signed constant.
    Signed(i64),

    /// An unsigned constant.
    Unsigned(u64),
}

impl EnumVariant {
    /// Construct a new enumeration variant from the given parts.
    pub fn new(
        name: String,
        comment: Option<String>,
        val: EnumVariantValue,
        custom_behavior: Option<EnumVariantCustomBehavior>,
    ) -> Self {
        EnumVariant {
            name,
            comment,
            val,
            custom_behavior,
        }
    }

    /// Get this variant's name.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get this variant's value.
    pub fn val(&self) -> EnumVariantValue {
        self.val
    }

    /// Get this variant's documentation.
    pub fn comment(&self) -> Option<&str> {
        self.comment.as_ref().map(|s| &**s)
    }

    /// Returns whether this variant should be enforced to be a constant by code
    /// generation.
    pub fn force_constification(&self) -> bool {
        self.custom_behavior.map_or(false, |b| {
            b == EnumVariantCustomBehavior::Constify
        })
    }

    /// Returns whether the current variant should be hidden completely from the
    /// resulting rust enum.
    pub fn hidden(&self) -> bool {
        self.custom_behavior.map_or(false, |b| {
            b == EnumVariantCustomBehavior::Hide
        })
    }
}
<commit_msg>Minor cleanup after #1419.<commit_after>//! Intermediate representation for C/C++ enumerations.

use super::context::{BindgenContext, TypeId};
use super::item::Item;
use super::super::codegen::EnumVariation;
use super::ty::TypeKind;
use clang;
use ir::annotations::Annotations;
use ir::item::ItemCanonicalPath;
use parse::{ClangItemParser, ParseError};
use regex_set::RegexSet;

/// An enum representing custom handling that can be given to a variant.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EnumVariantCustomBehavior {
    /// This variant will be a module containing constants.
    ModuleConstify,
    /// This variant will be constified, that is, forced to generate a constant.
    Constify,
    /// This variant will be hidden entirely from the resulting enum.
    Hide,
}

/// A C/C++ enumeration.
#[derive(Debug)]
pub struct Enum {
    /// The representation used for this enum; it should be an `IntKind` type or
    /// an alias to one.
    ///
    /// It's `None` if the enum is a forward declaration and isn't defined
    /// anywhere else, see `tests/headers/func_ptr_in_struct.h`.
    repr: Option<TypeId>,

    /// The different variants, with explicit values.
    variants: Vec<EnumVariant>,
}

impl Enum {
    /// Construct a new `Enum` with the given representation and variants.
    pub fn new(repr: Option<TypeId>, variants: Vec<EnumVariant>) -> Self {
        Enum {
            repr,
            variants,
        }
    }

    /// Get this enumeration's representation.
    pub fn repr(&self) -> Option<TypeId> {
        self.repr
    }

    /// Get this enumeration's variants.
    pub fn variants(&self) -> &[EnumVariant] {
        &self.variants
    }

    /// Construct an enumeration from the given Clang type.
    pub fn from_ty(
        ty: &clang::Type,
        ctx: &mut BindgenContext,
    ) -> Result<Self, ParseError> {
        use clang_sys::*;
        debug!("Enum::from_ty {:?}", ty);

        if ty.kind() != CXType_Enum {
            return Err(ParseError::Continue);
        }

        let declaration = ty.declaration().canonical();
        let repr = declaration.enum_type().and_then(|et| {
            Item::from_ty(&et, declaration, None, ctx).ok()
        });
        let mut variants = vec![];

        // Assume signedness since the default type by the C standard is an int.
        let is_signed = repr.and_then(
            |r| ctx.resolve_type(r).safe_canonical_type(ctx),
        ).map_or(true, |ty| match *ty.kind() {
                TypeKind::Int(ref int_kind) => int_kind.is_signed(),
                ref other => {
                    panic!("Since when enums can be non-integers? {:?}", other)
                }
            });

        let type_name = ty.spelling();
        let type_name = if type_name.is_empty() {
            None
        } else {
            Some(type_name)
        };
        let type_name = type_name.as_ref().map(String::as_str);

        let definition = declaration.definition().unwrap_or(declaration);
        definition.visit(|cursor| {
            if cursor.kind() == CXCursor_EnumConstantDecl {
                let value = if is_signed {
                    cursor.enum_val_signed().map(EnumVariantValue::Signed)
                } else {
                    cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned)
                };
                if let Some(val) = value {
                    let name = cursor.spelling();
                    let annotations = Annotations::new(&cursor);
                    let custom_behavior = ctx.parse_callbacks()
                        .and_then(|callbacks| {
                            callbacks.enum_variant_behavior(type_name, &name, val)
                        })
                        .or_else(|| {
                            let annotations = annotations.as_ref()?;
                            if annotations.hide() {
                                Some(EnumVariantCustomBehavior::Hide)
                            } else if annotations.constify_enum_variant() {
                                Some(EnumVariantCustomBehavior::Constify)
                            } else {
                                None
                            }
                        });

                    let name = ctx.parse_callbacks()
                        .and_then(|callbacks| {
                            callbacks.enum_variant_name(type_name, &name, val)
                        })
                        .or_else(|| {
                            annotations.as_ref()?.use_instead_of()?.last().cloned()
                        })
                        .unwrap_or(name);

                    let comment = cursor.raw_comment();
                    variants.push(EnumVariant::new(
                        name,
                        comment,
                        val,
                        custom_behavior,
                    ));
                }
            }
            CXChildVisit_Continue
        });
        Ok(Enum::new(repr, variants))
    }

    fn is_matching_enum(&self, ctx: &BindgenContext, enums: &RegexSet, item: &Item) -> bool {
        let path = item.canonical_path(ctx);
        let enum_ty = item.expect_type();

        if enums.matches(&path[1..].join("::")) {
            return true;
        }

        // Test the variants if the enum is anonymous.
        if enum_ty.name().is_some() {
            return false;
        }

        self.variants().iter().any(|v| enums.matches(&v.name()))
    }

    /// Returns the final representation of the enum.
    pub fn computed_enum_variation(&self, ctx: &BindgenContext, item: &Item) -> EnumVariation {
        // ModuleConsts has higher precedence before Rust in order to avoid
        // problems with overlapping match patterns.
        if self.is_matching_enum(ctx, &ctx.options().constified_enum_modules, item) {
            EnumVariation::ModuleConsts
        } else if self.is_matching_enum(ctx, &ctx.options().bitfield_enums, item) {
            EnumVariation::Bitfield
        } else if self.is_matching_enum(ctx, &ctx.options().rustified_enums, item) {
            EnumVariation::Rust
        } else if self.is_matching_enum(ctx, &ctx.options().constified_enums, item) {
            EnumVariation::Consts
        } else {
            ctx.options().default_enum_style
        }
    }
}

/// A single enum variant, to be contained only in an enum.
#[derive(Debug)]
pub struct EnumVariant {
    /// The name of the variant.
    name: String,

    /// An optional doc comment.
    comment: Option<String>,

    /// The integer value of the variant.
    val: EnumVariantValue,

    /// The custom behavior this variant may have, if any.
    custom_behavior: Option<EnumVariantCustomBehavior>,
}

/// A constant value assigned to an enumeration variant.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EnumVariantValue {
    /// A signed constant.
    Signed(i64),

    /// An unsigned constant.
    Unsigned(u64),
}

impl EnumVariant {
    /// Construct a new enumeration variant from the given parts.
    pub fn new(
        name: String,
        comment: Option<String>,
        val: EnumVariantValue,
        custom_behavior: Option<EnumVariantCustomBehavior>,
    ) -> Self {
        EnumVariant {
            name,
            comment,
            val,
            custom_behavior,
        }
    }

    /// Get this variant's name.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get this variant's value.
    pub fn val(&self) -> EnumVariantValue {
        self.val
    }

    /// Get this variant's documentation.
    pub fn comment(&self) -> Option<&str> {
        self.comment.as_ref().map(|s| &**s)
    }

    /// Returns whether this variant should be enforced to be a constant by code
    /// generation.
    pub fn force_constification(&self) -> bool {
        self.custom_behavior.map_or(false, |b| {
            b == EnumVariantCustomBehavior::Constify
        })
    }

    /// Returns whether the current variant should be hidden completely from the
    /// resulting rust enum.
    pub fn hidden(&self) -> bool {
        self.custom_behavior.map_or(false, |b| {
            b == EnumVariantCustomBehavior::Hide
        })
    }
}
<|endoftext|>


<commit_before>//! Issues interface

extern crate serde_json;

use super::{Github, Result};
use comments::Comments;
use users::User;
use labels::Label;
use super::SortDirection;
use std::fmt;
use std::collections::HashMap;
use url::form_urlencoded;

/// enum representation of github pull and issue state
#[derive(Clone, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            State::Open => "open",
            State::Closed => "closed",
            State::All => "all",
        }.fmt(f)
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// Sort options available for github issues
#[derive(Clone, Debug, PartialEq)]
pub enum Sort {
    /// sort by creation time of issue
    Created,
    /// sort by the last time issue was updated
    Updated,
    /// sort by number of comments
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Sort::Created => "created",
            Sort::Updated => "updated",
            Sort::Comments => "comments",
        }.fmt(f)
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

/// Provides access to label operations available for an individual issues
pub struct IssueLabels<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    #[doc(hidden)]
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueLabels<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}/labels{}",
            self.owner,
            self.repo,
            self.number,
            more
        )
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.post::<Vec<Label>>(
            &self.path(""),
            serde_json::to_string(&labels)?.as_bytes(),
        )
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github.delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(
            &self.path(""),
            serde_json::to_string(&labels)?.as_bytes(),
        )
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github.delete(&self.path(""))
    }
}

/// Provides access to operations available for a single issue
/// Typically accessed from `github.repo(.., ..).issues().get(number)`
pub struct IssueRef<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueRef<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    /// Request an issue's information
    pub fn get(&self) -> Result<Issue> {
        self.github.get::<Issue>(&self.path(""))
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}{}",
            self.owner,
            self.repo,
            self.number,
            more
        )
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(
            self.github,
            self.owner.as_str(),
            self.repo.as_str(),
            self.number,
        )
    }

    pub fn edit(&self, is: &IssueOptions) -> Result<Issue> {
        let data = serde_json::to_string(&is)?;
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn comments(&self) -> Comments {
        Comments::new(
            self.github,
            self.owner.clone(),
            self.repo.clone(),
            self.number,
        )
    }
}

/// Provides access to operations available for a repository issues
/// Typically accessed via `github.repo(..., ...).issues()`
pub struct Issues<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R) -> Issues<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_str(), self.repo.as_str(), number)
    }

    pub fn create(&self, is: &IssueOptions) -> Result<Issue> {
        let data = serde_json::to_string(&is)?;
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self, options: &IssueListOptions) -> Result<Vec<Issue>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get::<Vec<Issue>>(&uri.join("?"))
    }
}

// representations

// todo: simplify with param
#[derive(Default)]
pub struct IssueListOptions {
    params: HashMap<&'static str, String>,
}

impl IssueListOptions {
    pub fn builder() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder::new()
    }

    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// a mutable issue list builder
pub struct IssueListOptionsBuilder(IssueListOptions);

impl IssueListOptionsBuilder {
    pub fn new() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder(IssueListOptions { ..Default::default() })
    }

    pub fn state(&mut self, state: State) -> &mut IssueListOptionsBuilder {
        self.0.params.insert("state", state.to_string());
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut IssueListOptionsBuilder {
        self.0.params.insert("sort", sort.to_string());
        self
    }

    pub fn asc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Asc)
    }

    pub fn desc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Desc)
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut IssueListOptionsBuilder {
        self.0.params.insert("direction", direction.to_string());
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut IssueListOptionsBuilder
    where
        A: Into<String>,
    {
        self.0.params.insert("assignee", assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut IssueListOptionsBuilder
    where
        C: Into<String>,
    {
        self.0.params.insert("creator", creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut IssueListOptionsBuilder
    where
        M: Into<String>,
    {
        self.0.params.insert("mentioned", mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut IssueListOptionsBuilder
    where
        L: Into<String>,
    {
        self.0.params.insert(
            "labels",
            labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<_>>()
                .join(","),
        );
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut IssueListOptionsBuilder
    where
        S: Into<String>,
    {
        self.0.params.insert("since", since.into());
        self
    }

    pub fn build(&self) -> IssueListOptions {
        IssueListOptions { params: self.0.params.clone() }
    }
}

#[derive(Debug, Serialize)]
pub struct IssueOptions {
    pub title: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub assignee: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub milestone: Option<u64>,
    pub labels: Vec<String>,
}

impl IssueOptions {
    pub fn new<T, B, A, L>(
        title: T,
        body: Option<B>,
        assignee: Option<A>,
        milestone: Option<u64>,
        labels: Vec<L>,
    ) -> IssueOptions
    where
        T: Into<String>,
        B: Into<String>,
        A: Into<String>,
        L: Into<String>,
    {
        IssueOptions {
            title: title.into(),
            body: body.map(|b| b.into()),
            assignee: assignee.map(|a| a.into()),
            milestone: milestone,
            labels: labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<String>>(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Issue {
    pub id: u64,
    pub url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub number: u64,
    pub state: String,
    pub title: String,
    pub body: String,
    pub user: User,
    pub labels: Vec<Label>,
    pub assignee: Option<User>,
    pub locked: bool,
    pub comments: u64,
    pub closed_at: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

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

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn issue_list_reqs() {
        fn test_serialize(tests: Vec<(IssueListOptions, Option<String>)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (IssueListOptions::builder().build(), None),
            (
                IssueListOptions::builder().state(State::Closed).build(),
                Some("state=closed".to_owned())
            ),
            (
                IssueListOptions::builder()
                    .labels(vec!["foo", "bar"])
                    .build(),
                Some("labels=foo%2Cbar".to_owned())
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in vec![
            (Sort::Created, "created"),
            (Sort::Updated, "updated"),
            (Sort::Comments, "comments"),
        ]
        {
            assert_eq!(k.to_string(), v)
        }
    }
}
<commit_msg>Issue: make body an Option<commit_after>//! Issues interface

extern crate serde_json;

use super::{Github, Result};
use comments::Comments;
use users::User;
use labels::Label;
use super::SortDirection;
use std::fmt;
use std::collections::HashMap;
use url::form_urlencoded;

/// enum representation of github pull and issue state
#[derive(Clone, Debug, PartialEq)]
pub enum State {
    /// Only open issues
    Open,
    /// Only closed issues
    Closed,
    /// All issues, open or closed
    All,
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            State::Open => "open",
            State::Closed => "closed",
            State::All => "all",
        }.fmt(f)
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// Sort options available for github issues
#[derive(Clone, Debug, PartialEq)]
pub enum Sort {
    /// sort by creation time of issue
    Created,
    /// sort by the last time issue was updated
    Updated,
    /// sort by number of comments
    Comments,
}

impl fmt::Display for Sort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Sort::Created => "created",
            Sort::Updated => "updated",
            Sort::Comments => "comments",
        }.fmt(f)
    }
}

impl Default for Sort {
    fn default() -> Sort {
        Sort::Created
    }
}

/// Provides access to label operations available for an individual issues
pub struct IssueLabels<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueLabels<'a> {
    #[doc(hidden)]
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueLabels<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueLabels {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}/labels{}",
            self.owner,
            self.repo,
            self.number,
            more
        )
    }

    /// add a set of labels to this issue ref
    pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.post::<Vec<Label>>(
            &self.path(""),
            serde_json::to_string(&labels)?.as_bytes(),
        )
    }

    /// remove a label from this issue
    pub fn remove(&self, label: &str) -> Result<()> {
        self.github.delete(&self.path(&format!("/{}", label)))
    }

    /// replace all labels associated with this issue with a new set.
    /// providing an empty set of labels is the same as clearing the
    /// current labels
    pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
        self.github.put::<Vec<Label>>(
            &self.path(""),
            serde_json::to_string(&labels)?.as_bytes(),
        )
    }

    /// remove all labels from an issue
    pub fn clear(&self) -> Result<()> {
        self.github.delete(&self.path(""))
    }
}

/// Provides access to operations available for a single issue
/// Typically accessed from `github.repo(.., ..).issues().get(number)`
pub struct IssueRef<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
    number: u64,
}

impl<'a> IssueRef<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R, number: u64) -> IssueRef<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        IssueRef {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
            number: number,
        }
    }

    /// Request an issue's information
    pub fn get(&self) -> Result<Issue> {
        self.github.get::<Issue>(&self.path(""))
    }

    fn path(&self, more: &str) -> String {
        format!(
            "/repos/{}/{}/issues/{}{}",
            self.owner,
            self.repo,
            self.number,
            more
        )
    }

    pub fn labels(&self) -> IssueLabels {
        IssueLabels::new(
            self.github,
            self.owner.as_str(),
            self.repo.as_str(),
            self.number,
        )
    }

    pub fn edit(&self, is: &IssueOptions) -> Result<Issue> {
        let data = serde_json::to_string(&is)?;
        self.github.patch::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn comments(&self) -> Comments {
        Comments::new(
            self.github,
            self.owner.clone(),
            self.repo.clone(),
            self.number,
        )
    }
}

/// Provides access to operations available for a repository issues
/// Typically accessed via `github.repo(..., ...).issues()`
pub struct Issues<'a> {
    github: &'a Github,
    owner: String,
    repo: String,
}

impl<'a> Issues<'a> {
    /// create a new instance of a github repo issue ref
    pub fn new<O, R>(github: &'a Github, owner: O, repo: R) -> Issues<'a>
    where
        O: Into<String>,
        R: Into<String>,
    {
        Issues {
            github: github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
    }

    pub fn get(&self, number: u64) -> IssueRef {
        IssueRef::new(self.github, self.owner.as_str(), self.repo.as_str(), number)
    }

    pub fn create(&self, is: &IssueOptions) -> Result<Issue> {
        let data = serde_json::to_string(&is)?;
        self.github.post::<Issue>(&self.path(""), data.as_bytes())
    }

    pub fn list(&self, options: &IssueListOptions) -> Result<Vec<Issue>> {
        let mut uri = vec![self.path("")];
        if let Some(query) = options.serialize() {
            uri.push(query);
        }
        self.github.get::<Vec<Issue>>(&uri.join("?"))
    }
}

// representations

// todo: simplify with param
#[derive(Default)]
pub struct IssueListOptions {
    params: HashMap<&'static str, String>,
}

impl IssueListOptions {
    pub fn builder() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder::new()
    }

    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// a mutable issue list builder
pub struct IssueListOptionsBuilder(IssueListOptions);

impl IssueListOptionsBuilder {
    pub fn new() -> IssueListOptionsBuilder {
        IssueListOptionsBuilder(IssueListOptions { ..Default::default() })
    }

    pub fn state(&mut self, state: State) -> &mut IssueListOptionsBuilder {
        self.0.params.insert("state", state.to_string());
        self
    }

    pub fn sort(&mut self, sort: Sort) -> &mut IssueListOptionsBuilder {
        self.0.params.insert("sort", sort.to_string());
        self
    }

    pub fn asc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Asc)
    }

    pub fn desc(&mut self) -> &mut IssueListOptionsBuilder {
        self.direction(SortDirection::Desc)
    }

    pub fn direction(&mut self, direction: SortDirection) -> &mut IssueListOptionsBuilder {
        self.0.params.insert("direction", direction.to_string());
        self
    }

    pub fn assignee<A>(&mut self, assignee: A) -> &mut IssueListOptionsBuilder
    where
        A: Into<String>,
    {
        self.0.params.insert("assignee", assignee.into());
        self
    }

    pub fn creator<C>(&mut self, creator: C) -> &mut IssueListOptionsBuilder
    where
        C: Into<String>,
    {
        self.0.params.insert("creator", creator.into());
        self
    }

    pub fn mentioned<M>(&mut self, mentioned: M) -> &mut IssueListOptionsBuilder
    where
        M: Into<String>,
    {
        self.0.params.insert("mentioned", mentioned.into());
        self
    }

    pub fn labels<L>(&mut self, labels: Vec<L>) -> &mut IssueListOptionsBuilder
    where
        L: Into<String>,
    {
        self.0.params.insert(
            "labels",
            labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<_>>()
                .join(","),
        );
        self
    }

    pub fn since<S>(&mut self, since: S) -> &mut IssueListOptionsBuilder
    where
        S: Into<String>,
    {
        self.0.params.insert("since", since.into());
        self
    }

    pub fn build(&self) -> IssueListOptions {
        IssueListOptions { params: self.0.params.clone() }
    }
}

#[derive(Debug, Serialize)]
pub struct IssueOptions {
    pub title: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub assignee: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub milestone: Option<u64>,
    pub labels: Vec<String>,
}

impl IssueOptions {
    pub fn new<T, B, A, L>(
        title: T,
        body: Option<B>,
        assignee: Option<A>,
        milestone: Option<u64>,
        labels: Vec<L>,
    ) -> IssueOptions
    where
        T: Into<String>,
        B: Into<String>,
        A: Into<String>,
        L: Into<String>,
    {
        IssueOptions {
            title: title.into(),
            body: body.map(|b| b.into()),
            assignee: assignee.map(|a| a.into()),
            milestone: milestone,
            labels: labels
                .into_iter()
                .map(|l| l.into())
                .collect::<Vec<String>>(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Issue {
    pub id: u64,
    pub url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub number: u64,
    pub state: String,
    pub title: String,
    pub body: Option<String>,
    pub user: User,
    pub labels: Vec<Label>,
    pub assignee: Option<User>,
    pub locked: bool,
    pub comments: u64,
    pub closed_at: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

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

    #[test]
    fn default_state() {
        let default: State = Default::default();
        assert_eq!(default, State::Open)
    }

    #[test]
    fn issue_list_reqs() {
        fn test_serialize(tests: Vec<(IssueListOptions, Option<String>)>) {
            for test in tests {
                match test {
                    (k, v) => assert_eq!(k.serialize(), v),
                }
            }
        }
        let tests = vec![
            (IssueListOptions::builder().build(), None),
            (
                IssueListOptions::builder().state(State::Closed).build(),
                Some("state=closed".to_owned())
            ),
            (
                IssueListOptions::builder()
                    .labels(vec!["foo", "bar"])
                    .build(),
                Some("labels=foo%2Cbar".to_owned())
            ),
        ];
        test_serialize(tests)
    }

    #[test]
    fn sort_default() {
        let default: Sort = Default::default();
        assert_eq!(default, Sort::Created)
    }

    #[test]
    fn sort_display() {
        for (k, v) in vec![
            (Sort::Created, "created"),
            (Sort::Updated, "updated"),
            (Sort::Comments, "comments"),
        ]
        {
            assert_eq!(k.to_string(), v)
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};
use conhash::Node;
use num::FromPrimitive;

use errors::BMemcachedError;

enum Type {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Command {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

enum_from_primitive! {
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Success = 0x00,
        KeyNotFound = 0x01,
        KeyExists = 0x02,
        AuthError = 0x08,
        UnknownCommand = 0x81
    }
}

#[derive(Debug)]
pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

#[derive(Debug)]
pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

#[derive(Debug)]
pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Protocol, BMemcachedError> {
        Ok(Protocol{connection: try!(TcpStream::connect(addr))})
    }

    pub fn connection_info(&self) -> String {
        format!("{:?}", self.connection.peer_addr().unwrap())
    }

    fn build_request(command: Command, key_length: usize, value_length: usize, data_type: u8,
        extras_length: usize, cas: u64) -> Request {
        Request {
            magic: Type::Request as u8, opcode: command as u8,
            key_length: key_length as u16,
            extras_length: extras_length as u8,
            data_type: data_type, reserved: 0,
            body_length: (key_length + value_length + extras_length) as u32,
            opaque: 0, cas: cas
        }
    }

    fn write_request(&self, request: Request, final_payload: &[u8]) -> Result<(), BMemcachedError> {
        let mut buf = &self.connection;
        try!(buf.write_u8(request.magic));
        try!(buf.write_u8(request.opcode));
        try!(buf.write_u16::<BigEndian>(request.key_length));
        try!(buf.write_u8(request.extras_length));
        try!(buf.write_u8(request.data_type));
        try!(buf.write_u16::<BigEndian>(request.reserved));
        try!(buf.write_u32::<BigEndian>(request.body_length));
        try!(buf.write_u32::<BigEndian>(request.opaque));
        try!(buf.write_u64::<BigEndian>(request.cas));
        try!(buf.write(final_payload));
        Ok(())
    }

    fn read_response(&mut self) -> Result<Response, BMemcachedError> {
        let mut buf = &self.connection;
        let magic: u8 = try!(buf.read_u8());
        if magic != Type::Response as u8 {
            // TODO Consume the stream, disconnect or something?
            debug!("Server sent an unknown magic code {:?}", magic);
            return Err(BMemcachedError::UnkownError("Server sent an unknown magic code"))
        }
        Ok(Response {
            magic: magic,
            opcode: try!(buf.read_u8()),
            key_length: try!(buf.read_u16::<BigEndian>()),
            extras_length: try!(buf.read_u8()),
            data_type: try!(buf.read_u8()),
            status: try!(buf.read_u16::<BigEndian>()),
            body_length: try!(buf.read_u32::<BigEndian>()),
            opaque: try!(buf.read_u32::<BigEndian>()),
            cas: try!(buf.read_u64::<BigEndian>())
        })
    }

    fn consume_body(&mut self, size: u32) {
        debug!("Consuming body");
        let mut buf: Vec<u8> = vec![0; size as usize];
        self.connection.read(&mut *buf);
        let str_buf = String::from_utf8(buf).unwrap();
        debug!("Consumed body {:?}", str_buf);
    }

    fn set_add_replace<K, V>(&mut self, command: Command, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        let key = key.as_ref();
        let value = value.as_ref();
        let extras_length = size_of::<SetAddReplace>();
        let request = Protocol::build_request(command, key.len(), value.len(), 0x00, extras_length, 0x00);
        let mut final_payload = vec![];
        // Flags
        try!(final_payload.write_u32::<BigEndian>(0));
        try!(final_payload.write_u32::<BigEndian>(time));
        // After flags key and value
        try!(final_payload.write(key));
        try!(final_payload.write(value));
        let size = try!(self.write_request(request, final_payload.as_slice()));
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(rest) => {
                self.consume_body(response.body_length);
                Err(BMemcachedError::Status(rest))
            },
            None => Err(BMemcachedError::UnkownError("Server returned an unknown status code"))
        }
    }

    pub fn set<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Set, key, value, time)
    }

    pub fn add<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Add, key, value, time)
    }

    pub fn replace<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Replace, key, value, time)
    }

    pub fn get<K>(&mut self, key: K) -> Result<String, BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Get, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => {},
            Some(status) => {
                self.consume_body(response.body_length);
                return Err(BMemcachedError::Status(status))
            },
            None => return Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        };
        // Discard extras for now
        try!(self.connection.read_u32::<BigEndian>());
        let mut outbuf = vec![0; (response.body_length - response.extras_length as u32) as usize];
        try!(self.connection.read_exact(&mut outbuf));
        Ok(try!(String::from_utf8(outbuf)))
    }

    pub fn delete<K>(&mut self, key: K) -> Result<(), BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Delete, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());

        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(Status::KeyNotFound) => {
                self.consume_body(response.body_length);
                Ok(())
            },
            Some(status) => {
                self.consume_body(response.body_length);
                Err(BMemcachedError::Status(status))
            },
            None => Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        }
    }
}
#[cfg(test)]
mod tests {
    extern crate env_logger;
    use errors::BMemcachedError;
    use super::*;

    #[test]
    fn set_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        p.delete(key).unwrap();
    }

    #[test]
    fn add_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello Add";
        let value = "World";
        p.add(key, value, 10).unwrap();
        let result = p.add(key, value, 10);
        match result {
            Ok(()) => panic!("Add key should return error"),
            Err(BMemcachedError::Status(Status::KeyExists)) => {},
            Err(_) => panic!("Some strange error that should not happen")
        };
        p.delete(key);
    }

    #[test]
    fn get_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        assert_eq!(p.get(key).unwrap(),  value);
        match p.get("not found".to_string()) {
            Ok(_) => panic!("This key should not exist"),
            Err(BMemcachedError::Status(Status::KeyNotFound)) => {},
            Err(_) => panic!("This should return KeyNotFound")
        };
        p.delete(key).unwrap();
    }

    #[test]
    fn delete_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        p.delete(key).unwrap();
        p.delete(key).unwrap();
    }
}
<commit_msg>Increase tests expiring times to avoid breaking<commit_after>use std::io::{Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};
use conhash::Node;
use num::FromPrimitive;

use errors::BMemcachedError;

enum Type {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Command {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

enum_from_primitive! {
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Success = 0x00,
        KeyNotFound = 0x01,
        KeyExists = 0x02,
        AuthError = 0x08,
        UnknownCommand = 0x81
    }
}

#[derive(Debug)]
pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

#[derive(Debug)]
pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

#[derive(Debug)]
pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Protocol, BMemcachedError> {
        Ok(Protocol{connection: try!(TcpStream::connect(addr))})
    }

    pub fn connection_info(&self) -> String {
        format!("{:?}", self.connection.peer_addr().unwrap())
    }

    fn build_request(command: Command, key_length: usize, value_length: usize, data_type: u8,
        extras_length: usize, cas: u64) -> Request {
        Request {
            magic: Type::Request as u8, opcode: command as u8,
            key_length: key_length as u16,
            extras_length: extras_length as u8,
            data_type: data_type, reserved: 0,
            body_length: (key_length + value_length + extras_length) as u32,
            opaque: 0, cas: cas
        }
    }

    fn write_request(&self, request: Request, final_payload: &[u8]) -> Result<(), BMemcachedError> {
        let mut buf = &self.connection;
        try!(buf.write_u8(request.magic));
        try!(buf.write_u8(request.opcode));
        try!(buf.write_u16::<BigEndian>(request.key_length));
        try!(buf.write_u8(request.extras_length));
        try!(buf.write_u8(request.data_type));
        try!(buf.write_u16::<BigEndian>(request.reserved));
        try!(buf.write_u32::<BigEndian>(request.body_length));
        try!(buf.write_u32::<BigEndian>(request.opaque));
        try!(buf.write_u64::<BigEndian>(request.cas));
        try!(buf.write(final_payload));
        Ok(())
    }

    fn read_response(&mut self) -> Result<Response, BMemcachedError> {
        let mut buf = &self.connection;
        let magic: u8 = try!(buf.read_u8());
        if magic != Type::Response as u8 {
            // TODO Consume the stream, disconnect or something?
            debug!("Server sent an unknown magic code {:?}", magic);
            return Err(BMemcachedError::UnkownError("Server sent an unknown magic code"))
        }
        Ok(Response {
            magic: magic,
            opcode: try!(buf.read_u8()),
            key_length: try!(buf.read_u16::<BigEndian>()),
            extras_length: try!(buf.read_u8()),
            data_type: try!(buf.read_u8()),
            status: try!(buf.read_u16::<BigEndian>()),
            body_length: try!(buf.read_u32::<BigEndian>()),
            opaque: try!(buf.read_u32::<BigEndian>()),
            cas: try!(buf.read_u64::<BigEndian>())
        })
    }

    fn consume_body(&mut self, size: u32) {
        debug!("Consuming body");
        let mut buf: Vec<u8> = vec![0; size as usize];
        self.connection.read(&mut *buf);
        let str_buf = String::from_utf8(buf).unwrap();
        debug!("Consumed body {:?}", str_buf);
    }

    fn set_add_replace<K, V>(&mut self, command: Command, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        let key = key.as_ref();
        let value = value.as_ref();
        let extras_length = size_of::<SetAddReplace>();
        let request = Protocol::build_request(command, key.len(), value.len(), 0x00, extras_length, 0x00);
        let mut final_payload = vec![];
        // Flags
        try!(final_payload.write_u32::<BigEndian>(0));
        try!(final_payload.write_u32::<BigEndian>(time));
        // After flags key and value
        try!(final_payload.write(key));
        try!(final_payload.write(value));
        let size = try!(self.write_request(request, final_payload.as_slice()));
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(rest) => {
                self.consume_body(response.body_length);
                Err(BMemcachedError::Status(rest))
            },
            None => Err(BMemcachedError::UnkownError("Server returned an unknown status code"))
        }
    }

    pub fn set<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Set, key, value, time)
    }

    pub fn add<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Add, key, value, time)
    }

    pub fn replace<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Replace, key, value, time)
    }

    pub fn get<K>(&mut self, key: K) -> Result<String, BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Get, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => {},
            Some(status) => {
                self.consume_body(response.body_length);
                return Err(BMemcachedError::Status(status))
            },
            None => return Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        };
        // Discard extras for now
        try!(self.connection.read_u32::<BigEndian>());
        let mut outbuf = vec![0; (response.body_length - response.extras_length as u32) as usize];
        try!(self.connection.read_exact(&mut outbuf));
        Ok(try!(String::from_utf8(outbuf)))
    }

    pub fn delete<K>(&mut self, key: K) -> Result<(), BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Delete, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());

        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(Status::KeyNotFound) => {
                self.consume_body(response.body_length);
                Ok(())
            },
            Some(status) => {
                self.consume_body(response.body_length);
                Err(BMemcachedError::Status(status))
            },
            None => Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        }
    }
}
#[cfg(test)]
mod tests {
    extern crate env_logger;
    use errors::BMemcachedError;
    use super::*;

    #[test]
    fn set_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 1000).unwrap();
        p.delete(key).unwrap();
    }

    #[test]
    fn add_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello Add";
        let value = "World";
        p.add(key, value, 10).unwrap();
        let result = p.add(key, value, 10);
        match result {
            Ok(()) => panic!("Add key should return error"),
            Err(BMemcachedError::Status(Status::KeyExists)) => {},
            Err(_) => panic!("Some strange error that should not happen")
        };
        p.delete(key);
    }

    #[test]
    fn get_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 1000).unwrap();
        assert_eq!(p.get(key).unwrap(),  value);
        match p.get("not found".to_string()) {
            Ok(_) => panic!("This key should not exist"),
            Err(BMemcachedError::Status(Status::KeyNotFound)) => {},
            Err(_) => panic!("This should return KeyNotFound")
        };
        p.delete(key).unwrap();
    }

    #[test]
    fn delete_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 1000).unwrap();
        p.delete(key).unwrap();
        p.delete(key).unwrap();
    }
}
<|endoftext|>


<commit_before>pub fn guess_single_xor_char_decode(bytes: &Vec<u8>) -> (u16, Vec<u8>, u8) {
	use english_scoring::*;
	use key::*;

	let mut top_score = 0;
	let mut top_decode = vec![];
	let mut top_x = 2;
	for x in 0..255 {
		let mut rk = RepeatingKey::new_bytes(vec![x]);
		let decoded = rk.encrypt_bytes(&bytes);

		let score = score_on_letter_frequency(&decoded);
		if score > top_score {
			top_score = score;
			top_decode = decoded;
			top_x = x;
		}
	}

	(top_score, top_decode, top_x)
}

//-----------------------------------------------------------------------------

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

	#[test]
	fn guess_single_xor_char_decode_i_set_1_problem_3() {
		// http://cryptopals.com/sets/1/challenges/3/
		use byte_conversion::*;
		let encoded = hex_to_bytes("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736");

		let (top_score, guessed_decode, guessed_character) = guess_single_xor_char_decode(&encoded);

		let expected = readable_text_to_bytes(&"Cooking MC's like a pound of bacon");

		assert_eq!(expected, guessed_decode);
		assert_eq!(88, guessed_character);
		assert!(top_score > 0);
	}

	#[test]
	fn guess_single_xor_char_decode_i_example() {
		// http://cryptopals.com/sets/1/challenges/3/
		use byte_conversion::*;
		use key::*;

		let mut rk = RepeatingKey::new("Q");
		let example = readable_text_to_bytes(&"Some super hard to decrypt (but still English!) text.");

		let encrypted = rk.encrypt_bytes(&example);
		let (top_score, guessed_decode, guessed_character) = guess_single_xor_char_decode(&encrypted);

		assert_eq!(example, guessed_decode);
		assert_eq!('Q' as u8, guessed_character);
		assert!(top_score > 0);
	}
}
<commit_msg>single_xor_guess uses score_combined<commit_after>pub fn guess_single_xor_char_decode(bytes: &Vec<u8>) -> (u16, Vec<u8>, u8) {
	use english_scoring::*;
	use key::*;

	let mut top_score = 0;
	let mut top_decode = vec![];
	let mut top_x = 2;
	for x in 0..255 {
		let mut rk = RepeatingKey::new_bytes(&vec![x]);
		let decoded = rk.encrypt_bytes(&bytes);

		let score = score_combined(&decoded);
		if score > top_score {
			top_score = score;
			top_decode = decoded;
			top_x = x;
		}
	}

	(top_score, top_decode, top_x)
}

//-----------------------------------------------------------------------------

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

	#[test]
	fn guess_single_xor_char_decode_i_set_1_problem_3() {
		// http://cryptopals.com/sets/1/challenges/3/
		use byte_conversion::*;
		let encoded = hex_to_bytes("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736");

		let (top_score, guessed_decode, guessed_character) = guess_single_xor_char_decode(&encoded);

		let expected = readable_text_to_bytes(&"Cooking MC's like a pound of bacon");

		assert_eq!(expected, guessed_decode);
		assert_eq!(88, guessed_character);
		assert!(top_score > 0);
	}

	#[test]
	fn guess_single_xor_char_decode_i_example() {
		// http://cryptopals.com/sets/1/challenges/3/
		use byte_conversion::*;
		use key::*;

		let mut rk = RepeatingKey::new("Q");
		let example = readable_text_to_bytes(&"Some super hard to decrypt (but still English!) text.");

		let encrypted = rk.encrypt_bytes(&example);
		let (top_score, guessed_decode, guessed_character) = guess_single_xor_char_decode(&encrypted);

		assert_eq!(example, guessed_decode);
		assert_eq!('Q' as u8, guessed_character);
		assert!(top_score > 0);
	}
}
<|endoftext|>


<commit_before>use clap::{Arg, ArgMatches, App, SubCommand, AppSettings};

pub fn create_arg_parser<'a, 'b>() -> App<'a, 'b> {
    App::new("A rust based clone of the all time classic xxd tool")
        .version("0.1.0")
        .author("Nicola Coretti <nicola.coretti@gmail.com>")
        .about("make a hexdump or the reverse")
        .global_settings(&[AppSettings::ColoredHelp])
        .arg(Arg::with_name("infile")
                 .required(false)
                 .global(true)
                 .index(1)
                 .help("Input file which shall be used (default: stdin)"))
        .arg(Arg::with_name("outfile")
                 .required(false)
                 .global(true)
                 .index(2)
                 .help("File to which the output will be written (default: stdout)"))
        .arg(Arg::with_name("seek")
                 .short("s")
                 .long("seek")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Offset in the file where to start reading"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Amount of bytes which shall be read"))
        .subcommand(SubCommand::with_name("dump")
                        .about("Dumps an input file in the appropriate output format")
                        .arg(Arg::with_name("plain_hexdump")
                                 .short("p")
                                 .long("plain-hexdump")
                                 .required(false)
                                 .help("output in postscript plain hexdump style."))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("Hex")
                                 .possible_value("hex")
                                 .possible_value("bin")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .help("Specifies the output format for the value (default: hex)"))
                        .arg(Arg::with_name("group-size")
                                 .short("g")
                                 .long("group-size")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Separate  the output of every <bytes> bytes (two hex characters or eight bit-digits each) by a whitespace."))
                        .arg(Arg::with_name("columns")
                                 .short("c")
                                 .long("columns")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the amount of output columns")))
        .subcommand(SubCommand::with_name("convert")
                        .about("Converts input data to a file (e.g. hexstream -> binary file")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("binary")
                                 .possible_value("c-array")
                                 .possible_value("oct")
                                 .help("Specifies the output format (default: hex)")))
        .subcommand(SubCommand::with_name("generate")
                        .about("Generates a source file containing the specified file as array")
                        .arg(Arg::with_name("template")
                                 .short("t")
                                 .long("template")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("c")
                                 .possible_value("cpp")
                                 .possible_value("rs")
                                 .help("Specifies a template file which shall be used for \
                                        generation"))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .possible_value("bin")
                                 .help("Specifies the output format (default: hex)"))
                        .arg(Arg::with_name("Separator")
                                 .long("separator")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the the separator between single values \
                                        (default: ',')")))
}
<commit_msg>Remove unnecessary cmd options<commit_after>use clap::{Arg, ArgMatches, App, SubCommand, AppSettings};

pub fn create_arg_parser<'a, 'b>() -> App<'a, 'b> {
    App::new("A rust based clone of the all time classic xxd tool")
        .version("0.1.0")
        .author("Nicola Coretti <nicola.coretti@gmail.com>")
        .about("make a hexdump or the reverse")
        .global_settings(&[AppSettings::ColoredHelp])
        .arg(Arg::with_name("infile")
                 .required(false)
                 .global(true)
                 .index(1)
                 .help("Input file which shall be used (default: stdin)"))
        .arg(Arg::with_name("outfile")
                 .required(false)
                 .global(true)
                 .index(2)
                 .help("File to which the output will be written (default: stdout)"))
        .arg(Arg::with_name("seek")
                 .short("s")
                 .long("seek")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Offset in the file where to start reading"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Amount of bytes which shall be read"))
        .subcommand(SubCommand::with_name("dump")
                        .about("Dumps an input file in the appropriate output format")
                        .arg(Arg::with_name("plain_hexdump")
                                 .short("p")
                                 .long("plain-hexdump")
                                 .required(false)
                                 .help("output in postscript plain hexdump style."))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("Hex")
                                 .possible_value("hex")
                                 .possible_value("bin")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .help("Specifies the output format for the value (default: hex)"))
                        .arg(Arg::with_name("group-size")
                                 .short("g")
                                 .long("group-size")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Separate  the output of every <bytes> bytes (two hex characters or eight bit-digits each) by a whitespace."))
                        .arg(Arg::with_name("columns")
                                 .short("c")
                                 .long("columns")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the amount of output columns")))
        .subcommand(SubCommand::with_name("convert")
                        .about("Converts input data to a file (e.g. hexstream -> binary file")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("binary")
                                 .possible_value("c-array")
                                 .possible_value("oct")
                                 .help("Specifies the output format (default: hex)")))
        .subcommand(SubCommand::with_name("generate")
                        .about("Generates a source file containing the specified file as array")
                        .arg(Arg::with_name("template")
                                 .short("t")
                                 .long("template")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("c")
                                 .possible_value("cpp")
                                 .possible_value("rs")
                                 .help("Specifies a template file which shall be used for \
                                        generation"))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .possible_value("bin")
                                 .help("Specifies the output format (default: hex)")))
}
<|endoftext|>


<commit_before>use std::mem;
use std::ffi::CString;

use cbox::{CSemiBox, DisposeRef};
use ffi::prelude::{LLVMBuilderRef, LLVMValueRef};
use ffi::{core, LLVMBuilder, LLVMRealPredicate, LLVMIntPredicate};
use libc::{c_char, c_uint};

use context::Context;
use block::BasicBlock;
use ty::Type;
use value::{Function, Value, Predicate};
use phi::PhiNode;

static NULL_NAME:[c_char; 1] = [0];

/// This provides a uniform API for creating instructions and inserting them into a basic block.
pub struct Builder;
native_ref!(&Builder = LLVMBuilderRef);

macro_rules! bin_op (
  ($name:ident, $func:ident) => (
    pub fn $name(&self, left: &Value, right: &Value) -> &Value
    {
      unsafe { core::$func(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()) }.into()
    }
  );
  ($name:ident, $ifunc:ident, $ffunc:ident) => (
    pub fn $name(&self, left: &Value, right: &Value) -> &Value {
      let ty = left.get_type();
      unsafe {
        (if ty.is_integer() {
           core::$ifunc
         } else {
           core::$ffunc
         })(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()).into()
      }
    }
  );
);

macro_rules! unary_op (
  ($name:ident, $func:ident) => (
    pub fn $name(&self, value: &Value) -> &Value {
      unsafe { core::$func(self.into(), value.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
    }
  );
);

impl Builder
{
  /// Create a new builder in the context given.
  pub fn new(context: &Context) -> CSemiBox<Builder>
  {
    CSemiBox::new(unsafe { core::LLVMCreateBuilderInContext(context.into()) }.into())
  }

  pub fn get_insert_block(&self) -> &BasicBlock {
    unsafe { core::LLVMGetInsertBlock(self.into()) }.into()
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value) {
    unsafe { core::LLVMPositionBuilder(self.into(), block.into(), instr.into()) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.into(), block.into()) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> &Value
  {
    unsafe { core::LLVMBuildRetVoid(self.into()) }.into()
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> &Value
  {
    unsafe { core::LLVMBuildRet(self.into(), value.into()) }.into()
  }

  /// Build an instruction that allocates an array with the element type `elem` and the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Type, size: &Value) -> &Value
  {
    unsafe {
    	core::LLVMBuildArrayAlloca(self.into(),
    														 elem.into(),
    														 size.into(),
    														 NULL_NAME.as_ptr() as *const c_char)
    }.into()
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Type) -> &Value
  {
    unsafe {
    	core::LLVMBuildAlloca(self.into(),
    												ty.into(),
    												NULL_NAME.as_ptr() as *const c_char)
    }.into()
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> &Value
  {
    unsafe { core::LLVMBuildFree(self.into(), val.into()) }.into()
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> &Value
  {
    unsafe { core::LLVMBuildStore(self.into(), val.into(), ptr.into()) }.into()
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> &Value
  {
    unsafe { core::LLVMBuildBr(self.into(), dest.into()).into() }
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> &Value
  {
    unsafe {
    	core::LLVMBuildCondBr(self.into(),
    		                    cond.into(),
    		                    if_block.into(),
    		                    mem::transmute(else_block)).into()
    }
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_call(&self, func: &Function, args: &[&Value]) -> &Value
  {
    unsafe {
        let call = core::LLVMBuildCall(self.into(),
        	                             func.into(), args.as_ptr() as *mut LLVMValueRef,
        	                             args.len() as c_uint,
        	                             NULL_NAME.as_ptr());
        core::LLVMSetTailCall(call, 0);
        call.into()
    }
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_tail_call(&self, func: &Function, args: &[&Value]) -> &Value
  {
    unsafe {
        let call = core::LLVMBuildCall(self.into(),
        	                             func.into(), args.as_ptr() as *mut LLVMValueRef,
        	                             args.len() as c_uint,
        	                             NULL_NAME.as_ptr());
        core::LLVMSetTailCall(call, 1);
        call.into()
    }
  }
  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val` otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> &Value
  {
    unsafe {
    	core::LLVMBuildSelect(self.into(),
    		                    cond.into(),
    		                    true_val.into(),
    		                    false_val.into(),
    		                    NULL_NAME.as_ptr()).into() }
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Type) -> &Value
  {
    unsafe { core::LLVMBuildBitCast(
    		self.into(),
    		value.into(),
    		dest.into(),
    		NULL_NAME.as_ptr()).into()
    }
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> &Value
  {
    unsafe {
    	core::LLVMBuildInsertValue(self.into(),
    		                         agg.into(),
    		                         elem.into(),
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr()).into()
    }
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> &Value
  {
    unsafe {
    	core::LLVMBuildInBoundsGEP(self.into(),
    	                           pointer.into(),
    	                           indices.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr()).into()
    }
  }

     /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Type, name: &str) -> &PhiNode
  {
	  unsafe {
	  	core::LLVMBuildPhi(self.into(), ty.into(), CString::new(name).unwrap().as_ptr())
  	}.into()
  }

  /// Build an instruction that runs whichever block matches the value, or `default` if none of them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> &Value
  {
    unsafe {
      let switch = core::LLVMBuildSwitch(self.into(),
      	                                 value.into(),
      	                                 default.into(),
      	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, case.0.into(), case.1.into());
      }
      switch.into()
    }
  }

  unary_op!{create_load, LLVMBuildLoad}
  unary_op!{create_neg, LLVMBuildNeg}
  unary_op!{create_not, LLVMBuildNot}

  bin_op!{create_add, LLVMBuildAdd, LLVMBuildFAdd}
  bin_op!{create_sub, LLVMBuildSub, LLVMBuildFSub}
  bin_op!{create_mul, LLVMBuildMul, LLVMBuildFMul}
  bin_op!{create_div, LLVMBuildSDiv, LLVMBuildFDiv}
  bin_op!{create_rem, LLVMBuildSRem, LLVMBuildFRem}
  bin_op!{create_shl, LLVMBuildShl}
  bin_op!{create_ashr, LLVMBuildAShr}
  bin_op!{create_and, LLVMBuildAnd}
  bin_op!{create_or, LLVMBuildOr}
  bin_op!{create_xor, LLVMBuildXor}

  /// Build an instruction to compare two values with the predicate given.
  pub fn create_cmp(&self, a: &Value, b: &Value, pred: Predicate) -> &Value
  {
    let (at, bt) = (a.get_type(), b.get_type());
    assert_eq!(at, bt);

    if at.is_integer() {
      let pred = match pred {
          Predicate::Equal => LLVMIntPredicate::LLVMIntEQ,
          Predicate::NotEqual => LLVMIntPredicate::LLVMIntNE,
          Predicate::GreaterThan => LLVMIntPredicate::LLVMIntSGT,
          Predicate::GreaterThanOrEqual => LLVMIntPredicate::LLVMIntSGE,
          Predicate::LessThan => LLVMIntPredicate::LLVMIntSLT,
          Predicate::LessThanOrEqual => LLVMIntPredicate::LLVMIntSLE
      };
      unsafe {
      	core::LLVMBuildICmp(self.into(),
      		                  pred,
      		                  a.into(), b.into(),
      		                  NULL_NAME.as_ptr())
      }.into()

    } else if at.is_float() {
      let pred = match pred {
          Predicate::Equal => LLVMRealPredicate::LLVMRealOEQ,
          Predicate::NotEqual => LLVMRealPredicate::LLVMRealONE,
          Predicate::GreaterThan => LLVMRealPredicate::LLVMRealOGT,
          Predicate::GreaterThanOrEqual => LLVMRealPredicate::LLVMRealOGE,
          Predicate::LessThan => LLVMRealPredicate::LLVMRealOLT,
          Predicate::LessThanOrEqual => LLVMRealPredicate::LLVMRealOLE
      };
      unsafe {
      	core::LLVMBuildFCmp(self.into(),
      		                 pred, a.into(), b.into(),
      		                 NULL_NAME.as_ptr())
      }.into()

    } else {
        panic!("expected numbers, got {:?}", at)
    }
  }
}

impl DisposeRef for Builder {
  type RefTo = LLVMBuilder;
  #[inline(always)]
  unsafe fn dispose(ptr: LLVMBuilderRef) {
      core::LLVMDisposeBuilder(ptr)
  }
}
<commit_msg>Add create_extract_value to Builder.<commit_after>use std::mem;
use std::ffi::CString;

use cbox::{CSemiBox, DisposeRef};
use ffi::prelude::{LLVMBuilderRef, LLVMValueRef};
use ffi::{core, LLVMBuilder, LLVMRealPredicate, LLVMIntPredicate};
use libc::{c_char, c_uint};

use context::Context;
use block::BasicBlock;
use ty::Type;
use value::{Function, Value, Predicate};
use phi::PhiNode;

static NULL_NAME:[c_char; 1] = [0];

/// This provides a uniform API for creating instructions and inserting them into a basic block.
pub struct Builder;
native_ref!(&Builder = LLVMBuilderRef);

macro_rules! bin_op (
  ($name:ident, $func:ident) => (
    pub fn $name(&self, left: &Value, right: &Value) -> &Value
    {
      unsafe { core::$func(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()) }.into()
    }
  );
  ($name:ident, $ifunc:ident, $ffunc:ident) => (
    pub fn $name(&self, left: &Value, right: &Value) -> &Value {
      let ty = left.get_type();
      unsafe {
        (if ty.is_integer() {
           core::$ifunc
         } else {
           core::$ffunc
         })(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()).into()
      }
    }
  );
);

macro_rules! unary_op (
  ($name:ident, $func:ident) => (
    pub fn $name(&self, value: &Value) -> &Value {
      unsafe { core::$func(self.into(), value.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
    }
  );
);

impl Builder
{
  /// Create a new builder in the context given.
  pub fn new(context: &Context) -> CSemiBox<Builder>
  {
    CSemiBox::new(unsafe { core::LLVMCreateBuilderInContext(context.into()) }.into())
  }

  pub fn get_insert_block(&self) -> &BasicBlock {
    unsafe { core::LLVMGetInsertBlock(self.into()) }.into()
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value) {
    unsafe { core::LLVMPositionBuilder(self.into(), block.into(), instr.into()) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.into(), block.into()) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> &Value
  {
    unsafe { core::LLVMBuildRetVoid(self.into()) }.into()
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> &Value
  {
    unsafe { core::LLVMBuildRet(self.into(), value.into()) }.into()
  }

  /// Build an instruction that allocates an array with the element type `elem` and the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Type, size: &Value) -> &Value
  {
    unsafe {
    	core::LLVMBuildArrayAlloca(self.into(),
    														 elem.into(),
    														 size.into(),
    														 NULL_NAME.as_ptr() as *const c_char)
    }.into()
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Type) -> &Value
  {
    unsafe {
    	core::LLVMBuildAlloca(self.into(),
    												ty.into(),
    												NULL_NAME.as_ptr() as *const c_char)
    }.into()
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> &Value
  {
    unsafe { core::LLVMBuildFree(self.into(), val.into()) }.into()
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> &Value
  {
    unsafe { core::LLVMBuildStore(self.into(), val.into(), ptr.into()) }.into()
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> &Value
  {
    unsafe { core::LLVMBuildBr(self.into(), dest.into()).into() }
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> &Value
  {
    unsafe {
    	core::LLVMBuildCondBr(self.into(),
    		                    cond.into(),
    		                    if_block.into(),
    		                    mem::transmute(else_block)).into()
    }
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_call(&self, func: &Function, args: &[&Value]) -> &Value
  {
    unsafe {
        let call = core::LLVMBuildCall(self.into(),
        	                             func.into(), args.as_ptr() as *mut LLVMValueRef,
        	                             args.len() as c_uint,
        	                             NULL_NAME.as_ptr());
        core::LLVMSetTailCall(call, 0);
        call.into()
    }
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_tail_call(&self, func: &Function, args: &[&Value]) -> &Value
  {
    unsafe {
        let call = core::LLVMBuildCall(self.into(),
        	                             func.into(), args.as_ptr() as *mut LLVMValueRef,
        	                             args.len() as c_uint,
        	                             NULL_NAME.as_ptr());
        core::LLVMSetTailCall(call, 1);
        call.into()
    }
  }
  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val` otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> &Value
  {
    unsafe {
    	core::LLVMBuildSelect(self.into(),
    		                    cond.into(),
    		                    true_val.into(),
    		                    false_val.into(),
    		                    NULL_NAME.as_ptr()).into() }
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Type) -> &Value
  {
    unsafe { core::LLVMBuildBitCast(
    		self.into(),
    		value.into(),
    		dest.into(),
    		NULL_NAME.as_ptr()).into()
    }
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> &Value
  {
    unsafe {
    	core::LLVMBuildInsertValue(self.into(),
    		                         agg.into(),
    		                         elem.into(),
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr()).into()
    }
  }

  /// Build an instruction that extracts a value from an aggregate type.
	pub fn create_extract_value(&self, agg: &Value, index: usize) -> &Value {
    unsafe {
    	core::LLVMBuildExtractValue(self.into(),
    		                          agg.into(),
    		                          index as c_uint,
    		                          NULL_NAME.as_ptr()).into()
   	}
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> &Value
  {
    unsafe {
    	core::LLVMBuildInBoundsGEP(self.into(),
    	                           pointer.into(),
    	                           indices.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr()).into()
    }
  }

     /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Type, name: &str) -> &PhiNode
  {
	  unsafe {
	  	core::LLVMBuildPhi(self.into(), ty.into(), CString::new(name).unwrap().as_ptr())
  	}.into()
  }

  /// Build an instruction that runs whichever block matches the value, or `default` if none of them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> &Value
  {
    unsafe {
      let switch = core::LLVMBuildSwitch(self.into(),
      	                                 value.into(),
      	                                 default.into(),
      	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, case.0.into(), case.1.into());
      }
      switch.into()
    }
  }

  unary_op!{create_load, LLVMBuildLoad}
  unary_op!{create_neg, LLVMBuildNeg}
  unary_op!{create_not, LLVMBuildNot}

  bin_op!{create_add, LLVMBuildAdd, LLVMBuildFAdd}
  bin_op!{create_sub, LLVMBuildSub, LLVMBuildFSub}
  bin_op!{create_mul, LLVMBuildMul, LLVMBuildFMul}
  bin_op!{create_div, LLVMBuildSDiv, LLVMBuildFDiv}
  bin_op!{create_rem, LLVMBuildSRem, LLVMBuildFRem}
  bin_op!{create_shl, LLVMBuildShl}
  bin_op!{create_ashr, LLVMBuildAShr}
  bin_op!{create_and, LLVMBuildAnd}
  bin_op!{create_or, LLVMBuildOr}
  bin_op!{create_xor, LLVMBuildXor}

  /// Build an instruction to compare two values with the predicate given.
  pub fn create_cmp(&self, a: &Value, b: &Value, pred: Predicate) -> &Value
  {
    let (at, bt) = (a.get_type(), b.get_type());
    assert_eq!(at, bt);

    if at.is_integer() {
      let pred = match pred {
          Predicate::Equal => LLVMIntPredicate::LLVMIntEQ,
          Predicate::NotEqual => LLVMIntPredicate::LLVMIntNE,
          Predicate::GreaterThan => LLVMIntPredicate::LLVMIntSGT,
          Predicate::GreaterThanOrEqual => LLVMIntPredicate::LLVMIntSGE,
          Predicate::LessThan => LLVMIntPredicate::LLVMIntSLT,
          Predicate::LessThanOrEqual => LLVMIntPredicate::LLVMIntSLE
      };
      unsafe {
      	core::LLVMBuildICmp(self.into(),
      		                  pred,
      		                  a.into(), b.into(),
      		                  NULL_NAME.as_ptr())
      }.into()

    } else if at.is_float() {
      let pred = match pred {
          Predicate::Equal => LLVMRealPredicate::LLVMRealOEQ,
          Predicate::NotEqual => LLVMRealPredicate::LLVMRealONE,
          Predicate::GreaterThan => LLVMRealPredicate::LLVMRealOGT,
          Predicate::GreaterThanOrEqual => LLVMRealPredicate::LLVMRealOGE,
          Predicate::LessThan => LLVMRealPredicate::LLVMRealOLT,
          Predicate::LessThanOrEqual => LLVMRealPredicate::LLVMRealOLE
      };
      unsafe {
      	core::LLVMBuildFCmp(self.into(),
      		                 pred, a.into(), b.into(),
      		                 NULL_NAME.as_ptr())
      }.into()

    } else {
        panic!("expected numbers, got {:?}", at)
    }
  }
}

impl DisposeRef for Builder {
  type RefTo = LLVMBuilder;
  #[inline(always)]
  unsafe fn dispose(ptr: LLVMBuilderRef) {
      core::LLVMDisposeBuilder(ptr)
  }
}
<|endoftext|>