<commit_before>//! Details of parsing input for the `ruma_event` procedural macro.

use syn::{
    braced,
    parse::{self, Parse, ParseStream},
    token::Colon,
    Attribute, Expr, ExprLit, Field, FieldValue, Ident, Lit, LitStr, Member, Token, TypePath,
};

/// The entire `ruma_event!` macro structure directly as it appears in the source code..
pub struct RumaEventInput {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the event.
    pub name: Ident,

    /// The kind of event, determiend by the `kind` field.
    pub kind: EventKind,

    /// The value for the `type` field in the JSON representation of this event. There needs to be a
    /// corresponding variant in `ruma_events::EventType` for this event (converted to a valid
    /// Rust-style type name by stripping `m.`, replacing the remaining dots by underscores and then
    /// converting from snake_case to CamelCase).
    pub event_type: LitStr,

    /// Additional named struct fields in the top level event struct.
    pub fields: Option<Vec<Field>>,

    /// A struct definition or type alias to be used as the event's `content` field.
    pub content: Content,
}

impl Parse for RumaEventInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let attrs = input.call(Attribute::parse_outer)?;
        let name: Ident = input.parse()?;
        let body;
        braced!(body in input);

        let mut kind = None;
        let mut event_type = None;
        let mut fields = None;
        let mut content = None;

        #[allow(clippy::identity_conversion)]
        for field_value_inline_struct in
            body.parse_terminated::<RumaEventField, Token![,]>(RumaEventField::parse)?
        {
            match field_value_inline_struct {
                RumaEventField::Block(field_block) => {
                    let ident = match field_block.member {
                        Member::Named(ident) => ident,
                        Member::Unnamed(_) => panic!("fields with block values in `ruma_event!` must named `content_type_alias`"),
                    };

                    if ident == "content_type_alias" {
                        content = Some(Content::Typedef(field_block.typedef));
                    }
                }
                RumaEventField::InlineStruct(field_inline_struct) => {
                    let ident = match field_inline_struct.member {
                        Member::Named(ident) => ident,
                        Member::Unnamed(_) => panic!("fields with inline struct values in `ruma_event!` must be named `fields` or `content`."),
                    };

                    if ident == "fields" {
                        fields = Some(field_inline_struct.fields);
                    } else if ident == "content" {
                        content = Some(Content::Struct(field_inline_struct.fields));
                    }
                }
                RumaEventField::Value(field_value) => {
                    let ident = match field_value.member {
                        Member::Named(ident) => ident,
                        Member::Unnamed(_) => panic!("fields with expression values in `ruma_event!` must be named `kind` or `event_type`, ."),
                    };

                    if ident == "kind" {
                        let event_kind = match field_value.expr {
                            Expr::Path(expr_path) => {
                                if expr_path.path.is_ident("Event") {
                                    EventKind::Event
                                } else if expr_path.path.is_ident("RoomEvent") {
                                    EventKind::RoomEvent
                                } else if expr_path.path.is_ident("StateEvent") {
                                    EventKind::StateEvent
                                } else {
                                    panic!("value of field `kind` must be one of `Event`, `RoomEvent`, or `StateEvent`");
                                }
                            }
                            _ => panic!(
                                "value of field `kind` is required to be an ident by `ruma_event!`"
                            ),
                        };

                        kind = Some(event_kind);
                    } else if ident == "event_type" {
                        event_type = Some(match field_value.expr {
                            Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) => s,
                            // TODO: Span info
                            _ => panic!(
                                "value of field `event_type` is required to be a string literal by `ruma_event!`"
                            ),
                        })
                    } else {
                        panic!("unexpected field-value pair with field name `{}`", ident);
                    }
                }
            }
        }

        if kind.is_none() {
            panic!("field `kind` is required by `ruma_event!`");
        } else if event_type.is_none() {
            panic!("field `event_type` is required by `ruma_event!`");
        } else if content.is_none() {
            panic!(
                "one field named `content` or `content_type_alias` is required by `ruma_event!`"
            );
        }

        Ok(Self {
            attrs,
            name,
            kind: kind.unwrap(),
            event_type: event_type.unwrap(),
            fields,
            content: content.unwrap(),
        })
    }
}

/// Which kind of event is being generated.
///
/// Determined by the `kind` field in the macro body.
#[derive(PartialEq)]
pub enum EventKind {
    /// A basic event.
    Event,

    /// A room event.
    RoomEvent,

    /// A state event.
    StateEvent,
}

/// Information for generating the type used for the event's `content` field.
pub enum Content {
    /// A struct, e.g. `ExampleEventContent { ... }`.
    Struct(Vec<Field>),

    /// A type alias, e.g. `type ExampleEventContent = SomeExistingType`
    Typedef(Typedef),
}

/// The style of field within the macro body.
#[allow(clippy::large_enum_variant)]
enum RumaEventField {
    /// The value of a field is a block with a type alias in it.
    ///
    /// Used for `content_type_alias`.
    Block(FieldBlock),

    /// The value of a field is a block with named struct fields in it.
    ///
    /// Used for `content`.
    InlineStruct(FieldInlineStruct),

    /// A standard named struct field.
    ///
    /// Used for `kind` and `event_type`.
    Value(FieldValue),
}

impl Parse for RumaEventField {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let ahead = input.fork();
        let field_ident: Ident = ahead.parse()?;

        match field_ident.to_string().as_ref() {
            "content" | "fields" => {
                let attrs = input.call(Attribute::parse_outer)?;
                let member = input.parse()?;
                let colon_token = input.parse()?;
                let body;
                braced!(body in input);
                let fields = body
                    .parse_terminated::<Field, Token![,]>(Field::parse_named)?
                    .into_iter()
                    .collect();

                Ok(RumaEventField::InlineStruct(FieldInlineStruct {
                    attrs,
                    member,
                    colon_token,
                    fields,
                }))
            }
            "content_type_alias" => Ok(RumaEventField::Block(FieldBlock {
                attrs: input.call(Attribute::parse_outer)?,
                member: input.parse()?,
                colon_token: input.parse()?,
                typedef: input.parse()?,
            })),
            _ => Ok(RumaEventField::Value(input.parse()?)),
        }
    }
}

/// The value of a field is a block with a type alias in it.
///
/// Used for `content_type_alias`.
struct FieldBlock {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the field.
    pub member: Member,

    /// The colon that appears between the field name and type.
    pub colon_token: Colon,

    /// The path to the type that will be used in a type alias for the event's `content` type.
    pub typedef: Typedef,
}

/// The value of a field is a block with named struct fields in it.
///
/// Used for `content`.
struct FieldInlineStruct {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the field.
    pub member: Member,

    /// The colon that appears between the field name and type.
    pub colon_token: Colon,

    /// The fields that define the `content` struct.
    pub fields: Vec<Field>,
}

/// Path to a type to be used in a type alias for an event's `content` type.
pub struct Typedef {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// Path to the type.
    pub path: TypePath,
}

impl Parse for Typedef {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let body;
        braced!(body in input);

        Ok(Self {
            attrs: body.call(Attribute::parse_outer)?,
            path: body.parse()?,
        })
    }
}
<commit_msg>remove allow clippy::identity_conversion<commit_after>//! Details of parsing input for the `ruma_event` procedural macro.

use syn::{
    braced,
    parse::{self, Parse, ParseStream},
    token::Colon,
    Attribute, Expr, ExprLit, Field, FieldValue, Ident, Lit, LitStr, Member, Token, TypePath,
};

/// The entire `ruma_event!` macro structure directly as it appears in the source code..
pub struct RumaEventInput {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the event.
    pub name: Ident,

    /// The kind of event, determiend by the `kind` field.
    pub kind: EventKind,

    /// The value for the `type` field in the JSON representation of this event. There needs to be a
    /// corresponding variant in `ruma_events::EventType` for this event (converted to a valid
    /// Rust-style type name by stripping `m.`, replacing the remaining dots by underscores and then
    /// converting from snake_case to CamelCase).
    pub event_type: LitStr,

    /// Additional named struct fields in the top level event struct.
    pub fields: Option<Vec<Field>>,

    /// A struct definition or type alias to be used as the event's `content` field.
    pub content: Content,
}

impl Parse for RumaEventInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let attrs = input.call(Attribute::parse_outer)?;
        let name: Ident = input.parse()?;
        let body;
        braced!(body in input);

        let mut kind = None;
        let mut event_type = None;
        let mut fields = None;
        let mut content = None;

        for field_value_inline_struct in
            body.parse_terminated::<RumaEventField, Token![,]>(RumaEventField::parse)?
        {
            match field_value_inline_struct {
                RumaEventField::Block(field_block) => {
                    let ident = match field_block.member {
                        Member::Named(ident) => ident,
                        Member::Unnamed(_) => panic!("fields with block values in `ruma_event!` must named `content_type_alias`"),
                    };

                    if ident == "content_type_alias" {
                        content = Some(Content::Typedef(field_block.typedef));
                    }
                }
                RumaEventField::InlineStruct(field_inline_struct) => {
                    let ident = match field_inline_struct.member {
                        Member::Named(ident) => ident,
                        Member::Unnamed(_) => panic!("fields with inline struct values in `ruma_event!` must be named `fields` or `content`."),
                    };

                    if ident == "fields" {
                        fields = Some(field_inline_struct.fields);
                    } else if ident == "content" {
                        content = Some(Content::Struct(field_inline_struct.fields));
                    }
                }
                RumaEventField::Value(field_value) => {
                    let ident = match field_value.member {
                        Member::Named(ident) => ident,
                        Member::Unnamed(_) => panic!("fields with expression values in `ruma_event!` must be named `kind` or `event_type`, ."),
                    };

                    if ident == "kind" {
                        let event_kind = match field_value.expr {
                            Expr::Path(expr_path) => {
                                if expr_path.path.is_ident("Event") {
                                    EventKind::Event
                                } else if expr_path.path.is_ident("RoomEvent") {
                                    EventKind::RoomEvent
                                } else if expr_path.path.is_ident("StateEvent") {
                                    EventKind::StateEvent
                                } else {
                                    panic!("value of field `kind` must be one of `Event`, `RoomEvent`, or `StateEvent`");
                                }
                            }
                            _ => panic!(
                                "value of field `kind` is required to be an ident by `ruma_event!`"
                            ),
                        };

                        kind = Some(event_kind);
                    } else if ident == "event_type" {
                        event_type = Some(match field_value.expr {
                            Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) => s,
                            // TODO: Span info
                            _ => panic!(
                                "value of field `event_type` is required to be a string literal by `ruma_event!`"
                            ),
                        })
                    } else {
                        panic!("unexpected field-value pair with field name `{}`", ident);
                    }
                }
            }
        }

        if kind.is_none() {
            panic!("field `kind` is required by `ruma_event!`");
        } else if event_type.is_none() {
            panic!("field `event_type` is required by `ruma_event!`");
        } else if content.is_none() {
            panic!(
                "one field named `content` or `content_type_alias` is required by `ruma_event!`"
            );
        }

        Ok(Self {
            attrs,
            name,
            kind: kind.unwrap(),
            event_type: event_type.unwrap(),
            fields,
            content: content.unwrap(),
        })
    }
}

/// Which kind of event is being generated.
///
/// Determined by the `kind` field in the macro body.
#[derive(PartialEq)]
pub enum EventKind {
    /// A basic event.
    Event,

    /// A room event.
    RoomEvent,

    /// A state event.
    StateEvent,
}

/// Information for generating the type used for the event's `content` field.
pub enum Content {
    /// A struct, e.g. `ExampleEventContent { ... }`.
    Struct(Vec<Field>),

    /// A type alias, e.g. `type ExampleEventContent = SomeExistingType`
    Typedef(Typedef),
}

/// The style of field within the macro body.
#[allow(clippy::large_enum_variant)]
enum RumaEventField {
    /// The value of a field is a block with a type alias in it.
    ///
    /// Used for `content_type_alias`.
    Block(FieldBlock),

    /// The value of a field is a block with named struct fields in it.
    ///
    /// Used for `content`.
    InlineStruct(FieldInlineStruct),

    /// A standard named struct field.
    ///
    /// Used for `kind` and `event_type`.
    Value(FieldValue),
}

impl Parse for RumaEventField {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let ahead = input.fork();
        let field_ident: Ident = ahead.parse()?;

        match field_ident.to_string().as_ref() {
            "content" | "fields" => {
                let attrs = input.call(Attribute::parse_outer)?;
                let member = input.parse()?;
                let colon_token = input.parse()?;
                let body;
                braced!(body in input);
                let fields = body
                    .parse_terminated::<Field, Token![,]>(Field::parse_named)?
                    .into_iter()
                    .collect();

                Ok(RumaEventField::InlineStruct(FieldInlineStruct {
                    attrs,
                    member,
                    colon_token,
                    fields,
                }))
            }
            "content_type_alias" => Ok(RumaEventField::Block(FieldBlock {
                attrs: input.call(Attribute::parse_outer)?,
                member: input.parse()?,
                colon_token: input.parse()?,
                typedef: input.parse()?,
            })),
            _ => Ok(RumaEventField::Value(input.parse()?)),
        }
    }
}

/// The value of a field is a block with a type alias in it.
///
/// Used for `content_type_alias`.
struct FieldBlock {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the field.
    pub member: Member,

    /// The colon that appears between the field name and type.
    pub colon_token: Colon,

    /// The path to the type that will be used in a type alias for the event's `content` type.
    pub typedef: Typedef,
}

/// The value of a field is a block with named struct fields in it.
///
/// Used for `content`.
struct FieldInlineStruct {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The name of the field.
    pub member: Member,

    /// The colon that appears between the field name and type.
    pub colon_token: Colon,

    /// The fields that define the `content` struct.
    pub fields: Vec<Field>,
}

/// Path to a type to be used in a type alias for an event's `content` type.
pub struct Typedef {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// Path to the type.
    pub path: TypePath,
}

impl Parse for Typedef {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let body;
        braced!(body in input);

        Ok(Self {
            attrs: body.call(Attribute::parse_outer)?,
            path: body.parse()?,
        })
    }
}
<|endoftext|>


<commit_before>#![allow(unused_doc_comment)]

#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate prettytable;
extern crate clap;
extern crate synapse_rpc as rpc;
extern crate serde;
extern crate serde_json;
extern crate reqwest;
extern crate url;
extern crate websocket;

mod cmd;
mod client;
mod error;

use std::process;

use url::Url;
use clap::{App, AppSettings, Arg, SubCommand};

use self::client::Client;

fn main() {
    let matches = App::new("sycli")
        .about("cli interface for synapse")
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("server")
                .help("URI of the synapse client to connect to.")
                .short("s")
                .long("server")
                .default_value("ws://localhost:8412/"),
        )
        .arg(
            Arg::with_name("password")
                .help("Password to use when connecting to synapse.")
                .short("p")
                .long("password")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("add")
                .about("Adds torrents to synapse.")
                .arg(
                    Arg::with_name("directory")
                        .help("Custom directory to download the torrent to.")
                        .short("d")
                        .long("directory")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("pause")
                        .help("Whether or not the torrent should start paused.")
                        .short("P")
                        .long("pause"),
                )
                .arg(
                    Arg::with_name("files")
                        .help("Torrent files to add")
                        .multiple(true)
                        .short("f")
                        .long("files")
                        .required(true)
                        .index(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("del")
                .about("Deletes torrents from synapse.")
                .arg(
                    Arg::with_name("torrents")
                        .help("Names of torrents to delete.")
                        .multiple(true)
                        .short("t")
                        .long("torrents")
                        .required(true)
                        .index(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("dl")
                .about("Downloads a torrent.")
                .arg(
                    Arg::with_name("torrent")
                        .help("Name of torrent to download.")
                        .short("t")
                        .long("torrent")
                        .index(1)
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("get")
                .about("Gets the specified resource.")
                .arg(
                    Arg::with_name("output")
                        .help("Output the results in the specified format.")
                        .short("o")
                        .long("output")
                        .possible_values(&["json", "text"])
                        .default_value("text"),
                )
                .arg(
                    Arg::with_name("id")
                        .help("ID of the resource.")
                        .index(1)
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("list")
                .about("Lists resources of a given type in synapse.")
                .arg(
                    Arg::with_name("filter")
                        .help(
                            "Apply an array of json formatted criterion to the resources.",
                        )
                        .short("f")
                        .long("filter")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("kind")
                        .help("The kind of resource to list.")
                        .possible_values(&["torrent", "peer", "file", "server", "tracker", "piece"])
                        .default_value("torrent")
                        .short("k")
                        .long("kind"),
                )
                .arg(
                    Arg::with_name("output")
                        .help("Output the results in the specified format.")
                        .short("o")
                        .long("output")
                        .possible_values(&["json", "text"])
                        .default_value("text"),
                ),
        )
        .subcommand(
            SubCommand::with_name("pause")
                .about("Pauses the given torrents.")
                .arg(
                    Arg::with_name("torrents")
                        .help("Names of torrents to pause.")
                        .multiple(true)
                        .short("t")
                        .long("torrents")
                        .index(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("resume")
                .about("Resumes the given torrents.")
                .arg(
                    Arg::with_name("torrents")
                        .help("Names of torrents to resume.")
                        .multiple(true)
                        .short("t")
                        .long("torrents")
                        .index(1),
                ),
        )
        .subcommand(SubCommand::with_name("status").about("Server status"))
        .subcommand(
            SubCommand::with_name("watch")
                .about("Watches the specified resource, printing out updates.")
                .arg(
                    Arg::with_name("output")
                        .help("Output the results in the specified format.")
                        .short("o")
                        .long("output")
                        .possible_values(&["json", "text"])
                        .default_value("text"),
                )
                .arg(
                    Arg::with_name("id")
                        .help("ID of the resource.")
                        .index(1)
                        .required(true),
                ),
        )
        .get_matches();

    let mut url = match Url::parse(matches.value_of("server").unwrap()) {
        Ok(url) => url,
        Err(_) => {
            eprintln!("Couldn't parse server URI!");
            process::exit(1);
        }
    };
    if let Some(password) = matches.value_of("password") {
        url.query_pairs_mut().append_pair("password", password);
    }
    let client = match Client::new(url.as_str()) {
        Ok(c) => c,
        Err(e) => {
            eprintln!("Failed to connect to synapse: {}!", e);
            process::exit(1);
        }
    };

    if client.version().major != rpc::MAJOR_VERSION {
        eprintln!(
            "synapse RPC major version {} is not compatible with sycli RPC major version {}",
            client.version().major,
            rpc::MAJOR_VERSION
        );
        process::exit(1);
    }
    if client.version().minor < rpc::MINOR_VERSION {
        eprintln!(
            "synapse RPC minor version {} is not compatible with sycli RPC minor version {}",
            client.version().minor,
            rpc::MINOR_VERSION
        );
        process::exit(1);
    }

    if url.scheme() == "wss" {
        url.set_scheme("https").unwrap();
    } else {
        url.set_scheme("http").unwrap();
    }

    match matches.subcommand_name().unwrap() {
        "add" => {
            let args = matches.subcommand_matches("add").unwrap();
            let mut files = Vec::new();
            for file in args.values_of("files").unwrap() {
                files.push(file)
            }
            let res = cmd::add(
                client,
                url.as_str(),
                files,
                args.value_of("directory"),
                !args.is_present("pause"),
            );
            if let Err(e) = res {
                eprintln!("Failed to add torrents: {:?}", e);
                process::exit(1);
            }
        }
        "del" => {
            let args = matches.subcommand_matches("del").unwrap();
            let res = cmd::del(client, args.values_of("torrents").unwrap().collect());
            if let Err(e) = res {
                eprintln!("Failed to delete torrents: {:?}", e);
                process::exit(1);
            }
        }
        "dl" => {
            let args = matches.subcommand_matches("dl").unwrap();
            let res = cmd::dl(client, url.as_str(), args.value_of("torrent").unwrap());
            if let Err(e) = res {
                eprintln!("Failed to download torrent: {:?}", e);
                process::exit(1);
            }
        }
        "get" => {
            let args = matches.subcommand_matches("get").unwrap();
            let id = args.value_of("id").unwrap();
            let output = args.value_of("output").unwrap();
            let res = cmd::get(client, id, output);
            if let Err(e) = res {
                eprintln!("Failed to get resource: {:?}", e);
                process::exit(1);
            }
        }
        "list" => {
            let args = matches.subcommand_matches("list").unwrap();
            let crit = args.value_of("filter")
                .and_then(|f| {
                    let single_crit = serde_json::from_str(f).map(|c| vec![c]).ok();
                    single_crit.or_else(|| serde_json::from_str(f).ok())
                })
                .unwrap_or(vec![]);
            let kind = args.value_of("kind").unwrap();
            let output = args.value_of("output").unwrap();
            let res = cmd::list(client, kind, crit, output);
            if let Err(e) = res {
                eprintln!("Failed to list torrents: {:?}", e);
                process::exit(1);
            }
        }
        "pause" => {
            let args = matches.subcommand_matches("pause").unwrap();
            let res = cmd::pause(client, args.values_of("torrents").unwrap().collect());
            if let Err(e) = res {
                eprintln!("Failed to pause torrents: {:?}", e);
                process::exit(1);
            }
        }
        "resume" => {
            let args = matches.subcommand_matches("resume").unwrap();
            let res = cmd::resume(client, args.values_of("torrents").unwrap().collect());
            if let Err(e) = res {
                eprintln!("Failed to resume torrents: {:?}", e);
                process::exit(1);
            }
        }
        "status" => {
            if let Err(e) = cmd::status(client) {
                eprintln!("Failed to get server status: {:?}", e);
                process::exit(1);
            }
        }
        "watch" => {
            let args = matches.subcommand_matches("watch").unwrap();
            let id = args.value_of("id").unwrap();
            let output = args.value_of("output").unwrap();
            let res = cmd::watch(client, id, output);
            if let Err(e) = res {
                eprintln!("Failed to watch resource: {:?}", e);
                process::exit(1);
            }
        }
        _ => {}
    }
}
<commit_msg>Require arguments for sycli pause and resume<commit_after>#![allow(unused_doc_comment)]

#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate prettytable;
extern crate clap;
extern crate synapse_rpc as rpc;
extern crate serde;
extern crate serde_json;
extern crate reqwest;
extern crate url;
extern crate websocket;

mod cmd;
mod client;
mod error;

use std::process;

use url::Url;
use clap::{App, AppSettings, Arg, SubCommand};

use self::client::Client;

fn main() {
    let matches = App::new("sycli")
        .about("cli interface for synapse")
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("server")
                .help("URI of the synapse client to connect to.")
                .short("s")
                .long("server")
                .default_value("ws://localhost:8412/"),
        )
        .arg(
            Arg::with_name("password")
                .help("Password to use when connecting to synapse.")
                .short("p")
                .long("password")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("add")
                .about("Adds torrents to synapse.")
                .arg(
                    Arg::with_name("directory")
                        .help("Custom directory to download the torrent to.")
                        .short("d")
                        .long("directory")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("pause")
                        .help("Whether or not the torrent should start paused.")
                        .short("P")
                        .long("pause"),
                )
                .arg(
                    Arg::with_name("files")
                        .help("Torrent files to add")
                        .multiple(true)
                        .short("f")
                        .long("files")
                        .required(true)
                        .index(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("del")
                .about("Deletes torrents from synapse.")
                .arg(
                    Arg::with_name("torrents")
                        .help("Names of torrents to delete.")
                        .multiple(true)
                        .short("t")
                        .long("torrents")
                        .required(true)
                        .index(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("dl")
                .about("Downloads a torrent.")
                .arg(
                    Arg::with_name("torrent")
                        .help("Name of torrent to download.")
                        .short("t")
                        .long("torrent")
                        .index(1)
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("get")
                .about("Gets the specified resource.")
                .arg(
                    Arg::with_name("output")
                        .help("Output the results in the specified format.")
                        .short("o")
                        .long("output")
                        .possible_values(&["json", "text"])
                        .default_value("text"),
                )
                .arg(
                    Arg::with_name("id")
                        .help("ID of the resource.")
                        .index(1)
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("list")
                .about("Lists resources of a given type in synapse.")
                .arg(
                    Arg::with_name("filter")
                        .help(
                            "Apply an array of json formatted criterion to the resources.",
                        )
                        .short("f")
                        .long("filter")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("kind")
                        .help("The kind of resource to list.")
                        .possible_values(&["torrent", "peer", "file", "server", "tracker", "piece"])
                        .default_value("torrent")
                        .short("k")
                        .long("kind"),
                )
                .arg(
                    Arg::with_name("output")
                        .help("Output the results in the specified format.")
                        .short("o")
                        .long("output")
                        .possible_values(&["json", "text"])
                        .default_value("text"),
                ),
        )
        .subcommand(
            SubCommand::with_name("pause")
                .about("Pauses the given torrents.")
                .arg(
                    Arg::with_name("torrents")
                        .help("Names of torrents to pause.")
                        .required(true)
                        .multiple(true)
                        .short("t")
                        .long("torrents")
                        .index(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("resume")
                .about("Resumes the given torrents.")
                .arg(
                    Arg::with_name("torrents")
                        .help("Names of torrents to resume.")
                        .required(true)
                        .multiple(true)
                        .short("t")
                        .long("torrents")
                        .index(1),
                ),
        )
        .subcommand(SubCommand::with_name("status").about("Server status"))
        .subcommand(
            SubCommand::with_name("watch")
                .about("Watches the specified resource, printing out updates.")
                .arg(
                    Arg::with_name("output")
                        .help("Output the results in the specified format.")
                        .short("o")
                        .long("output")
                        .possible_values(&["json", "text"])
                        .default_value("text"),
                )
                .arg(
                    Arg::with_name("id")
                        .help("ID of the resource.")
                        .index(1)
                        .required(true),
                ),
        )
        .get_matches();

    let mut url = match Url::parse(matches.value_of("server").unwrap()) {
        Ok(url) => url,
        Err(_) => {
            eprintln!("Couldn't parse server URI!");
            process::exit(1);
        }
    };
    if let Some(password) = matches.value_of("password") {
        url.query_pairs_mut().append_pair("password", password);
    }
    let client = match Client::new(url.as_str()) {
        Ok(c) => c,
        Err(e) => {
            eprintln!("Failed to connect to synapse: {}!", e);
            process::exit(1);
        }
    };

    if client.version().major != rpc::MAJOR_VERSION {
        eprintln!(
            "synapse RPC major version {} is not compatible with sycli RPC major version {}",
            client.version().major,
            rpc::MAJOR_VERSION
        );
        process::exit(1);
    }
    if client.version().minor < rpc::MINOR_VERSION {
        eprintln!(
            "synapse RPC minor version {} is not compatible with sycli RPC minor version {}",
            client.version().minor,
            rpc::MINOR_VERSION
        );
        process::exit(1);
    }

    if url.scheme() == "wss" {
        url.set_scheme("https").unwrap();
    } else {
        url.set_scheme("http").unwrap();
    }

    match matches.subcommand_name().unwrap() {
        "add" => {
            let args = matches.subcommand_matches("add").unwrap();
            let mut files = Vec::new();
            for file in args.values_of("files").unwrap() {
                files.push(file)
            }
            let res = cmd::add(
                client,
                url.as_str(),
                files,
                args.value_of("directory"),
                !args.is_present("pause"),
            );
            if let Err(e) = res {
                eprintln!("Failed to add torrents: {:?}", e);
                process::exit(1);
            }
        }
        "del" => {
            let args = matches.subcommand_matches("del").unwrap();
            let res = cmd::del(client, args.values_of("torrents").unwrap().collect());
            if let Err(e) = res {
                eprintln!("Failed to delete torrents: {:?}", e);
                process::exit(1);
            }
        }
        "dl" => {
            let args = matches.subcommand_matches("dl").unwrap();
            let res = cmd::dl(client, url.as_str(), args.value_of("torrent").unwrap());
            if let Err(e) = res {
                eprintln!("Failed to download torrent: {:?}", e);
                process::exit(1);
            }
        }
        "get" => {
            let args = matches.subcommand_matches("get").unwrap();
            let id = args.value_of("id").unwrap();
            let output = args.value_of("output").unwrap();
            let res = cmd::get(client, id, output);
            if let Err(e) = res {
                eprintln!("Failed to get resource: {:?}", e);
                process::exit(1);
            }
        }
        "list" => {
            let args = matches.subcommand_matches("list").unwrap();
            let crit = args.value_of("filter")
                .and_then(|f| {
                    let single_crit = serde_json::from_str(f).map(|c| vec![c]).ok();
                    single_crit.or_else(|| serde_json::from_str(f).ok())
                })
                .unwrap_or(vec![]);
            let kind = args.value_of("kind").unwrap();
            let output = args.value_of("output").unwrap();
            let res = cmd::list(client, kind, crit, output);
            if let Err(e) = res {
                eprintln!("Failed to list torrents: {:?}", e);
                process::exit(1);
            }
        }
        "pause" => {
            let args = matches.subcommand_matches("pause").unwrap();
            let res = cmd::pause(client, args.values_of("torrents").unwrap().collect());
            if let Err(e) = res {
                eprintln!("Failed to pause torrents: {:?}", e);
                process::exit(1);
            }
        }
        "resume" => {
            let args = matches.subcommand_matches("resume").unwrap();
            let res = cmd::resume(client, args.values_of("torrents").unwrap().collect());
            if let Err(e) = res {
                eprintln!("Failed to resume torrents: {:?}", e);
                process::exit(1);
            }
        }
        "status" => {
            if let Err(e) = cmd::status(client) {
                eprintln!("Failed to get server status: {:?}", e);
                process::exit(1);
            }
        }
        "watch" => {
            let args = matches.subcommand_matches("watch").unwrap();
            let id = args.value_of("id").unwrap();
            let output = args.value_of("output").unwrap();
            let res = cmd::watch(client, id, output);
            if let Err(e) = res {
                eprintln!("Failed to watch resource: {:?}", e);
                process::exit(1);
            }
        }
        _ => {}
    }
}
<|endoftext|>


<commit_before>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        {
            let container = try!(self.lookup_mut(id));
            if !container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");

            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(edge, new_geo);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, mut edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // This is the vector of operations we will perform, we do all geometry sets atomically.
        let mut resizing_ops: Vec<(Uuid, (ResizeEdge, Geometry))> = Vec::with_capacity(4);
        edge &= !RESIZE_TOP;
        edge &= !RESIZE_BOTTOM;
        let dirs_moving_in = Direction::from_edge(edge);
        assert_eq!(dirs_moving_in.len(), 1);
        let next_container = try!(self.container_in_dir(id, dirs_moving_in[0]));
        {
            let container = try!(self.lookup(next_container.0));//try!(self.lookup(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            if is_making_too_small(geo, edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            resizing_ops.push((next_container.0, (edge, new_geo)));
        }
        let siblings: Vec<Uuid> = vec!(next_container.1);
        /*let siblings: Vec<Uuid> = dirs_moving_in.iter()
            .map(|dir| {
                self.container_in_dir(id, *dir)
                    .map(|uuids| {
                        let container = try!(self.lookup(id));
                        let geo = container.get_geometry()
                            .expect("Could not get geometry of the container");
                        let new_geo = calculate_resize(geo, edge, pointer, action.grab);
                        resizing_ops.push((uuids.0, (edge, new_geo)));
                        Ok(uuids.1)
                    })
            })
        // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();

         */
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                         vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            if is_making_too_small(geo, reversed_edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, reversed_edge, pointer, action.grab);
            resizing_ops.push((sibling, (reversed_edge, new_geo)));
            container.set_geometry(reversed_edge, new_geo);
        }
        action.grab = pointer;
        for (id, (edge, geo)) in resizing_ops {
            let container = self.lookup_mut(id)
                .expect("Id no longer points to node!");
            container.set_geometry(edge, geo);
        }
        action.grab = pointer;
        let node_ix = self.tree.lookup_id(id).unwrap();
        let workspace_ix = self.tree.ancestor_of_type(node_ix, ContainerType::Workspace).unwrap();
        self.layout(workspace_ix);
        self.update_pointer_pos(id, edge)
    }
}

/// Calculates what the new geometry is of a window.
/// Needs the geometry of the window, the edge direction the pointer is moving in,
/// the current position of the pointer, and the previous place the pointer was at.
fn calculate_resize(geo: Geometry, edge: ResizeEdge,
                    cur_pointer: Point, prev_pointer: Point) -> Geometry {
    let mut new_geo = geo.clone();
    let dx = cur_pointer.x - prev_pointer.x;
    let dy = cur_pointer.y - prev_pointer.y;
    if edge.contains(RESIZE_LEFT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        }
    }

    if new_geo.size.w < MIN_SIZE.w {
        new_geo.origin.x = geo.origin.x;
        new_geo.size.w = MIN_SIZE.w;
    }

    if new_geo.size.h < MIN_SIZE.h {
        new_geo.origin.y = geo.origin.y;
        new_geo.size.h = MIN_SIZE.h;
    }
    new_geo
}

/// If the geometry is at the minimum size (in either the x or y plane)
/// and the pointer is trying to make it even smaller in that direction,
/// the it returns true (to indicate you should abandon all operations).
///
/// Otherwise returns false
fn is_making_too_small(geo: Geometry, edge: ResizeEdge, cur_point: Point,
                       prev_point: Point) -> bool {
    if geo.size.w > MIN_SIZE.w && geo.size.h > MIN_SIZE.h {
        return false
    }
    if edge.contains(RESIZE_RIGHT) && cur_point.x - prev_point.x < 0 {
        true
    } else if edge.contains(RESIZE_LEFT) && cur_point.x - prev_point.x > 0 {
        true
    } else if edge.contains(RESIZE_TOP) && cur_point.y - prev_point.y > 0 {
        true
    } else if edge.contains(RESIZE_BOTTOM) && cur_point.y - prev_point.y < 0 {
        true
    } else {
        false
    }
}
<commit_msg>Nearly there...<commit_after>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        {
            let container = try!(self.lookup_mut(id));
            if !container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");

            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(edge, new_geo);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, mut edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // This is the vector of operations we will perform, we do all geometry sets atomically.
        let mut resizing_ops: Vec<(Uuid, (ResizeEdge, Geometry))> = Vec::with_capacity(4);
        let dirs_moving_in = Direction::from_edge(edge);
        let next_containers: Vec<(Uuid, Uuid)> = dirs_moving_in.iter()
            .map(|dir| self.container_in_dir(id, *dir))
            // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();
        for ancestor_id in next_containers.iter().map(|uuids| uuids.0) {
            let container = try!(self.lookup(ancestor_id));//try!(self.lookup(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(ancestor_id)))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(ancestor_id,
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            if is_making_too_small(geo, edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            resizing_ops.push((ancestor_id, (edge, new_geo)));
        }
        let siblings: Vec<Uuid> = next_containers.into_iter()
            .map(|uuids| uuids.1).collect();
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                         vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            if is_making_too_small(geo, reversed_edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, reversed_edge, pointer, action.grab);
            resizing_ops.push((sibling, (reversed_edge, new_geo)));
            container.set_geometry(reversed_edge, new_geo);
        }
        action.grab = pointer;
        for (id, (edge, geo)) in resizing_ops {
            let container = self.lookup_mut(id)
                .expect("Id no longer points to node!");
            container.set_geometry(edge, geo);
        }
        action.grab = pointer;
        let node_ix = self.tree.lookup_id(id).unwrap();
        let workspace_ix = self.tree.ancestor_of_type(node_ix, ContainerType::Workspace).unwrap();
        self.layout(workspace_ix);
        self.update_pointer_pos(id, edge)
    }
}

/// Calculates what the new geometry is of a window.
/// Needs the geometry of the window, the edge direction the pointer is moving in,
/// the current position of the pointer, and the previous place the pointer was at.
fn calculate_resize(geo: Geometry, edge: ResizeEdge,
                    cur_pointer: Point, prev_pointer: Point) -> Geometry {
    let mut new_geo = geo.clone();
    let dx = cur_pointer.x - prev_pointer.x;
    let dy = cur_pointer.y - prev_pointer.y;
    if edge.contains(RESIZE_LEFT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        }
    }

    if new_geo.size.w < MIN_SIZE.w {
        new_geo.origin.x = geo.origin.x;
        new_geo.size.w = MIN_SIZE.w;
    }

    if new_geo.size.h < MIN_SIZE.h {
        new_geo.origin.y = geo.origin.y;
        new_geo.size.h = MIN_SIZE.h;
    }
    new_geo
}

/// If the geometry is at the minimum size (in either the x or y plane)
/// and the pointer is trying to make it even smaller in that direction,
/// the it returns true (to indicate you should abandon all operations).
///
/// Otherwise returns false
fn is_making_too_small(geo: Geometry, edge: ResizeEdge, cur_point: Point,
                       prev_point: Point) -> bool {
    if geo.size.w > MIN_SIZE.w && geo.size.h > MIN_SIZE.h {
        return false
    }
    if edge.contains(RESIZE_RIGHT) && cur_point.x - prev_point.x < 0 {
        true
    } else if edge.contains(RESIZE_LEFT) && cur_point.x - prev_point.x > 0 {
        true
    } else if edge.contains(RESIZE_TOP) && cur_point.y - prev_point.y > 0 {
        true
    } else if edge.contains(RESIZE_BOTTOM) && cur_point.y - prev_point.y < 0 {
        true
    } else {
        false
    }
}
<|endoftext|>


<commit_before>fn main() {
    let data: [u8; std::isize::MAX as usize] = [42; std::isize::MAX as usize];
    //~^ ERROR: rustc layout computation failed: SizeOverflow([u8;
    assert_eq!(data.len(), 1024);
}
<commit_msg>Make layout SizeOverflow test trigger on i686.<commit_after>fn main() {
    let data: [u8; std::usize::MAX] = [42; std::usize::MAX];
    //~^ ERROR: rustc layout computation failed: SizeOverflow([u8;
    assert_eq!(data.len(), 1024);
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0533: r##"
The export_name attribute was badly formatted.

Erroneous code example:

```compile_fail,E0533
#[export_name] // error: export_name attribute has invalid format
pub fn something() {}

fn main() {}
```

The export_name attribute expects a string in order to determine the name of
the exported symbol. Example:

```
#[export_name = "some function"] // ok!
pub fn something() {}

fn main() {}
```
"##,

E0534: r##"
The inline attribute was badly used.

Erroneous code example:

```compile_fail,E0534
#[inline()] // error: expected one argument
pub fn something() {}

fn main() {}
```

The inline attribute can be used without arguments:

```
#[inline] // ok!
pub fn something() {}

fn main() {}
```

Or with arguments (and parens have to be used for this case!):

```
#[inline(always)] // ok!
pub fn something() {}

fn main() {}
```

For more information about the inline attribute, take a look here:
https://doc.rust-lang.org/reference.html#inline-attributes)
"##,

}

register_diagnostics! {
    E0535, // invalid argument
    E0536, // expected 1 cfg-pattern
    E0537, // invalid predicate
    E0538, // multiple [same] items
    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0541, // unknown meta item
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
    E0548, // incorrect stability attribute type
    E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
    E0550, // multiple deprecated attributes
    E0551, // incorrect meta item
    E0552, // unrecognized representation hint
    E0553, // unrecognized enum representation hint
    E0554, // #[feature] may not be used on the [] release channel
    E0555, // malformed feature attribute, expected #![feature(...)]
    E0556, // malformed feature, expected just one word
    E0557, // feature has been removed
}
<commit_msg>Add E0535 error explanation<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0533: r##"
The export_name attribute was badly formatted.

Erroneous code example:

```compile_fail,E0533
#[export_name] // error: export_name attribute has invalid format
pub fn something() {}

fn main() {}
```

The export_name attribute expects a string in order to determine the name of
the exported symbol. Example:

```
#[export_name = "some function"] // ok!
pub fn something() {}

fn main() {}
```
"##,

E0534: r##"
The inline attribute was badly used.

Erroneous code example:

```compile_fail,E0534
#[inline()] // error: expected one argument
pub fn something() {}

fn main() {}
```

The inline attribute can be used without arguments:

```
#[inline] // ok!
pub fn something() {}

fn main() {}
```

Or with arguments (and parens have to be used for this case!):

```
#[inline(always)] // ok!
pub fn something() {}

fn main() {}
```

For more information about the inline attribute, take a look here:
https://doc.rust-lang.org/reference.html#inline-attributes)
"##,

E0535: r##"
An unknown argument was given to inline attribute.

Erroneous code example:

```compile_fail,E0535
#[inline(unknown)] // error: invalid argument
pub fn something() {}

fn main() {}
```

The inline attribute only knows two arguments:

 * always
 * never

All other arguments given to the inline attribute will return this error.
Example:

```
#[inline(never)] // ok!
pub fn something() {}

fn main() {}
```

For more information about the inline attribute, take a look here:
https://doc.rust-lang.org/reference.html#inline-attributes)
"##,

}

register_diagnostics! {
    E0536, // expected 1 cfg-pattern
    E0537, // invalid predicate
    E0538, // multiple [same] items
    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0541, // unknown meta item
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
    E0548, // incorrect stability attribute type
    E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
    E0550, // multiple deprecated attributes
    E0551, // incorrect meta item
    E0552, // unrecognized representation hint
    E0553, // unrecognized enum representation hint
    E0554, // #[feature] may not be used on the [] release channel
    E0555, // malformed feature attribute, expected #![feature(...)]
    E0556, // malformed feature, expected just one word
    E0557, // feature has been removed
}
<|endoftext|>


<commit_before>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::marker::Unpin;
use crate::ops;
use crate::pin::Pin;
use crate::task::{Context, Poll};

/// A future represents an asynchronous computation.
///
/// A future is a value that may not have finished computing yet. This kind of
/// "asynchronous value" makes it possible for a thread to continue doing useful
/// work while it waits for the value to become available.
///
/// # The `poll` method
///
/// The core method of future, `poll`, *attempts* to resolve the future into a
/// final value. This method does not block if the value is not ready. Instead,
/// the current task is scheduled to be woken up when it's possible to make
/// further progress by `poll`ing again. The `context` passed to the `poll`
/// method can provide a `Waker`, which is a handle for waking up the current
/// task.
///
/// When using a future, you generally won't call `poll` directly, but instead
/// `await!` the value.
#[doc(spotlight)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
pub trait Future {
    /// The type of value produced on completion.
    #[stable(feature = "futures_api", since = "1.36.0")]
    type Output;

    /// Attempt to resolve the future to a final value, registering
    /// the current task for wakeup if the value is not yet available.
    ///
    /// # Return value
    ///
    /// This function returns:
    ///
    /// - [`Poll::Pending`] if the future is not ready yet
    /// - [`Poll::Ready(val)`] with the result `val` of this future if it
    ///   finished successfully.
    ///
    /// Once a future has finished, clients should not `poll` it again.
    ///
    /// When a future is not ready yet, `poll` returns `Poll::Pending` and
    /// stores a clone of the [`Waker`] copied from the current [`Context`].
    /// This [`Waker`] is then woken once the future can make progress.
    /// For example, a future waiting for a socket to become
    /// readable would call `.clone()` on the [`Waker`] and store it.
    /// When a signal arrives elsewhere indicating that the socket is readable,
    /// [`Waker::wake`] is called and the socket future's task is awoken.
    /// Once a task has been woken up, it should attempt to `poll` the future
    /// again, which may or may not produce a final value.
    ///
    /// Note that on multiple calls to `poll`, only the [`Waker`] from the
    /// [`Context`] passed to the most recent call should be scheduled to
    /// receive a wakeup.
    ///
    /// # Runtime characteristics
    ///
    /// Futures alone are *inert*; they must be *actively* `poll`ed to make
    /// progress, meaning that each time the current task is woken up, it should
    /// actively re-`poll` pending futures that it still has an interest in.
    ///
    /// The `poll` function is not called repeatedly in a tight loop -- instead,
    /// it should only be called when the future indicates that it is ready to
    /// make progress (by calling `wake()`). If you're familiar with the
    /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
    /// typically do *not* suffer the same problems of "all wakeups must poll
    /// all events"; they are more like `epoll(4)`.
    ///
    /// An implementation of `poll` should strive to return quickly, and should
    /// not block. Returning quickly prevents unnecessarily clogging up
    /// threads or event loops. If it is known ahead of time that a call to
    /// `poll` may end up taking awhile, the work should be offloaded to a
    /// thread pool (or something similar) to ensure that `poll` can return
    /// quickly.
    ///
    /// # Panics
    ///
    /// Once a future has completed (returned `Ready` from `poll`), calling its
    /// `poll` method again may panic, block forever, or cause other kinds of
    /// problems; the `Future` trait places no requirements on the effects of
    /// such a call. However, as the `poll` method is not marked `unsafe`,
    /// Rust's usual rules apply: calls must never cause undefined behavior
    /// (memory corruption, incorrect use of `unsafe` functions, or the like),
    /// regardless of the future's state.
    ///
    /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
    /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
    /// [`Context`]: ../task/struct.Context.html
    /// [`Waker`]: ../task/struct.Waker.html
    /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake
    #[stable(feature = "futures_api", since = "1.36.0")]
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: ?Sized + Future + Unpin> Future for &mut F {
    type Output = F::Output;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        F::poll(Pin::new(&mut **self), cx)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl
 Future for Pin

where
    P: Unpin + ops::DerefMut,
    P::Target: Future,
{
    type Output = <
::Target as Future>::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Pin::get_mut(self).as_mut().poll(cx)
    }
}
<commit_msg>Use .await syntax instead of await!<commit_after>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::marker::Unpin;
use crate::ops;
use crate::pin::Pin;
use crate::task::{Context, Poll};

/// A future represents an asynchronous computation.
///
/// A future is a value that may not have finished computing yet. This kind of
/// "asynchronous value" makes it possible for a thread to continue doing useful
/// work while it waits for the value to become available.
///
/// # The `poll` method
///
/// The core method of future, `poll`, *attempts* to resolve the future into a
/// final value. This method does not block if the value is not ready. Instead,
/// the current task is scheduled to be woken up when it's possible to make
/// further progress by `poll`ing again. The `context` passed to the `poll`
/// method can provide a `Waker`, which is a handle for waking up the current
/// task.
///
/// When using a future, you generally won't call `poll` directly, but instead
/// `.await` the value.
#[doc(spotlight)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
pub trait Future {
    /// The type of value produced on completion.
    #[stable(feature = "futures_api", since = "1.36.0")]
    type Output;

    /// Attempt to resolve the future to a final value, registering
    /// the current task for wakeup if the value is not yet available.
    ///
    /// # Return value
    ///
    /// This function returns:
    ///
    /// - [`Poll::Pending`] if the future is not ready yet
    /// - [`Poll::Ready(val)`] with the result `val` of this future if it
    ///   finished successfully.
    ///
    /// Once a future has finished, clients should not `poll` it again.
    ///
    /// When a future is not ready yet, `poll` returns `Poll::Pending` and
    /// stores a clone of the [`Waker`] copied from the current [`Context`].
    /// This [`Waker`] is then woken once the future can make progress.
    /// For example, a future waiting for a socket to become
    /// readable would call `.clone()` on the [`Waker`] and store it.
    /// When a signal arrives elsewhere indicating that the socket is readable,
    /// [`Waker::wake`] is called and the socket future's task is awoken.
    /// Once a task has been woken up, it should attempt to `poll` the future
    /// again, which may or may not produce a final value.
    ///
    /// Note that on multiple calls to `poll`, only the [`Waker`] from the
    /// [`Context`] passed to the most recent call should be scheduled to
    /// receive a wakeup.
    ///
    /// # Runtime characteristics
    ///
    /// Futures alone are *inert*; they must be *actively* `poll`ed to make
    /// progress, meaning that each time the current task is woken up, it should
    /// actively re-`poll` pending futures that it still has an interest in.
    ///
    /// The `poll` function is not called repeatedly in a tight loop -- instead,
    /// it should only be called when the future indicates that it is ready to
    /// make progress (by calling `wake()`). If you're familiar with the
    /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
    /// typically do *not* suffer the same problems of "all wakeups must poll
    /// all events"; they are more like `epoll(4)`.
    ///
    /// An implementation of `poll` should strive to return quickly, and should
    /// not block. Returning quickly prevents unnecessarily clogging up
    /// threads or event loops. If it is known ahead of time that a call to
    /// `poll` may end up taking awhile, the work should be offloaded to a
    /// thread pool (or something similar) to ensure that `poll` can return
    /// quickly.
    ///
    /// # Panics
    ///
    /// Once a future has completed (returned `Ready` from `poll`), calling its
    /// `poll` method again may panic, block forever, or cause other kinds of
    /// problems; the `Future` trait places no requirements on the effects of
    /// such a call. However, as the `poll` method is not marked `unsafe`,
    /// Rust's usual rules apply: calls must never cause undefined behavior
    /// (memory corruption, incorrect use of `unsafe` functions, or the like),
    /// regardless of the future's state.
    ///
    /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
    /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
    /// [`Context`]: ../task/struct.Context.html
    /// [`Waker`]: ../task/struct.Waker.html
    /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake
    #[stable(feature = "futures_api", since = "1.36.0")]
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: ?Sized + Future + Unpin> Future for &mut F {
    type Output = F::Output;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        F::poll(Pin::new(&mut **self), cx)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl
 Future for Pin

where
    P: Unpin + ops::DerefMut,
    P::Target: Future,
{
    type Output = <
::Target as Future>::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Pin::get_mut(self).as_mut().poll(cx)
    }
}
<|endoftext|>


<commit_before>//! Platform-independent platform abstraction
//!
//! This is the platform-independent portion of the standard library's
//! platform abstraction layer, whereas `std::sys` is the
//! platform-specific portion.
//!
//! The relationship between `std::sys_common`, `std::sys` and the
//! rest of `std` is complex, with dependencies going in all
//! directions: `std` depending on `sys_common`, `sys_common`
//! depending on `sys`, and `sys` depending on `sys_common` and `std`.
//! Ideally `sys_common` would be split into two and the dependencies
//! between them all would form a dag, facilitating the extraction of
//! `std::sys` from the standard library.

#![allow(missing_docs)]
#![allow(missing_debug_implementations)]

use crate::sync::Once;
use crate::sys;

macro_rules! rtabort {
    ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*)))
}

macro_rules! rtassert {
    ($e:expr) => (if !$e {
        rtabort!(concat!("assertion failed: ", stringify!($e)));
    })
}

#[allow(unused_macros)] // not used on all platforms
macro_rules! rtunwrap {
    ($ok:ident, $e:expr) => (if let $ok(v) = $e {
        v
    } else {
        rtabort!(concat!("unwrap failed: ", stringify!($e)));
    })
}

pub mod alloc;
pub mod at_exit_imp;
#[cfg(feature = "backtrace")]
pub mod backtrace;
pub mod condvar;
pub mod io;
pub mod mutex;
#[cfg(any(rustdoc, // see `mod os`, docs are generated for multiple platforms
          unix,
          target_os = "redox",
          target_os = "cloudabi",
          target_arch = "wasm32",
          all(target_vendor = "fortanix", target_env = "sgx")))]
pub mod os_str_bytes;
pub mod poison;
pub mod remutex;
pub mod rwlock;
pub mod thread;
pub mod thread_info;
pub mod thread_local;
pub mod util;
pub mod wtf8;
pub mod bytestring;
pub mod process;
pub mod fs;

cfg_if! {
    if #[cfg(any(target_os = "cloudabi",
                 target_os = "l4re",
                 target_os = "redox",
                 all(target_arch = "wasm32", not(target_os = "emscripten")),
                 all(target_vendor = "fortanix", target_env = "sgx")))] {
        pub use crate::sys::net;
    } else {
        pub mod net;
    }
}

#[cfg(feature = "backtrace")]
#[cfg(any(all(unix, not(target_os = "emscripten")),
          all(windows, target_env = "gnu"),
          target_os = "redox"))]
pub mod gnu;

// common error constructors

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInner<Inner: ?Sized> {
    fn as_inner(&self) -> &Inner;
}

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInnerMut<Inner: ?Sized> {
    fn as_inner_mut(&mut self) -> &mut Inner;
}

/// A trait for extracting representations from std types
#[doc(hidden)]
pub trait IntoInner<Inner> {
    fn into_inner(self) -> Inner;
}

/// A trait for creating std types from internal representations
#[doc(hidden)]
pub trait FromInner<Inner> {
    fn from_inner(inner: Inner) -> Self;
}

/// Enqueues a procedure to run when the main thread exits.
///
/// Currently these closures are only run once the main *Rust* thread exits.
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
/// infinitely so. Eventually a handler registration will be forced to fail.
///
/// Returns `Ok` if the handler was successfully registered, meaning that the
/// closure will be run once the main thread exits. Returns `Err` to indicate
/// that the closure could not be registered, meaning that it is not scheduled
/// to be run.
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
    if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
}

/// One-time runtime cleanup.
pub fn cleanup() {
    static CLEANUP: Once = Once::new();
    CLEANUP.call_once(|| unsafe {
        sys::args::cleanup();
        sys::stack_overflow::cleanup();
        at_exit_imp::cleanup();
    });
}

// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
#[allow(dead_code)] // not used on all platforms
pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
    let q = value / denom;
    let r = value % denom;
    // Decompose value as (value/denom*denom + value%denom),
    // substitute into (value*numer)/denom and simplify.
    // r < denom, so (denom*numer) is the upper bound of (r*numer)
    q * numer + r * numer / denom
}

#[test]
fn test_muldiv() {
    assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000),
               1_000_000_000_001_000);
}
<commit_msg>Auto merge of #60204 - jethrogb:jb/rtunwrap-debug-print, r=alexcrichton<commit_after>//! Platform-independent platform abstraction
//!
//! This is the platform-independent portion of the standard library's
//! platform abstraction layer, whereas `std::sys` is the
//! platform-specific portion.
//!
//! The relationship between `std::sys_common`, `std::sys` and the
//! rest of `std` is complex, with dependencies going in all
//! directions: `std` depending on `sys_common`, `sys_common`
//! depending on `sys`, and `sys` depending on `sys_common` and `std`.
//! Ideally `sys_common` would be split into two and the dependencies
//! between them all would form a dag, facilitating the extraction of
//! `std::sys` from the standard library.

#![allow(missing_docs)]
#![allow(missing_debug_implementations)]

use crate::sync::Once;
use crate::sys;

macro_rules! rtabort {
    ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*)))
}

macro_rules! rtassert {
    ($e:expr) => (if !$e {
        rtabort!(concat!("assertion failed: ", stringify!($e)));
    })
}

#[allow(unused_macros)] // not used on all platforms
macro_rules! rtunwrap {
    ($ok:ident, $e:expr) => (match $e {
        $ok(v) => v,
        ref err => {
            let err = err.as_ref().map(|_|()); // map Ok/Some which might not be Debug
            rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
        },
    })
}

pub mod alloc;
pub mod at_exit_imp;
#[cfg(feature = "backtrace")]
pub mod backtrace;
pub mod condvar;
pub mod io;
pub mod mutex;
#[cfg(any(rustdoc, // see `mod os`, docs are generated for multiple platforms
          unix,
          target_os = "redox",
          target_os = "cloudabi",
          target_arch = "wasm32",
          all(target_vendor = "fortanix", target_env = "sgx")))]
pub mod os_str_bytes;
pub mod poison;
pub mod remutex;
pub mod rwlock;
pub mod thread;
pub mod thread_info;
pub mod thread_local;
pub mod util;
pub mod wtf8;
pub mod bytestring;
pub mod process;
pub mod fs;

cfg_if! {
    if #[cfg(any(target_os = "cloudabi",
                 target_os = "l4re",
                 target_os = "redox",
                 all(target_arch = "wasm32", not(target_os = "emscripten")),
                 all(target_vendor = "fortanix", target_env = "sgx")))] {
        pub use crate::sys::net;
    } else {
        pub mod net;
    }
}

#[cfg(feature = "backtrace")]
#[cfg(any(all(unix, not(target_os = "emscripten")),
          all(windows, target_env = "gnu"),
          target_os = "redox"))]
pub mod gnu;

// common error constructors

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInner<Inner: ?Sized> {
    fn as_inner(&self) -> &Inner;
}

/// A trait for viewing representations from std types
#[doc(hidden)]
pub trait AsInnerMut<Inner: ?Sized> {
    fn as_inner_mut(&mut self) -> &mut Inner;
}

/// A trait for extracting representations from std types
#[doc(hidden)]
pub trait IntoInner<Inner> {
    fn into_inner(self) -> Inner;
}

/// A trait for creating std types from internal representations
#[doc(hidden)]
pub trait FromInner<Inner> {
    fn from_inner(inner: Inner) -> Self;
}

/// Enqueues a procedure to run when the main thread exits.
///
/// Currently these closures are only run once the main *Rust* thread exits.
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
/// infinitely so. Eventually a handler registration will be forced to fail.
///
/// Returns `Ok` if the handler was successfully registered, meaning that the
/// closure will be run once the main thread exits. Returns `Err` to indicate
/// that the closure could not be registered, meaning that it is not scheduled
/// to be run.
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
    if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
}

/// One-time runtime cleanup.
pub fn cleanup() {
    static CLEANUP: Once = Once::new();
    CLEANUP.call_once(|| unsafe {
        sys::args::cleanup();
        sys::stack_overflow::cleanup();
        at_exit_imp::cleanup();
    });
}

// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
#[allow(dead_code)] // not used on all platforms
pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
    let q = value / denom;
    let r = value % denom;
    // Decompose value as (value/denom*denom + value%denom),
    // substitute into (value*numer)/denom and simplify.
    // r < denom, so (denom*numer) is the upper bound of (r*numer)
    q * numer + r * numer / denom
}

#[test]
fn test_muldiv() {
    assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000),
               1_000_000_000_001_000);
}
<|endoftext|>


<commit_before>//! Check and checkmate detection.

use rules::game_state::GameState;
use board::piece::Piece;
use board::player::Player;

impl GameState {
    // Returns true if the given player is is in check.
    pub fn is_check(&self, player: Player) -> bool {
        let own_board = self.player_board(player);
        let king_square = own_board.king.to_square();
        let own_pieces = own_board.all();
        let opponent_pieces = self.player_board(player.other());

        // if for example, bishop attacks from the king contains a bishop,
        // then a bishop can attack the king. Repeat this for all pieces.
        Piece::iter().any(|p| {
            !(p.attacks(king_square, player, own_pieces, opponent_pieces.all()) & opponent_pieces.piece(p)).is_empty()
        })
    }

    /// Returns true if the player whose turn it is has been mated.
    pub fn is_mate(&self) -> bool {
        self.legal_moves().is_empty()
    }
}
<commit_msg>Add stale mate check<commit_after>//! Check and checkmate detection.

use rules::game_state::GameState;
use board::piece::Piece;
use board::player::Player;

impl GameState {
    // Returns true if the given player is is in check.
    pub fn is_check(&self, player: Player) -> bool {
        let own_board = self.player_board(player);
        let king_square = own_board.king.to_square();
        let own_pieces = own_board.all();
        let opponent_pieces = self.player_board(player.other());

        // if for example, bishop attacks from the king contains a bishop,
        // then a bishop can attack the king. Repeat this for all pieces.
        Piece::iter().any(|p| {
            !(p.attacks(king_square, player, own_pieces, opponent_pieces.all()) & opponent_pieces.piece(p)).is_empty()
        })
    }

    /// Returns true if the player whose turn it is has been mated.
    pub fn is_mate(&self, player: Player) -> bool {
        self.is_check(player) && self.legal_moves().is_empty()
    }

    /// Returns true if there is a stale mate.
    pub fn is_stale_mate(&self, player: Player) -> bool {
        !self.is_check(player) && self.legal_moves().is_empty()
    }
}
<|endoftext|>


<commit_before>pub mod symbol_table;
use std::collections::HashMap;

pub trait StaticSymbolTable<'a>
{
	/// Return all symbols in this table with the specified name (in any namespace)
	fn lookup_by_name(&self, name: &str) -> Vec<Symbol<'a>>;

	/// Return all symbols in this table with the specified namespace
	fn lookup_by_namespace(&self, namespace: &str) -> Vec<Symbol<'a>>;

	/// Lookup a variable by its name and namespace. Duplicate symbols are not allowed, so the result will be unique
	/// @return the specified symbol or None if the specified symbol is not in this namespace
	fn lookup_variable(&self, namespace: &str, name: &str) -> Option<Symbol<'a>>;

	/// Lookup a function by its name and namespace. Functions with the same signature are not allowed, so the result will be unique
	/// If no result is found in the direct namespace, the parent namespaces will be searched
	/// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_function(&self, namespace: &str, name: &str, argument_types: &Vec<&str>) -> Option<Symbol<'a>>;

	/// Lookup a structure (class, enum) by its name and namespace.
	/// Duplicate classes in the same namespace are not allowed, so the result will be unique
	/// If no result is found in the direct namespace, the parent namespaces will be searched
	/// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_structure(&self, namespace: &str, name: &str) -> Option<(Symbol<'a>)>;

	/// Adds a symbol to this table and allocates it's location
	/// Returns true if the symbol could be added; false otherwise
	/// Duplicate symbols are not allowed
	/// TODO: support overloaded methods
	fn add(&self, class: SymbolClass<'a>, namespace: &'a str, name: &'a str) -> bool;
}

pub enum SymbolLocation<'a>
{
	/// Indicates that a register has been reserved for a specific use (e.g. by a variable)
	/// tuple: (name)
	Register(&'a str),

	/// Indicates a location in memory (e.g. for static variables)
	/// tuple: (address)
	Memory(MemoryAddress<'a>),

	/// Indicates an offset location from a structured entity (e.g. a member variable of a class)
	/// tuple: offset
	InstancedMemory(u16),

	/// Indicates that the symbol should not be accessed, as it represents a structured entity
	Structured
}

pub enum SymbolClass<'a>
{
	Variable { variable_type: &'a str },

	/// Function signature //TODO: support exceptions
	Function { return_type: &'a str, argument_types: &'a Vec<&'a str> },

	/// Includes class, enum, and interface
	Structure { subtype: &'a str },
}

pub struct Symbol<'a>
{
	/// Namespace of this symbol, without the final "." or the name of this symbol
	pub namespace: &'a str,

	/// Identifier for the symbol (e.g. name of variable, function, class, etc. without it's namespace)
	pub name: &'a str,

	/// What this symbol represents (class, enum, variable, function, etc)
	pub symbol_class: SymbolClass<'a>,

	/// Memory location of this symbol. Methods will always map to a SymbolLocation::Memory label with a 0 offset
	pub location: SymbolLocation<'a>,
}

pub struct MemoryAddress<'a>
{
	/// Label marking the base address where the symbol is stored
	pub label_name: &'a str,

	/// Offset from the base address to access the symbol. Methods will always have an offset of 0
	pub offset: u16,
}
<commit_msg>Convert SymbolClass to tuple nests<commit_after>pub mod symbol_table;
use std::collections::HashMap;

pub trait StaticSymbolTable<'a>
{
	/// Return all symbols in this table with the specified name (in any namespace)
	fn lookup_by_name(&self, name: &str) -> Vec<Symbol<'a>>;

	/// Return all symbols in this table with the specified namespace
	fn lookup_by_namespace(&self, namespace: &str) -> Vec<Symbol<'a>>;

	/// Lookup a variable by its name and namespace. Duplicate symbols are not allowed, so the result will be unique
	/// @return the specified symbol or None if the specified symbol is not in this namespace
	fn lookup_variable(&self, namespace: &str, name: &str) -> Option<Symbol<'a>>;

	/// Lookup a function by its name and namespace. Functions with the same signature are not allowed, so the result will be unique
	/// If no result is found in the direct namespace, the parent namespaces will be searched
	/// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_function(&self, namespace: &str, name: &str, argument_types: &Vec<String>) -> Option<Symbol<'a>>;

	/// Lookup a structure (class, enum) by its name and namespace.
	/// Duplicate classes in the same namespace are not allowed, so the result will be unique
	/// If no result is found in the direct namespace, the parent namespaces will be searched
	/// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_structure(&self, namespace: &str, name: &str) -> Option<(Symbol<'a>)>;

	/// Adds a symbol to this table and allocates it's location
	/// Returns true if the symbol could be added; false otherwise
	/// Duplicate symbols are not allowed
	/// TODO: support overloaded methods
	fn add(&self, class: SymbolClass<'a>, namespace: &'a str, name: &'a str) -> bool;
}

pub enum SymbolLocation<'a>
{
	/// Indicates that a register has been reserved for a specific use (e.g. by a variable)
	/// tuple: (name)
	Register(&'a str),

	/// Indicates a location in memory (e.g. for static variables)
	/// tuple: (address)
	Memory(MemoryAddress<'a>),

	/// Indicates an offset location from a structured entity (e.g. a member variable of a class)
	/// tuple: offset
	InstancedMemory(u16),

	/// Indicates that the symbol should not be accessed, as it represents a structured entity
	Structured
}

pub enum SymbolClass<'a>
{
	/// (variable_type)
	Variable(&'a str),

	/// Function signature (return_type, argument_types) //TODO: support exceptions
	Function(&'a str, &'a Vec<&'a str>),

	/// Includes class, enum, and interface
	/// (subtype)
	Structure(&'a str),
}

pub struct Symbol<'a>
{
	/// Namespace of this symbol, without the final "." or the name of this symbol
	pub namespace: &'a str,

	/// Identifier for the symbol (e.g. name of variable, function, class, etc. without it's namespace)
	pub name: &'a str,

	/// What this symbol represents (class, enum, variable, function, etc)
	pub symbol_class: SymbolClass<'a>,

	/// Memory location of this symbol. Methods will always map to a SymbolLocation::Memory label with a 0 offset
	pub location: SymbolLocation<'a>,
}

pub struct MemoryAddress<'a>
{
	/// Label marking the base address where the symbol is stored
	pub label_name: &'a str,

	/// Offset from the base address to access the symbol. Methods will always have an offset of 0
	pub offset: u16,
}
<|endoftext|>