<commit_before>use buffer::Mark;
use textobject::{ Anchor, TextObject, Offset, Kind };
use overlay::OverlayType;
use modes::ModeType;
use keymap::{CommandInfo, KeyBinding};

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Clone)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    SetMode(ModeType),
    ShowMessage(String),
    SwitchToLastBuffer,
    None,
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from `log::Change` in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Clone)]
pub enum Operation {
    Insert(char), // insert text
    DeleteObject,         // delete some object
    DeleteFromMark(Mark), // delete from some mark to an object

    Undo,         // rewind buffer transaction log
    Redo,         // replay buffer transaction log
}

#[derive(Clone)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Clone)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: Option<TextObject>, // where to do it
}

impl Command {
    /// Display a message
    pub fn show_message(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to show_message");
        let message = args.str_args.expect("no message provided");
        Command {
            action: Action::Instruction(Instruction::ShowMessage(message)),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create an ExitEditor command
    pub fn exit_editor(_args: Option<BuilderArgs>) -> Command {
        Command {
            action: Action::Instruction(Instruction::ExitEditor),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create a SaveBuffer command
    pub fn save_buffer(_args: Option<BuilderArgs>) -> Command {
        Command {
            action: Action::Instruction(Instruction::SaveBuffer),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create SetMode command
    pub fn set_mode(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to set_mode");
        let mode_type = args.mode_args.expect("no mode type given");
        Command {
            action: Action::Instruction(Instruction::SetMode(mode_type)),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to change the active overlay
    pub fn set_overlay(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to set_overlay");
        let overlay = args.overlay_args.expect("no overlay type given");
        Command {
            action: Action::Instruction(Instruction::SetOverlay(overlay)),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create an Insert command
    pub fn insert_char(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to insert_char");
        let c = args.char_args.expect("no char given");
        Command {
            number: 1,
            action: Action::Operation(Operation::Insert(c)),
            object: None,
        }
    }

    /// Shortcut to create an Insert command
    // FIXME: shouldn't need this method
    pub fn insert_tab(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 4,
            action: Action::Operation(Operation::Insert(' ')),
            object: None,
        }
    }

    /// Shortcut to create Undo command
    pub fn undo(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Operation(Operation::Undo),
            object: None
        }
    }

    /// Shortcut to create Redo command
    pub fn redo(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Operation(Operation::Redo),
            object: None
        }
    }

    pub fn move_cursor(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no args given to movement");
        let kind = args.kind.expect("no kind provided");
        let offset = args.offset.expect("no offset provided");
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: kind,
                offset: offset
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_forward_char(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_backward_char(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Char,
                offset: Offset::Backward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_forward_line(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::Same),
                offset: Offset::Forward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_backward_line(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::Same),
                offset: Offset::Backward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn set_overlay_command_prompt(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 0,
            action: Action::Instruction(Instruction::SetOverlay(OverlayType::CommandPrompt)),
            object: None,
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn set_mode_insert(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 0,
            action: Action::Instruction(Instruction::SetMode(ModeType::Insert)),
            object: None,
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_forward_word_start(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Word(Anchor::Start),
                offset: Offset::Forward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_backward_word_start(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Word(Anchor::Start),
                offset: Offset::Backward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_line_start(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::Start),
                offset: Offset::Backward(0, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_line_end(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::End),
                offset: Offset::Forward(0, Mark::Cursor(0)),
            })
        }
    }

    pub fn noop(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 0,
            action: Action::Instruction(Instruction::None),
            object: None,
        }
    }
}

#[derive(Clone)]
pub struct BuilderArgs {
    pub char_args: Option<char>,
    pub number: Option<i32>,
    pub str_args: Option<String>,
    pub mode_args: Option<ModeType>,
    pub overlay_args: Option<OverlayType>,
    pub kind: Option<Kind>,
    pub offset: Option<Offset>,
}

impl BuilderArgs {
    pub fn new() -> BuilderArgs {
        BuilderArgs {
            char_args: None,
            number: None,
            str_args: None,
            mode_args: None,
            overlay_args: None,
            kind: None,
            offset: None,
        }
    }

    pub fn with_char_arg(mut self, c: char) -> BuilderArgs {
        self.char_args = Some(c);

        self
    }

    pub fn with_str(mut self, s: String) -> BuilderArgs {
        self.str_args = Some(s);

        self
    }

    pub fn with_number(mut self, n: i32) -> BuilderArgs {
        self.number = Some(n);

        self
    }

    pub fn with_kind(mut self, kind: Kind) -> BuilderArgs {
        self.kind = Some(kind);

        self
    }

    pub fn with_offset(mut self, offset: Offset) -> BuilderArgs {
        self.offset = Some(offset);

        self
    }

    pub fn with_mode(mut self, mode: ModeType) -> BuilderArgs {
        self.mode_args = Some(mode);

        self
    }
}

pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(CommandInfo),  // command is finished
}
<commit_msg>Fix repeating movement commands<commit_after>use buffer::Mark;
use textobject::{ Anchor, TextObject, Offset, Kind };
use overlay::OverlayType;
use modes::ModeType;
use keymap::{CommandInfo, KeyBinding};

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Clone)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    SetMode(ModeType),
    ShowMessage(String),
    SwitchToLastBuffer,
    None,
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from `log::Change` in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Clone)]
pub enum Operation {
    Insert(char), // insert text
    DeleteObject,         // delete some object
    DeleteFromMark(Mark), // delete from some mark to an object

    Undo,         // rewind buffer transaction log
    Redo,         // replay buffer transaction log
}

#[derive(Clone)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Clone)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: Option<TextObject>, // where to do it
}

impl Command {
    /// Display a message
    pub fn show_message(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to show_message");
        let message = args.str_args.expect("no message provided");
        Command {
            action: Action::Instruction(Instruction::ShowMessage(message)),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create an ExitEditor command
    pub fn exit_editor(_args: Option<BuilderArgs>) -> Command {
        Command {
            action: Action::Instruction(Instruction::ExitEditor),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create a SaveBuffer command
    pub fn save_buffer(_args: Option<BuilderArgs>) -> Command {
        Command {
            action: Action::Instruction(Instruction::SaveBuffer),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create SetMode command
    pub fn set_mode(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to set_mode");
        let mode_type = args.mode_args.expect("no mode type given");
        Command {
            action: Action::Instruction(Instruction::SetMode(mode_type)),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to change the active overlay
    pub fn set_overlay(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to set_overlay");
        let overlay = args.overlay_args.expect("no overlay type given");
        Command {
            action: Action::Instruction(Instruction::SetOverlay(overlay)),
            number: 0,
            object: None,
        }
    }

    /// Shortcut to create an Insert command
    pub fn insert_char(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no arguments given to insert_char");
        let c = args.char_args.expect("no char given");
        Command {
            number: 1,
            action: Action::Operation(Operation::Insert(c)),
            object: None,
        }
    }

    /// Shortcut to create an Insert command
    // FIXME: shouldn't need this method
    pub fn insert_tab(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 4,
            action: Action::Operation(Operation::Insert(' ')),
            object: None,
        }
    }

    /// Shortcut to create Undo command
    pub fn undo(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Operation(Operation::Undo),
            object: None
        }
    }

    /// Shortcut to create Redo command
    pub fn redo(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Operation(Operation::Redo),
            object: None
        }
    }

    pub fn move_cursor(args: Option<BuilderArgs>) -> Command {
        let args = args.expect("no args given to movement");
        let kind = args.kind.expect("no kind provided");
        let offset = args.offset.expect("no offset provided");
        let repeat = args.number.unwrap_or(1);
        Command {
            number: repeat,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: kind,
                offset: offset
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_forward_char(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_backward_char(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Char,
                offset: Offset::Backward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_forward_line(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::Same),
                offset: Offset::Forward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_backward_line(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::Same),
                offset: Offset::Backward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn set_overlay_command_prompt(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 0,
            action: Action::Instruction(Instruction::SetOverlay(OverlayType::CommandPrompt)),
            object: None,
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn set_mode_insert(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 0,
            action: Action::Instruction(Instruction::SetMode(ModeType::Insert)),
            object: None,
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_forward_word_start(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Word(Anchor::Start),
                offset: Offset::Forward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_backward_word_start(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Word(Anchor::Start),
                offset: Offset::Backward(1, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_line_start(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::Start),
                offset: Offset::Backward(0, Mark::Cursor(0)),
            })
        }
    }

    #[deprecated(note="Remove when arguments can be added to keybindings")]
    pub fn move_cursor_line_end(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 1,
            action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
            object: Some(TextObject {
                kind: Kind::Line(Anchor::End),
                offset: Offset::Forward(0, Mark::Cursor(0)),
            })
        }
    }

    pub fn noop(_args: Option<BuilderArgs>) -> Command {
        Command {
            number: 0,
            action: Action::Instruction(Instruction::None),
            object: None,
        }
    }
}

#[derive(Clone)]
pub struct BuilderArgs {
    pub char_args: Option<char>,
    pub number: Option<i32>,
    pub str_args: Option<String>,
    pub mode_args: Option<ModeType>,
    pub overlay_args: Option<OverlayType>,
    pub kind: Option<Kind>,
    pub offset: Option<Offset>,
}

impl BuilderArgs {
    pub fn new() -> BuilderArgs {
        BuilderArgs {
            char_args: None,
            number: None,
            str_args: None,
            mode_args: None,
            overlay_args: None,
            kind: None,
            offset: None,
        }
    }

    pub fn with_char_arg(mut self, c: char) -> BuilderArgs {
        self.char_args = Some(c);

        self
    }

    pub fn with_str(mut self, s: String) -> BuilderArgs {
        self.str_args = Some(s);

        self
    }

    pub fn with_number(mut self, n: i32) -> BuilderArgs {
        self.number = Some(n);

        self
    }

    pub fn with_kind(mut self, kind: Kind) -> BuilderArgs {
        self.kind = Some(kind);

        self
    }

    pub fn with_offset(mut self, offset: Offset) -> BuilderArgs {
        self.offset = Some(offset);

        self
    }

    pub fn with_mode(mut self, mode: ModeType) -> BuilderArgs {
        self.mode_args = Some(mode);

        self
    }
}

pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(CommandInfo),  // command is finished
}
<|endoftext|>


<commit_before>//! Demonstrates the use of service accounts and the Google Cloud Pubsub API.
//!
//! Run this binary as .../service_account pub 'your message' in order to publish messages,
//! and as .../service_account sub in order to subscribe to those messages. This will look like the
//! following:
//!
//! ```
//! $ target/debug/service_account pub 'Hello oh wonderful world' &
//! $ target/debug/service_account sub
//! Published message #95491011619126
//! message <95491011619126> 'Hello oh wonderful world' at 2016-09-21T20:04:47.040Z
//! Published message #95491011620879
//! message <95491011620879> 'Hello oh wonderful world' at 2016-09-21T20:04:49.086Z
//! Published message #95491011622600
//! message <95491011622600> 'Hello oh wonderful world' at 2016-09-21T20:04:51.132Z
//! Published message #95491011624393
//! message <95491011624393> 'Hello oh wonderful world' at 2016-09-21T20:04:53.187Z
//! Published message #95491011626206
//! message <95491011626206> 'Hello oh wonderful world' at 2016-09-21T20:04:55.233Z
//!
//! Copyright (c) 2016 Google, Inc. (Lewin Bormann <lbo@spheniscida.de>)
//!
extern crate base64;
extern crate yup_oauth2 as oauth;
extern crate google_pubsub1 as pubsub;
extern crate hyper;
extern crate hyper_rustls;

use std::env;
use std::time;
use std::thread;

use hyper::net::HttpsConnector;
use pubsub::{Topic, Subscription};

// The prefixes are important!
const SUBSCRIPTION_NAME: &'static str = "projects/sanguine-rhythm-105020/subscriptions/rust_authd_sub_1";
const TOPIC_NAME: &'static str = "projects/sanguine-rhythm-105020/topics/topic-01";

type PubsubMethods<'a> = pubsub::ProjectMethods<'a,
                                                hyper::Client,
                                                oauth::ServiceAccountAccess<hyper::Client>>;

// Verifies that the topic TOPIC_NAME exists, or creates it.
fn check_or_create_topic(methods: &PubsubMethods) -> Topic {
    let result = methods.topics_get(TOPIC_NAME).doit();

    if result.is_err() {
        println!("Assuming topic doesn't exist; creating topic");
        let topic = pubsub::Topic { name: Some(TOPIC_NAME.to_string()) };
        let result = methods.topics_create(topic, TOPIC_NAME).doit().unwrap();
        result.1
    } else {
        result.unwrap().1
    }
}

fn check_or_create_subscription(methods: &PubsubMethods) -> Subscription {
    // check if subscription exists
    let result = methods.subscriptions_get(SUBSCRIPTION_NAME).doit();

    if result.is_err() {
        println!("Assuming subscription doesn't exist; creating subscription");
        let sub = pubsub::Subscription {
            topic: Some(TOPIC_NAME.to_string()),
            ack_deadline_seconds: Some(30),
            push_config: None,
            name: Some(SUBSCRIPTION_NAME.to_string()),
        };
        let (_resp, sub) = methods.subscriptions_create(sub, SUBSCRIPTION_NAME).doit().unwrap();

        sub
    } else {
        result.unwrap().1
    }
}

fn ack_message(methods: &PubsubMethods, id: String) {
    let request = pubsub::AcknowledgeRequest { ack_ids: Some(vec![id]) };
    let result = methods.subscriptions_acknowledge(request, SUBSCRIPTION_NAME).doit();

    match result {
        Err(e) => {
            println!("Ack error: {:?}", e);
        }
        Ok(_) => (),
    }
}

// Wait for new messages. Print and ack any new messages.
fn subscribe_wait(methods: &PubsubMethods) {
    check_or_create_subscription(&methods);

    let request = pubsub::PullRequest {
        return_immediately: Some(false),
        max_messages: Some(1),
    };

    loop {
        let result = methods.subscriptions_pull(request.clone(), SUBSCRIPTION_NAME).doit();

        match result {
            Err(e) => {
                println!("Pull error: {}", e);
            }
            Ok((_response, pullresponse)) => {
                for msg in pullresponse.received_messages.unwrap_or(Vec::new()) {
                    let ack_id = msg.ack_id.unwrap_or(String::new());
                    let message = msg.message.unwrap_or(Default::default());
                    println!("message <{}> '{}' at {}",
                             message.message_id.unwrap_or(String::new()),
                             String::from_utf8(base64::decode(&message.data
                                         .unwrap_or(String::new()))
                                     .unwrap())
                                 .unwrap(),
                             message.publish_time.unwrap_or(String::new()));

                    if ack_id != "" {
                        ack_message(methods, ack_id);
                    }
                }
            }
        }
    }
}

// Publish some message every 2 seconds.
fn publish_stuff(methods: &PubsubMethods, message: &str) {
    check_or_create_topic(&methods);

    let message = pubsub::PubsubMessage {
        // Base64 encoded!
        data: Some(base64::encode(message.as_bytes())),
        ..Default::default()
    };
    let request = pubsub::PublishRequest { messages: Some(vec![message]) };

    loop {
        let result = methods.topics_publish(request.clone(), TOPIC_NAME).doit();

        match result {
            Err(e) => {
                println!("Publish error: {}", e);
            }
            Ok((_response, pubresponse)) => {
                for msg in pubresponse.message_ids.unwrap_or(Vec::new()) {
                    println!("Published message #{}", msg);
                }
            }
        }

        thread::sleep(time::Duration::new(2, 0));
    }
}

// If called as '.../service_account pub', act as publisher; if called as '.../service_account
// sub', act as subscriber.
fn main() {
    let client_secret = oauth::service_account_key_from_file(&"pubsub-auth.json".to_string())
        .unwrap();
    let client = hyper::Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new()));
    let mut access = oauth::ServiceAccountAccess::new(client_secret, client);

    use oauth::GetToken;
    println!("{:?}",
             access.token(&vec!["https://www.googleapis.com/auth/pubsub"]).unwrap());

    let client = hyper::Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new()));
    let hub = pubsub::Pubsub::new(client, access);
    let methods = hub.projects();

    let mode = env::args().nth(1).unwrap_or(String::new());

    if mode == "pub" {
        let message = env::args().nth(2).unwrap_or("Hello World!".to_string());
        publish_stuff(&methods, &message);
    } else if mode == "sub" {
        subscribe_wait(&methods);
    } else {
        println!("Please use either of 'pub' or 'sub' as first argument to this binary!");
    }
}
<commit_msg>chore(api): Update use of pubsub client API.<commit_after>//! Demonstrates the use of service accounts and the Google Cloud Pubsub API.
//!
//! Run this binary as .../service_account pub 'your message' in order to publish messages,
//! and as .../service_account sub in order to subscribe to those messages. This will look like the
//! following:
//!
//! ```
//! $ target/debug/service_account pub 'Hello oh wonderful world' &
//! $ target/debug/service_account sub
//! Published message #95491011619126
//! message <95491011619126> 'Hello oh wonderful world' at 2016-09-21T20:04:47.040Z
//! Published message #95491011620879
//! message <95491011620879> 'Hello oh wonderful world' at 2016-09-21T20:04:49.086Z
//! Published message #95491011622600
//! message <95491011622600> 'Hello oh wonderful world' at 2016-09-21T20:04:51.132Z
//! Published message #95491011624393
//! message <95491011624393> 'Hello oh wonderful world' at 2016-09-21T20:04:53.187Z
//! Published message #95491011626206
//! message <95491011626206> 'Hello oh wonderful world' at 2016-09-21T20:04:55.233Z
//! ```
//!
//! (note that this program won't work as-is, because the credentials are invalid; it will work if
//! you supply a valid client secret)
//!
//! Copyright (c) 2016 Google, Inc. (Lewin Bormann <lbo@spheniscida.de>)
//!
extern crate base64;
extern crate yup_oauth2 as oauth;
extern crate google_pubsub1 as pubsub;
extern crate hyper;
extern crate hyper_rustls;

use std::env;
use std::time;
use std::thread;

use hyper::net::HttpsConnector;
use pubsub::{Topic, Subscription};

// The prefixes are important!
const SUBSCRIPTION_NAME: &'static str = "projects/sanguine-rhythm-105020/subscriptions/rust_authd_sub_1";
const TOPIC_NAME: &'static str = "projects/sanguine-rhythm-105020/topics/topic-01";

type PubsubMethods<'a> = pubsub::ProjectMethods<'a,
                                                hyper::Client,
                                                oauth::ServiceAccountAccess<hyper::Client>>;

// Verifies that the topic TOPIC_NAME exists, or creates it.
fn check_or_create_topic(methods: &PubsubMethods) -> Topic {
    let result = methods.topics_get(TOPIC_NAME).doit();

    if result.is_err() {
        println!("Assuming topic doesn't exist; creating topic");
        let topic = pubsub::Topic { name: Some(TOPIC_NAME.to_string()) };
        let result = methods.topics_create(topic, TOPIC_NAME).doit().unwrap();
        result.1
    } else {
        result.unwrap().1
    }
}

fn check_or_create_subscription(methods: &PubsubMethods) -> Subscription {
    // check if subscription exists
    let result = methods.subscriptions_get(SUBSCRIPTION_NAME).doit();

    if result.is_err() {
        println!("Assuming subscription doesn't exist; creating subscription");
        let sub = pubsub::Subscription {
            topic: Some(TOPIC_NAME.to_string()),
            ack_deadline_seconds: Some(30),
            push_config: None,
            message_retention_duration: None,
            retain_acked_messages: None,
            name: Some(SUBSCRIPTION_NAME.to_string()),
        };
        let (_resp, sub) = methods.subscriptions_create(sub, SUBSCRIPTION_NAME).doit().unwrap();

        sub
    } else {
        result.unwrap().1
    }
}

fn ack_message(methods: &PubsubMethods, id: String) {
    let request = pubsub::AcknowledgeRequest { ack_ids: Some(vec![id]) };
    let result = methods.subscriptions_acknowledge(request, SUBSCRIPTION_NAME).doit();

    match result {
        Err(e) => {
            println!("Ack error: {:?}", e);
        }
        Ok(_) => (),
    }
}

// Wait for new messages. Print and ack any new messages.
fn subscribe_wait(methods: &PubsubMethods) {
    check_or_create_subscription(&methods);

    let request = pubsub::PullRequest {
        return_immediately: Some(false),
        max_messages: Some(1),
    };

    loop {
        let result = methods.subscriptions_pull(request.clone(), SUBSCRIPTION_NAME).doit();

        match result {
            Err(e) => {
                println!("Pull error: {}", e);
            }
            Ok((_response, pullresponse)) => {
                for msg in pullresponse.received_messages.unwrap_or(Vec::new()) {
                    let ack_id = msg.ack_id.unwrap_or(String::new());
                    let message = msg.message.unwrap_or(Default::default());
                    println!("message <{}> '{}' at {}",
                             message.message_id.unwrap_or(String::new()),
                             String::from_utf8(base64::decode(&message.data
                                         .unwrap_or(String::new()))
                                     .unwrap())
                                 .unwrap(),
                             message.publish_time.unwrap_or(String::new()));

                    if ack_id != "" {
                        ack_message(methods, ack_id);
                    }
                }
            }
        }
    }
}

// Publish some message every 2 seconds.
fn publish_stuff(methods: &PubsubMethods, message: &str) {
    check_or_create_topic(&methods);

    let message = pubsub::PubsubMessage {
        // Base64 encoded!
        data: Some(base64::encode(message.as_bytes())),
        ..Default::default()
    };
    let request = pubsub::PublishRequest { messages: Some(vec![message]) };

    loop {
        let result = methods.topics_publish(request.clone(), TOPIC_NAME).doit();

        match result {
            Err(e) => {
                println!("Publish error: {}", e);
            }
            Ok((_response, pubresponse)) => {
                for msg in pubresponse.message_ids.unwrap_or(Vec::new()) {
                    println!("Published message #{}", msg);
                }
            }
        }

        thread::sleep(time::Duration::new(2, 0));
    }
}

// If called as '.../service_account pub', act as publisher; if called as '.../service_account
// sub', act as subscriber.
fn main() {
    let client_secret = oauth::service_account_key_from_file(&"pubsub-auth.json".to_string())
        .unwrap();
    let client = hyper::Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new()));
    let mut access = oauth::ServiceAccountAccess::new(client_secret, client);

    use oauth::GetToken;
    println!("{:?}",
             access.token(&vec!["https://www.googleapis.com/auth/pubsub"]).unwrap());

    let client = hyper::Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new()));
    let hub = pubsub::Pubsub::new(client, access);
    let methods = hub.projects();

    let mode = env::args().nth(1).unwrap_or(String::new());

    if mode == "pub" {
        let message = env::args().nth(2).unwrap_or("Hello World!".to_string());
        publish_stuff(&methods, &message);
    } else if mode == "sub" {
        subscribe_wait(&methods);
    } else {
        println!("Please use either of 'pub' or 'sub' as first argument to this binary!");
    }
}
<|endoftext|>


<commit_before>use crate::schema::*;
use diesel::prelude::*;

#[test]
fn selecting_basic_data() {
    let connection = &mut connection();
    connection
        .execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let expected_data = vec![
        ("Sean".to_string(), None::<String>),
        ("Tess".to_string(), None::<String>),
    ];

    let user_alias = alias!(users as user_alias);

    let actual_data = user_alias
        .select((
            user_alias.field(users::name),
            user_alias.field(users::hair_color),
        ))
        .load(connection)
        .unwrap();

    assert_eq!(expected_data, actual_data);
}

#[test]
fn select_multiple_from_join() {
    let connection = &mut connection_with_sean_and_tess_in_users_table();

    connection
        .execute(
            "INSERT INTO posts (id, user_id, title) VALUES
        (1, 1, 'Hello'),
        (2, 2, 'World')
    ",
        )
        .unwrap();

    alias!(users as user_alias: UserAlias);
    let post_alias = alias!(posts as post_alias);

    // Having two different aliases in one query works
    let query = post_alias
        .select(post_alias.fields((posts::id, posts::user_id, posts::title, posts::body)))
        .filter(
            post_alias.field(posts::user_id).eq_any(
                user_alias.select(user_alias.field(users::id)).filter(
                    user_alias
                        .field(users::id)
                        .eq_any(users::table.select(users::id)),
                ),
            ),
        );

    // using a subquery with an alias seems to work
    post_alias
        .select(
            posts::table
                .select(posts::id)
                .filter(post_alias.field(posts::id).eq(posts::id))
                .single_value(),
        )
        .load::<Option<i32>>(connection)
        .unwrap();

    query
        .load::<(i32, i32, String, Option<String>)>(connection)
        .unwrap();

    post_alias
        .left_join(users::table)
        .inner_join(
            // allowing a plain join here
            // would require to write an
            // impl JoinTo<Alias<T1, F1>> for Alias<T2, F2> where T2: JoinTo<T2>
            // but I found no simple way to modify the `From clause there`
            user_alias.on(post_alias
                .field(posts::user_id)
                .eq(user_alias.field(users::id))),
        )
        .select((
            post_alias.field(posts::id),
            users::id.nullable(),
            user_alias.field(users::id),
        ))
        .load::<(i32, Option<i32>, i32)>(connection)
        .unwrap();

    // having the alias on the right side seems to work
    // joining the table with an alias twice, also works
    posts::table
        .inner_join(user_alias)
        .inner_join(users::table)
        .select((user_alias.field(users::name), users::name))
        .load::<(String, String)>(connection)
        .unwrap();

    // Joining alias to alias works
    post_alias
        .inner_join(user_alias)
        .select((user_alias.field(users::name), post_alias.field(posts::id)))
        .load::<(String, i32)>(connection)
        .unwrap();

    // we could also define and use mutiple aliases for the same table.
    // If you want to use them in the same query it's required to define them
    // in the same macro call
    let (user1_alias, user2_alias, _post_alias) =
        alias!(users as user1, users as user2, posts as post1,);

    posts::table
        .inner_join(user1_alias)
        .inner_join(user2_alias)
        .select(posts::id)
        .load::<i32>(connection)
        .unwrap();

    // its also possible to do a self join, multiple times
    // (that should work as long as all aliases are declared in the same alias! call)
    users::table
        .inner_join(user1_alias.on(users::id.eq(user1_alias.field(users::id))))
        .inner_join(
            user2_alias.on(user2_alias
                .field(users::id)
                .eq(user1_alias.field(users::id))),
        )
        .select((
            users::id,
            user1_alias.field(users::id),
            user2_alias.field(users::id),
        ))
        .load::<(i32, i32, i32)>(connection)
        .unwrap();
}

#[test]
fn find_and_first() {
    let connection = &mut connection_with_sean_and_tess_in_users_table();
    let alias = alias!(users as users_alias);
    assert_eq!(
        alias
            .find(1)
            .select(alias.field(users::name))
            .first::<String>(connection),
        Ok("Sean".into()),
    )
}
<commit_msg>Review tests<commit_after>use crate::schema::*;
use diesel::prelude::*;

#[test]
fn selecting_basic_data() {
    let connection = &mut connection();
    connection
        .execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let expected_data = vec![
        ("Sean".to_string(), None::<String>),
        ("Tess".to_string(), None::<String>),
    ];

    let user_alias = alias!(users as user_alias);

    let actual_data = user_alias
        .select((
            user_alias.field(users::name),
            user_alias.field(users::hair_color),
        ))
        .load(connection)
        .unwrap();

    assert_eq!(expected_data, actual_data);
}

#[test]
fn select_multiple_from_join() {
    let connection = &mut connection_with_sean_and_tess_in_users_table();

    connection
        .execute(
            "INSERT INTO posts (id, user_id, title) VALUES
        (1, 1, 'Hello'),
        (2, 2, 'World')
    ",
        )
        .unwrap();

    alias!(users as user_alias: UserAlias);
    let post_alias = alias!(posts as post_alias);

    // Having two different aliases in one query works
    post_alias
        .select(post_alias.fields((posts::id, posts::user_id, posts::title, posts::body)))
        .filter(
            post_alias.field(posts::user_id).eq_any(
                user_alias.select(user_alias.field(users::id)).filter(
                    user_alias
                        .field(users::id)
                        .eq_any(users::table.select(users::id)),
                ),
            ),
        )
        .load::<(i32, i32, String, Option<String>)>(connection)
        .unwrap();

    // using a subquery with an alias seems to work
    post_alias
        .select(
            posts::table
                .select(posts::id)
                .filter(post_alias.field(posts::id).eq(posts::id))
                .single_value(),
        )
        .load::<Option<i32>>(connection)
        .unwrap();

    // Joining with explicit on clause works
    post_alias
        .left_join(users::table)
        .inner_join(
            user_alias.on(post_alias
                .field(posts::user_id)
                .eq(user_alias.field(users::id))),
        )
        .select((
            post_alias.field(posts::id),
            users::id.nullable(),
            user_alias.field(users::id),
        ))
        .load::<(i32, Option<i32>, i32)>(connection)
        .unwrap();

    // having the alias on the right side seems to work
    // joining the table with an alias twice, also works
    posts::table
        .inner_join(user_alias)
        .inner_join(users::table)
        .select((user_alias.field(users::name), users::name))
        .load::<(String, String)>(connection)
        .unwrap();

    // Joining alias to alias works
    post_alias
        .inner_join(user_alias)
        .select((user_alias.field(users::name), post_alias.field(posts::id)))
        .load::<(String, i32)>(connection)
        .unwrap();

    // using mutiple aliases for the same table works if they are declared in the same alias call
    let (user1_alias, user2_alias, _post_alias) =
        alias!(users as user1, users as user2, posts as post1,);

    posts::table
        .inner_join(user1_alias)
        .inner_join(user2_alias)
        .select(posts::id)
        .load::<i32>(connection)
        .unwrap();

    // its also possible to do a self join, multiple times
    // (that should work as long as all aliases are declared in the same alias! call)
    users::table
        .inner_join(user1_alias.on(users::id.eq(user1_alias.field(users::id))))
        .inner_join(
            user2_alias.on(user2_alias
                .field(users::id)
                .eq(user1_alias.field(users::id))),
        )
        .select((
            users::id,
            user1_alias.field(users::id),
            user2_alias.field(users::id),
        ))
        .load::<(i32, i32, i32)>(connection)
        .unwrap();
}

#[test]
fn find_and_first() {
    let connection = &mut connection_with_sean_and_tess_in_users_table();
    let alias = alias!(users as users_alias);
    assert_eq!(
        alias
            .find(1)
            .select(alias.field(users::name))
            .first::<String>(connection),
        Ok("Sean".into()),
    )
}
<|endoftext|>


<commit_before>use lexer::Token::{Name, Int as IntValue, Float as FloatValue, String as StringValue};

/// Document : Definition+
pub struct Document {
  pub definitions: Vec<Definition>
}

/// Definition :
///   - OperationDefinition
///   - FragmentDefinition
pub enum Definition {
  Operation(OperationDefinition),
  Fragment(FragmentDefinition)
}

/// OperationDefinition :
///   - SelectionSet
///   - OperationType Name? VariableDefinitions? Directives? SelectionSet
pub struct OperationDefinition {
  pub operation_type: OperationType,
  pub name: Option<Name>,
  pub variable_definitions: Option<VariableDefinitions>,
  pub directives: Option<Directives>,
  pub selection_set: SelectionSet
}

/// OperationType : one of query mutation
pub enum OperationType {
  Query,
  Mutation
}

/// SelectionSet : { Selection+ }
pub type SelectionSet = Vec<Selection>;

/// Selection :
///   - Field
///   - FragmentSpread
///   - InlineFragment
pub enum Selection {
  Field(Field),
  FragmentSpread(FragmentSpread),
  InlineFragment(InlineFragment)
}

/// Field : Alias? Name Arguments? Directives? SelectionSet?
pub struct Field {
  pub alias: Option<Alias>,
  pub name: Name,
  pub arguments: Option<Arguments>,
  pub directives: Option<Directives>,
  pub selection_set: Option<SelectionSet>
}

/// Alias : Name :
pub type Alias = Name;

/// Arguments : ( Argument+ )
pub type Arguments = Vec<Argument>;

/// Argument : Name : Value
pub struct Argument {
  pub name: Name,
  pub value: Value
}

/// FragmentSpread : ... FragmentName Directives?
pub struct FragmentSpread {
  pub fragment_name: Name,
  pub directives: Option<Directives>
}

/// InlineFragment : ... TypeCondition? Directives? SelectionSet
pub struct InlineFragment {
  pub type_condition: Option<TypeCondition>,
  pub directives: Option<Directives>,
  pub selection_set: SelectionSet
}

/// FragmentDefinition : fragment FragmentName TypeCondition Directives? SelectionSet
pub struct FragmentDefinition {
  pub fragment_name: Name,
  pub type_condition: TypeCondition,
  pub directives: Option<Directives>,
  pub selection_set: SelectionSet
}

/// FragmentName : Name but not `on`
pub type FragmentName = Name;

/// TypeCondition : on NamedType
pub type TypeCondition = NamedType;

/// Value[Const] :
///   - [~Const] Variable
///   - IntValue
///   - FloatValue
///   - StringValue
///   - BooleanValue
///   - EnumValue
///   - ListValue[?Const]
///   - ObjectValue[?Const]
pub enum Value {
  Variable(Variable),
  Int(IntValue),
  Float(FloatValue),
  String(StringValue),
  Boolean(BooleanValue),
  Enum(EnumValue),
  List(ListValue),
  Object(ObjectValue)
}

/// BooleanValue : one of `true` `false`
pub enum BooleanValue {
  True,
  False
}

/// EnumValue : Name but not `true`, `false` or `null`
pub struct EnumValue {
  pub name: Name
}

/// ListValue[Const] :
///   - [ ]
///   - [ Value[?Const]+ ]
pub type ListValue = Vec<Value>;

/// ObjectValue[Const] :
///   - { }
///   - { ObjectField[?Const]+ }
pub type ObjectValue = Vec<ObjectField>;

/// ObjectField[Const] : Name : Value[?Const]
pub struct ObjectField {
  pub name: Name,
  pub value: Value
}

/// VariableDefinitions : ( VariableDefinition+ )
pub type VariableDefinitions = Vec<VariableDefinition>;

/// VariableDefinition : Variable : Type DefaultValue?
pub struct VariableDefinition {
  pub variable: Variable,
  pub type_: Type,
  pub default_value: Option<DefaultValue>
}

/// Variable : $ Name
pub type Variable = Name;

/// DefaultValue : = Value[Const]
pub type DefaultValue = Value;

/// Type :
///   - NamedType
///   - ListType
///   - NonNullType
pub enum Type {
  Named(NamedType),
  List(ListType),
  NonNull(NonNullType)
}

/// NamedType : Name
pub type NamedType = Name;

/// ListType : [ Type ]
pub type ListType = Name;

/// NonNullType :
///   - NamedType !
///   - ListType !
pub enum NonNullType {
  Named(NamedType),
  List(ListType)
}

/// Directives : Directive+
pub type Directives = Vec<Directive>;

/// Directive : @ Name Arguments?
pub struct Directive {
  pub name: Name,
  pub arguments: Option<Arguments>
}
<commit_msg>feat(ast): implement node where appropriate<commit_after>//! AST node definitions which will be parsed into. Based off of the
//! `graphql-js` [`ast.js`][1] definitions.
//!
//! [1]: https://github.com/graphql/graphql-js/blob/dfe676c3011efe9560b9fa0fcbd2b7bd87476d02/src/language/ast.js

/// All AST node types implement this trait.
trait Node {}

macro_rules! impl_node_for {
  ($struct:ident) => {
    impl Node for $struct {}
  }
}

/// Name :: /[_A-Za-z][_0-9A-Za-z]*/
pub struct Name {
  pub value: String
}

impl_node_for! { Name }

/// IntValue :: IntegerPart
pub struct IntValue {
  pub value: String
}

impl_node_for! { IntValue }

/// FloatValue ::
///   - IntegerPart FractionalPart
///   - IntegerPart ExponentPart
///   - IntegerPart FractionalPart ExponentPart
pub struct FloatValue {
  pub value: String
}

impl_node_for! { FloatValue }

/// StringValue ::
///   - `""`
///   - `"` StringCharacter+ `"`
pub struct StringValue {
  pub value: String
}

impl_node_for! { StringValue }

/// Document : Definition+
pub struct Document {
  pub definitions: Vec<Definition>
}

impl_node_for! { Document }

/// Definition :
///   - OperationDefinition
///   - FragmentDefinition
pub enum Definition {
  Operation(OperationDefinition),
  Fragment(FragmentDefinition)
}

/// OperationDefinition :
///   - SelectionSet
///   - OperationType Name? VariableDefinitions? Directives? SelectionSet
pub struct OperationDefinition {
  pub operation: OperationType,
  pub name: Option<Name>,
  pub variable_definitions: Option<VariableDefinitions>,
  pub directives: Option<Directives>,
  pub selection_set: SelectionSet
}

impl_node_for! { OperationDefinition }

/// OperationType : one of query mutation
pub enum OperationType {
  Query,
  Mutation
}

/// SelectionSet : { Selection+ }
pub struct SelectionSet {
  pub selections: Vec<Selection>
}

impl_node_for! { SelectionSet }

/// Selection :
///   - Field
///   - FragmentSpread
///   - InlineFragment
pub enum Selection {
  Field(Field),
  FragmentSpread(FragmentSpread),
  InlineFragment(InlineFragment)
}

/// Field : Alias? Name Arguments? Directives? SelectionSet?
pub struct Field {
  pub alias: Option<Alias>,
  pub name: Name,
  pub arguments: Option<Arguments>,
  pub directives: Option<Directives>,
  pub selection_set: Option<SelectionSet>
}

impl_node_for! { Field }

/// Alias : Name :
pub type Alias = Name;

/// Arguments : ( Argument+ )
pub type Arguments = Vec<Argument>;

/// Argument : Name : Value
pub struct Argument {
  pub name: Name,
  pub value: Value
}

impl_node_for! { Argument }

/// FragmentSpread : ... FragmentName Directives?
pub struct FragmentSpread {
  pub name: Name,
  pub directives: Option<Directives>
}

impl_node_for! { FragmentSpread }

/// InlineFragment : ... TypeCondition? Directives? SelectionSet
pub struct InlineFragment {
  pub type_condition: Option<TypeCondition>,
  pub directives: Option<Directives>,
  pub selection_set: SelectionSet
}

impl_node_for! { InlineFragment }

/// FragmentDefinition : fragment FragmentName TypeCondition Directives? SelectionSet
pub struct FragmentDefinition {
  pub name: Name,
  pub type_condition: TypeCondition,
  pub directives: Option<Directives>,
  pub selection_set: SelectionSet
}

impl_node_for! { FragmentDefinition }

/// FragmentName : Name but not `on`
pub type FragmentName = Name;

/// TypeCondition : on NamedType
pub type TypeCondition = NamedType;

/// Value[Const] :
///   - [~Const] Variable
///   - IntValue
///   - FloatValue
///   - StringValue
///   - BooleanValue
///   - EnumValue
///   - ListValue[?Const]
///   - ObjectValue[?Const]
pub enum Value {
  Variable(Variable),
  Int(IntValue),
  Float(FloatValue),
  String(StringValue),
  Boolean(BooleanValue),
  Enum(EnumValue),
  List(ListValue),
  Object(ObjectValue)
}

/// BooleanValue : one of `true` `false`
pub enum BooleanValue {
  True,
  False
}

impl_node_for! { BooleanValue }

/// EnumValue : Name but not `true`, `false` or `null`
pub struct EnumValue {
  pub name: Name
}

impl_node_for! { EnumValue }

/// ListValue[Const] :
///   - [ ]
///   - [ Value[?Const]+ ]
pub struct ListValue {
  pub values: Vec<Value>
}

impl_node_for! { ListValue }

/// ObjectValue[Const] :
///   - { }
///   - { ObjectField[?Const]+ }
pub struct ObjectValue {
  pub fields: Vec<ObjectField>
}

impl_node_for! { ObjectValue }

/// ObjectField[Const] : Name : Value[?Const]
pub struct ObjectField {
  pub name: Name,
  pub value: Value
}

impl_node_for! { ObjectField }

/// VariableDefinitions : ( VariableDefinition+ )
pub type VariableDefinitions = Vec<VariableDefinition>;

/// VariableDefinition : Variable : Type DefaultValue?
pub struct VariableDefinition {
  pub variable: Variable,
  pub type_: Type,
  pub default_value: Option<DefaultValue>
}

impl_node_for! { VariableDefinition }

/// Variable : $ Name
pub struct Variable {
  pub name: Name
}

impl_node_for! { Variable }

/// DefaultValue : = Value[Const]
pub type DefaultValue = Value;

/// Type :
///   - NamedType
///   - ListType
///   - NonNullType
pub enum Type {
  Named(NamedType),
  List(ListType),
  NonNullNamed(NonNullNamedType),
  NonNullList(NonNullListType)
}

/// NamedType : Name
pub struct NamedType {
  pub name: Name
}

impl_node_for! { NamedType }

/// ListType : [ Type ]
pub struct ListType {
  pub type_: Type
}

impl_node_for! { ListType }

/// NonNullType :
///   - NamedType !
///   - ListType !
///
/// Are implementation deviates from the spec here. This is because
/// `NonNullType` is expected to be a [node][1], but it is also expected to be
/// a [union][2]. The best way to express this in Rust is with two types.
///
/// [1]: https://github.com/graphql/graphql-js/blob/dfe676c3011efe9560b9fa0fcbd2b7bd87476d02/src/language/ast.js#L49
/// [2]: https://github.com/graphql/graphql-js/blob/dfe676c3011efe9560b9fa0fcbd2b7bd87476d02/src/language/ast.js#L254
pub struct NonNullNamedType {
  pub type_: NamedType
}

impl_node_for! { NonNullNamedType }

/// See documentation for the `NonNullNamedType` struct.
pub struct NonNullListType {
  pub type_: ListType
}

impl_node_for! { NonNullListType }

/// Directives : Directive+
pub type Directives = Vec<Directive>;

/// Directive : @ Name Arguments?
pub struct Directive {
  pub name: Name,
  pub arguments: Option<Arguments>
}

impl_node_for! { Directive }
<|endoftext|>


<commit_before>use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;
use super::CommonState;

#[derive(Debug, Clone)]
pub struct BinaryParser {
    version: u32,
}

impl BinaryParser {
    pub fn new(version: u32) -> Self {
        BinaryParser {
            version: version,
        }
    }

    pub fn next<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<FbxEvent> {
        let node_record_header = try!(NodeRecordHeader::load(reader, &mut common.pos));
        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }
}

#[derive(Debug, Copy, Clone)]
struct NodeRecordHeader {
    end_offset: u32,
    num_properties: u32,
    property_list_len: u32,
    name_len: u8,
}

impl NodeRecordHeader {
    pub fn load<R: Read>(_reader: &mut R, pos: &mut u64) -> Result<Self> {
        Err(Error::new(*pos, ErrorKind::Unimplemented("Parser for NodeRecordHeader is not implemented yet".to_string())))
    }

    /// Check whether the header indicates there are no more children.
    pub fn is_null_record(&self) -> bool {
        self.end_offset == 0
            && self.num_properties == 0
            && self.property_list_len == 0
            && self.name_len == 0
    }
}
<commit_msg>Implement `NodeRecordHeader::load()`<commit_after>use std::io::Read;
use error::{Result, Error, ErrorKind};
use reader::FbxEvent;
use super::CommonState;

#[derive(Debug, Clone)]
pub struct BinaryParser {
    version: u32,
}

impl BinaryParser {
    pub fn new(version: u32) -> Self {
        BinaryParser {
            version: version,
        }
    }

    pub fn next<R: Read>(&mut self, reader: &mut R, common: &mut CommonState) -> Result<FbxEvent> {
        let node_record_header = try!(NodeRecordHeader::load(reader, &mut common.pos));
        Err(Error::new(common.pos, ErrorKind::Unimplemented("Parser for Binary FBX format is not implemented yet".to_string())))
    }
}

#[derive(Debug, Copy, Clone)]
struct NodeRecordHeader {
    end_offset: u32,
    num_properties: u32,
    property_list_len: u32,
    name_len: u8,
}

impl NodeRecordHeader {
    pub fn load<R: Read>(reader: &mut R, pos: &mut u64) -> Result<Self> {
        let end_offset = try_read_le_u32!(*pos, reader);
        let num_properties = try_read_le_u32!(*pos, reader);
        let property_list_len = try_read_le_u32!(*pos, reader);
        let name_len = try_read_le_u8!(*pos, reader);
        Ok(NodeRecordHeader {
            end_offset: end_offset,
            num_properties: num_properties,
            property_list_len: property_list_len,
            name_len: name_len,
        })
    }

    /// Check whether the header indicates there are no more children.
    pub fn is_null_record(&self) -> bool {
        self.end_offset == 0
            && self.num_properties == 0
            && self.property_list_len == 0
            && self.name_len == 0
    }
}
<|endoftext|>


<commit_before>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match int::from_str(input) {
        Some(number) => Int(number),
        None => match float::from_str(input) {
            Some(number) => Float(number),
            None => Symbol(input)
        }
    }
}

#[test]
fn test_that_parse_can_read_an_atom() {
    let atom = parse( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_parse_can_read_a_list() {
    let list = parse( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_parse_can_read_a_nested_list() {
    let list = parse( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn parse( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let token = tokens.head();
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                let mut remainder = tokens.tail();
                while remainder.len() > 0 && remainder.head() != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator += [expr];
                    remainder = new_remainder
                }
                (List(accumulator), remainder.tail())
            }
            ~")" => fail,
                _ => (atom(token), tokens.tail())
        }
    }
    let (expression, _remainder) = subexpression( tokens );
    expression
}

enum Expression {
    Int(int),
    Float(float),
    Symbol(~str),
    List(~[Expression])
}

fn stringify_expression( expression:Expression ) -> ~str {
    match expression {
        Int(number) => { fmt!("%d", number) }
        Float(number) => {
            if number == (number as int) as float {
                fmt!("%.1f", number)
            } else {
                fmt!("%f", number)
            }
        }
        Symbol(string) => { string }
        List(expressions) => {
            let strings = expressions.map( | &expr | {stringify_expression(expr)} );
            ~"(" + strings.foldl(~"", |&x, &y| { x + ~" " + y } ).trim() + ~")"
        }
    }
}

fn main() {
    io::println(stringify_expression( parse( tokenize( "(1 2 3 (1 2 3))" ) ) ));
    io::println(stringify_expression( parse( tokenize( "((1 2) 3 (1 2 3))" ) ) ));
    let blah:Expression = List(~[Int(1), List(~[Float(1.0), Symbol(~"xyz")])]);
    io::println(stringify_expression(blah));
    io::println( "(begin 1 2)" )
}
<commit_msg>Rename parse to read and add parse (includes tokenize)<commit_after>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match int::from_str(input) {
        Some(number) => Int(number),
        None => match float::from_str(input) {
            Some(number) => Float(number),
            None => Symbol(input)
        }
    }
}

#[test]
fn test_that_read_can_read_an_atom() {
    let atom = read( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_read_can_read_a_list() {
    let list = read( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_read_can_read_a_nested_list() {
    let list = read( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn parse( program:&str ) -> Expression {
    read( tokenize( program ) )
}

fn read( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let token = tokens.head();
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                let mut remainder = tokens.tail();
                while remainder.len() > 0 && remainder.head() != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator += [expr];
                    remainder = new_remainder
                }
                (List(accumulator), remainder.tail())
            }
            ~")" => fail,
                _ => (atom(token), tokens.tail())
        }
    }
    let (expression, _remainder) = subexpression( tokens );
    expression
}

enum Expression {
    Int(int),
    Float(float),
    Symbol(~str),
    List(~[Expression])
}

fn stringify_expression( expression:Expression ) -> ~str {
    match expression {
        Int(number) => { fmt!("%d", number) }
        Float(number) => {
            if number == (number as int) as float {
                fmt!("%.1f", number)
            } else {
                fmt!("%f", number)
            }
        }
        Symbol(string) => { string }
        List(expressions) => {
            let strings = expressions.map( | &expr | {stringify_expression(expr)} );
            ~"(" + strings.foldl(~"", |&x, &y| { x + ~" " + y } ).trim() + ~")"
        }
    }
}

fn main() {
    io::println(stringify_expression( parse( "(1 2 3 (1 2 3))" ) ));
    io::println(stringify_expression( parse( "((1 2) 3 (1 2 3))" ) ));
    let blah:Expression = List(~[Int(1), List(~[Float(1.0), Symbol(~"xyz")])]);
    io::println(stringify_expression(blah));
    io::println( "(begin 1 2)" )
}
<|endoftext|>


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

use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2};
use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D, Size2D};
use gfx::text::glyph::GlyphStore;
use std::sync::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{BorderStyle, Length, LengthPercentage};
use style::values::specified::ui::CursorKind;
use webrender_api::{self as wr, units};

// `webrender_api::display_item::ItemTag` is private
type ItemTag = (u64, u16);
type HitInfo = Option<ItemTag>;

pub struct DisplayListBuilder {
    current_space_and_clip: wr::SpaceAndClipInfo,
    pub wr: wr::DisplayListBuilder,

    /// Contentful paint, for the purpose of
    /// https://w3c.github.io/paint-timing/#first-contentful-paint
    /// (i.e. the display list contains items of type text,
    /// image, non-white canvas or SVG). Used by metrics.
    pub is_contentful: bool,
}

impl DisplayListBuilder {
    pub fn new(pipeline_id: wr::PipelineId, viewport_size: wr::units::LayoutSize) -> Self {
        Self {
            current_space_and_clip: wr::SpaceAndClipInfo::root_scroll(pipeline_id),
            is_contentful: false,
            wr: wr::DisplayListBuilder::new(pipeline_id, viewport_size),
        }
    }

    fn common_properties(&self, clip_rect: units::LayoutRect) -> wr::CommonItemProperties {
        self.common_properties_with_hit_info(clip_rect, None)
    }

    fn common_properties_with_hit_info(
        &self,
        clip_rect: units::LayoutRect,
        hit_info: HitInfo,
    ) -> wr::CommonItemProperties {
        wr::CommonItemProperties {
            clip_rect,
            clip_id: self.current_space_and_clip.clip_id,
            spatial_id: self.current_space_and_clip.spatial_id,
            hit_info,
            // TODO(gw): Make use of the WR backface visibility functionality.
            flags: wr::PrimitiveFlags::default(),
        }
    }

    fn clipping_and_scrolling_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
        let previous = self.current_space_and_clip;
        let result = f(self);
        self.current_space_and_clip = previous;
        result
    }
}

impl Fragment {
    pub(crate) fn build_display_list(
        &self,
        builder: &mut DisplayListBuilder,
        containing_block: &Rect<Length>,
    ) {
        match self {
            Fragment::Box(b) => {
                BuilderForBoxFragment::new(b, containing_block).build(builder, containing_block)
            },
            Fragment::Anonymous(a) => {
                let rect = a
                    .rect
                    .to_physical(a.mode, containing_block)
                    .translate(&containing_block.top_left);
                for child in &a.children {
                    child.build_display_list(builder, &rect)
                }
            },
            Fragment::Text(t) => {
                builder.is_contentful = true;
                let rect = t
                    .rect
                    .to_physical(t.parent_style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let mut baseline_origin = rect.top_left.clone();
                baseline_origin.y += t.ascent;
                let glyphs = glyphs(&t.glyphs, baseline_origin);
                if glyphs.is_empty() {
                    return;
                }
                let hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text);
                let common = builder.common_properties_with_hit_info(rect.clone().into(), hit_info);
                let color = t.parent_style.clone_color();
                builder
                    .wr
                    .push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
            },
            Fragment::Image(i) => {
                use style::computed_values::image_rendering::T as ImageRendering;
                builder.is_contentful = true;
                let rect = i
                    .rect
                    .to_physical(i.style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let common = builder.common_properties(rect.clone().into());
                builder.wr.push_image(
                    &common,
                    rect.into(),
                    match i.style.get_inherited_box().image_rendering {
                        ImageRendering::Auto => wr::ImageRendering::Auto,
                        ImageRendering::CrispEdges => wr::ImageRendering::CrispEdges,
                        ImageRendering::Pixelated => wr::ImageRendering::Pixelated,
                    },
                    wr::AlphaType::PremultipliedAlpha,
                    i.image_key,
                    wr::ColorF::WHITE,
                );
            },
        }
    }
}

struct BuilderForBoxFragment<'a> {
    fragment: &'a BoxFragment,
    border_rect: units::LayoutRect,
    border_radius: wr::BorderRadius,

    // Outer `Option` is `None`: not initialized yet
    // Inner `Option` is `None`: no border radius, no need to clip
    border_edge_clip_id: Option<Option<wr::ClipId>>,
}

impl<'a> BuilderForBoxFragment<'a> {
    fn new(fragment: &'a BoxFragment, containing_block: &Rect<Length>) -> Self {
        let border_rect: units::LayoutRect = fragment
            .border_rect()
            .to_physical(fragment.style.writing_mode, containing_block)
            .translate(&containing_block.top_left)
            .into();

        let border_radius = {
            let resolve = |radius: &LengthPercentage, box_size: f32| {
                radius.percentage_relative_to(Length::new(box_size)).px()
            };
            let corner = |corner: &style::values::computed::BorderCornerRadius| {
                Size2D::new(
                    resolve(&corner.0.width.0, border_rect.size.width),
                    resolve(&corner.0.height.0, border_rect.size.height),
                )
            };
            let b = fragment.style.get_border();
            wr::BorderRadius {
                top_left: corner(&b.border_top_left_radius),
                top_right: corner(&b.border_top_right_radius),
                bottom_right: corner(&b.border_bottom_right_radius),
                bottom_left: corner(&b.border_bottom_left_radius),
            }
        };

        Self {
            fragment,
            border_rect,
            border_radius,
            border_edge_clip_id: None,
        }
    }

    fn border_edge_clip_id(&mut self, builder: &mut DisplayListBuilder) -> Option<wr::ClipId> {
        let border_radius = &self.border_radius;
        let border_rect = &self.border_rect;
        *self.border_edge_clip_id.get_or_insert_with(|| {
            if border_radius.is_zero() {
                None
            } else {
                Some(builder.wr.define_clip(
                    &builder.current_space_and_clip,
                    *border_rect,
                    Some(wr::ComplexClipRegion {
                        rect: *border_rect,
                        radii: *border_radius,
                        mode: wr::ClipMode::Clip,
                    }),
                    None,
                ))
            }
        })
    }

    fn build(&mut self, builder: &mut DisplayListBuilder, containing_block: &Rect<Length>) {
        let hit_info = hit_info(&self.fragment.style, self.fragment.tag, Cursor::Default);
        if hit_info.is_some() {
            builder.clipping_and_scrolling_scope(|builder| {
                if let Some(id) = self.border_edge_clip_id(builder) {
                    builder.current_space_and_clip.clip_id = id
                }
                let common = builder.common_properties_with_hit_info(self.border_rect, hit_info);
                builder.wr.push_hit_test(&common)
            })
        }

        self.background_display_items(builder);
        self.border_display_items(builder);
        let content_rect = self
            .fragment
            .content_rect
            .to_physical(self.fragment.style.writing_mode, containing_block)
            .translate(&containing_block.top_left);
        for child in &self.fragment.children {
            child.build_display_list(builder, &content_rect)
        }
    }

    fn background_display_items(&mut self, builder: &mut DisplayListBuilder) {
        let background_color = self
            .fragment
            .style
            .resolve_color(self.fragment.style.clone_background_color());
        if background_color.alpha > 0 {
            builder.clipping_and_scrolling_scope(|builder| {
                if let Some(id) = self.border_edge_clip_id(builder) {
                    builder.current_space_and_clip.clip_id = id
                }
                let common = builder.common_properties(self.border_rect);
                builder.wr.push_rect(&common, rgba(background_color))
            });
        }
    }

    fn border_display_items(&mut self, builder: &mut DisplayListBuilder) {
        let b = self.fragment.style.get_border();
        let widths = SideOffsets2D::new(
            b.border_top_width.px(),
            b.border_right_width.px(),
            b.border_bottom_width.px(),
            b.border_left_width.px(),
        );
        if widths == SideOffsets2D::zero() {
            return;
        }
        let side = |style, color| wr::BorderSide {
            color: rgba(self.fragment.style.resolve_color(color)),
            style: match style {
                BorderStyle::None => wr::BorderStyle::None,
                BorderStyle::Solid => wr::BorderStyle::Solid,
                BorderStyle::Double => wr::BorderStyle::Double,
                BorderStyle::Dotted => wr::BorderStyle::Dotted,
                BorderStyle::Dashed => wr::BorderStyle::Dashed,
                BorderStyle::Hidden => wr::BorderStyle::Hidden,
                BorderStyle::Groove => wr::BorderStyle::Groove,
                BorderStyle::Ridge => wr::BorderStyle::Ridge,
                BorderStyle::Inset => wr::BorderStyle::Inset,
                BorderStyle::Outset => wr::BorderStyle::Outset,
            },
        };
        let common = builder.common_properties(self.border_rect);
        let details = wr::BorderDetails::Normal(wr::NormalBorder {
            top: side(b.border_top_style, b.border_top_color),
            right: side(b.border_right_style, b.border_right_color),
            bottom: side(b.border_bottom_style, b.border_bottom_color),
            left: side(b.border_left_style, b.border_left_color),
            radius: self.border_radius,
            do_aa: true,
        });
        builder
            .wr
            .push_border(&common, self.border_rect, widths, details)
    }
}

fn rgba(rgba: cssparser::RGBA) -> wr::ColorF {
    wr::ColorF::new(
        rgba.red_f32(),
        rgba.green_f32(),
        rgba.blue_f32(),
        rgba.alpha_f32(),
    )
}

fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::GlyphInstance> {
    use gfx_traits::ByteIndex;
    use range::Range;

    let mut glyphs = vec![];
    for run in glyph_runs {
        for glyph in run.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), run.len())) {
            if !run.is_whitespace() {
                let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
                let point = units::LayoutPoint::new(
                    origin.x.px() + glyph_offset.x.to_f32_px(),
                    origin.y.px() + glyph_offset.y.to_f32_px(),
                );
                let glyph = wr::GlyphInstance {
                    index: glyph.id(),
                    point,
                };
                glyphs.push(glyph);
            }
            origin.x += Length::from(glyph.advance());
        }
    }
    glyphs
}

fn hit_info(style: &ComputedValues, tag: OpaqueNode, auto_cursor: Cursor) -> HitInfo {
    use style::computed_values::pointer_events::T as PointerEvents;

    let inherited_ui = style.get_inherited_ui();
    if inherited_ui.pointer_events == PointerEvents::None {
        None
    } else {
        let cursor = cursor(inherited_ui.cursor.keyword, auto_cursor);
        Some((tag.0 as u64, cursor as u16))
    }
}

fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor {
    match kind {
        CursorKind::Auto => auto_cursor,
        CursorKind::None => Cursor::None,
        CursorKind::Default => Cursor::Default,
        CursorKind::Pointer => Cursor::Pointer,
        CursorKind::ContextMenu => Cursor::ContextMenu,
        CursorKind::Help => Cursor::Help,
        CursorKind::Progress => Cursor::Progress,
        CursorKind::Wait => Cursor::Wait,
        CursorKind::Cell => Cursor::Cell,
        CursorKind::Crosshair => Cursor::Crosshair,
        CursorKind::Text => Cursor::Text,
        CursorKind::VerticalText => Cursor::VerticalText,
        CursorKind::Alias => Cursor::Alias,
        CursorKind::Copy => Cursor::Copy,
        CursorKind::Move => Cursor::Move,
        CursorKind::NoDrop => Cursor::NoDrop,
        CursorKind::NotAllowed => Cursor::NotAllowed,
        CursorKind::Grab => Cursor::Grab,
        CursorKind::Grabbing => Cursor::Grabbing,
        CursorKind::EResize => Cursor::EResize,
        CursorKind::NResize => Cursor::NResize,
        CursorKind::NeResize => Cursor::NeResize,
        CursorKind::NwResize => Cursor::NwResize,
        CursorKind::SResize => Cursor::SResize,
        CursorKind::SeResize => Cursor::SeResize,
        CursorKind::SwResize => Cursor::SwResize,
        CursorKind::WResize => Cursor::WResize,
        CursorKind::EwResize => Cursor::EwResize,
        CursorKind::NsResize => Cursor::NsResize,
        CursorKind::NeswResize => Cursor::NeswResize,
        CursorKind::NwseResize => Cursor::NwseResize,
        CursorKind::ColResize => Cursor::ColResize,
        CursorKind::RowResize => Cursor::RowResize,
        CursorKind::AllScroll => Cursor::AllScroll,
        CursorKind::ZoomIn => Cursor::ZoomIn,
        CursorKind::ZoomOut => Cursor::ZoomOut,
    }
}
<commit_msg>Simplify `CommonItemProperties` construction<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2};
use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D, Size2D};
use gfx::text::glyph::GlyphStore;
use std::sync::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{BorderStyle, Length, LengthPercentage};
use style::values::specified::ui::CursorKind;
use webrender_api::{self as wr, units};

// `webrender_api::display_item::ItemTag` is private
type ItemTag = (u64, u16);
type HitInfo = Option<ItemTag>;

pub struct DisplayListBuilder {
    current_space_and_clip: wr::SpaceAndClipInfo,
    pub wr: wr::DisplayListBuilder,

    /// Contentful paint, for the purpose of
    /// https://w3c.github.io/paint-timing/#first-contentful-paint
    /// (i.e. the display list contains items of type text,
    /// image, non-white canvas or SVG). Used by metrics.
    pub is_contentful: bool,
}

impl DisplayListBuilder {
    pub fn new(pipeline_id: wr::PipelineId, viewport_size: wr::units::LayoutSize) -> Self {
        Self {
            current_space_and_clip: wr::SpaceAndClipInfo::root_scroll(pipeline_id),
            is_contentful: false,
            wr: wr::DisplayListBuilder::new(pipeline_id, viewport_size),
        }
    }

    fn common_properties(&self, clip_rect: units::LayoutRect) -> wr::CommonItemProperties {
        // TODO(gw): Make use of the WR backface visibility functionality.
        wr::CommonItemProperties::new(clip_rect, self.current_space_and_clip)
    }

    // FIXME: use this for the `overflow` property or anything else that clips an entire subtree.
    #[allow(unused)]
    fn clipping_and_scrolling_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
        let previous = self.current_space_and_clip;
        let result = f(self);
        self.current_space_and_clip = previous;
        result
    }
}

impl Fragment {
    pub(crate) fn build_display_list(
        &self,
        builder: &mut DisplayListBuilder,
        containing_block: &Rect<Length>,
    ) {
        match self {
            Fragment::Box(b) => {
                BuilderForBoxFragment::new(b, containing_block).build(builder, containing_block)
            },
            Fragment::Anonymous(a) => {
                let rect = a
                    .rect
                    .to_physical(a.mode, containing_block)
                    .translate(&containing_block.top_left);
                for child in &a.children {
                    child.build_display_list(builder, &rect)
                }
            },
            Fragment::Text(t) => {
                builder.is_contentful = true;
                let rect = t
                    .rect
                    .to_physical(t.parent_style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let mut baseline_origin = rect.top_left.clone();
                baseline_origin.y += t.ascent;
                let glyphs = glyphs(&t.glyphs, baseline_origin);
                if glyphs.is_empty() {
                    return;
                }
                let mut common = builder.common_properties(rect.clone().into());
                common.hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text);
                let color = t.parent_style.clone_color();
                builder
                    .wr
                    .push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
            },
            Fragment::Image(i) => {
                use style::computed_values::image_rendering::T as ImageRendering;
                builder.is_contentful = true;
                let rect = i
                    .rect
                    .to_physical(i.style.writing_mode, containing_block)
                    .translate(&containing_block.top_left);
                let common = builder.common_properties(rect.clone().into());
                builder.wr.push_image(
                    &common,
                    rect.into(),
                    match i.style.get_inherited_box().image_rendering {
                        ImageRendering::Auto => wr::ImageRendering::Auto,
                        ImageRendering::CrispEdges => wr::ImageRendering::CrispEdges,
                        ImageRendering::Pixelated => wr::ImageRendering::Pixelated,
                    },
                    wr::AlphaType::PremultipliedAlpha,
                    i.image_key,
                    wr::ColorF::WHITE,
                );
            },
        }
    }
}

struct BuilderForBoxFragment<'a> {
    fragment: &'a BoxFragment,
    border_rect: units::LayoutRect,
    border_radius: wr::BorderRadius,

    // Outer `Option` is `None`: not initialized yet
    // Inner `Option` is `None`: no border radius, no need to clip
    border_edge_clip_id: Option<Option<wr::ClipId>>,
}

impl<'a> BuilderForBoxFragment<'a> {
    fn new(fragment: &'a BoxFragment, containing_block: &Rect<Length>) -> Self {
        let border_rect: units::LayoutRect = fragment
            .border_rect()
            .to_physical(fragment.style.writing_mode, containing_block)
            .translate(&containing_block.top_left)
            .into();

        let border_radius = {
            let resolve = |radius: &LengthPercentage, box_size: f32| {
                radius.percentage_relative_to(Length::new(box_size)).px()
            };
            let corner = |corner: &style::values::computed::BorderCornerRadius| {
                Size2D::new(
                    resolve(&corner.0.width.0, border_rect.size.width),
                    resolve(&corner.0.height.0, border_rect.size.height),
                )
            };
            let b = fragment.style.get_border();
            wr::BorderRadius {
                top_left: corner(&b.border_top_left_radius),
                top_right: corner(&b.border_top_right_radius),
                bottom_right: corner(&b.border_bottom_right_radius),
                bottom_left: corner(&b.border_bottom_left_radius),
            }
        };

        Self {
            fragment,
            border_rect,
            border_radius,
            border_edge_clip_id: None,
        }
    }

    fn with_border_edge_clip(
        &mut self,
        builder: &mut DisplayListBuilder,
        common: &mut wr::CommonItemProperties,
    ) {
        let border_radius = &self.border_radius;
        let border_rect = &self.border_rect;
        let initialized = self.border_edge_clip_id.get_or_insert_with(|| {
            if border_radius.is_zero() {
                None
            } else {
                Some(builder.wr.define_clip(
                    &builder.current_space_and_clip,
                    *border_rect,
                    Some(wr::ComplexClipRegion {
                        rect: *border_rect,
                        radii: *border_radius,
                        mode: wr::ClipMode::Clip,
                    }),
                    None,
                ))
            }
        });
        if let Some(clip_id) = *initialized {
            common.clip_id = clip_id
        }
    }

    fn build(&mut self, builder: &mut DisplayListBuilder, containing_block: &Rect<Length>) {
        let hit_info = hit_info(&self.fragment.style, self.fragment.tag, Cursor::Default);
        if hit_info.is_some() {
            let mut common = builder.common_properties(self.border_rect);
            common.hit_info = hit_info;
            self.with_border_edge_clip(builder, &mut common);
            builder.wr.push_hit_test(&common)
        }

        self.background_display_items(builder);
        self.border_display_items(builder);
        let content_rect = self
            .fragment
            .content_rect
            .to_physical(self.fragment.style.writing_mode, containing_block)
            .translate(&containing_block.top_left);
        for child in &self.fragment.children {
            child.build_display_list(builder, &content_rect)
        }
    }

    fn background_display_items(&mut self, builder: &mut DisplayListBuilder) {
        let background_color = self
            .fragment
            .style
            .resolve_color(self.fragment.style.clone_background_color());
        if background_color.alpha > 0 {
            let mut common = builder.common_properties(self.border_rect);
            self.with_border_edge_clip(builder, &mut common);
            builder.wr.push_rect(&common, rgba(background_color))
        }
    }

    fn border_display_items(&mut self, builder: &mut DisplayListBuilder) {
        let b = self.fragment.style.get_border();
        let widths = SideOffsets2D::new(
            b.border_top_width.px(),
            b.border_right_width.px(),
            b.border_bottom_width.px(),
            b.border_left_width.px(),
        );
        if widths == SideOffsets2D::zero() {
            return;
        }
        let side = |style, color| wr::BorderSide {
            color: rgba(self.fragment.style.resolve_color(color)),
            style: match style {
                BorderStyle::None => wr::BorderStyle::None,
                BorderStyle::Solid => wr::BorderStyle::Solid,
                BorderStyle::Double => wr::BorderStyle::Double,
                BorderStyle::Dotted => wr::BorderStyle::Dotted,
                BorderStyle::Dashed => wr::BorderStyle::Dashed,
                BorderStyle::Hidden => wr::BorderStyle::Hidden,
                BorderStyle::Groove => wr::BorderStyle::Groove,
                BorderStyle::Ridge => wr::BorderStyle::Ridge,
                BorderStyle::Inset => wr::BorderStyle::Inset,
                BorderStyle::Outset => wr::BorderStyle::Outset,
            },
        };
        let common = builder.common_properties(self.border_rect);
        let details = wr::BorderDetails::Normal(wr::NormalBorder {
            top: side(b.border_top_style, b.border_top_color),
            right: side(b.border_right_style, b.border_right_color),
            bottom: side(b.border_bottom_style, b.border_bottom_color),
            left: side(b.border_left_style, b.border_left_color),
            radius: self.border_radius,
            do_aa: true,
        });
        builder
            .wr
            .push_border(&common, self.border_rect, widths, details)
    }
}

fn rgba(rgba: cssparser::RGBA) -> wr::ColorF {
    wr::ColorF::new(
        rgba.red_f32(),
        rgba.green_f32(),
        rgba.blue_f32(),
        rgba.alpha_f32(),
    )
}

fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::GlyphInstance> {
    use gfx_traits::ByteIndex;
    use range::Range;

    let mut glyphs = vec![];
    for run in glyph_runs {
        for glyph in run.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), run.len())) {
            if !run.is_whitespace() {
                let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
                let point = units::LayoutPoint::new(
                    origin.x.px() + glyph_offset.x.to_f32_px(),
                    origin.y.px() + glyph_offset.y.to_f32_px(),
                );
                let glyph = wr::GlyphInstance {
                    index: glyph.id(),
                    point,
                };
                glyphs.push(glyph);
            }
            origin.x += Length::from(glyph.advance());
        }
    }
    glyphs
}

fn hit_info(style: &ComputedValues, tag: OpaqueNode, auto_cursor: Cursor) -> HitInfo {
    use style::computed_values::pointer_events::T as PointerEvents;

    let inherited_ui = style.get_inherited_ui();
    if inherited_ui.pointer_events == PointerEvents::None {
        None
    } else {
        let cursor = cursor(inherited_ui.cursor.keyword, auto_cursor);
        Some((tag.0 as u64, cursor as u16))
    }
}

fn cursor(kind: CursorKind, auto_cursor: Cursor) -> Cursor {
    match kind {
        CursorKind::Auto => auto_cursor,
        CursorKind::None => Cursor::None,
        CursorKind::Default => Cursor::Default,
        CursorKind::Pointer => Cursor::Pointer,
        CursorKind::ContextMenu => Cursor::ContextMenu,
        CursorKind::Help => Cursor::Help,
        CursorKind::Progress => Cursor::Progress,
        CursorKind::Wait => Cursor::Wait,
        CursorKind::Cell => Cursor::Cell,
        CursorKind::Crosshair => Cursor::Crosshair,
        CursorKind::Text => Cursor::Text,
        CursorKind::VerticalText => Cursor::VerticalText,
        CursorKind::Alias => Cursor::Alias,
        CursorKind::Copy => Cursor::Copy,
        CursorKind::Move => Cursor::Move,
        CursorKind::NoDrop => Cursor::NoDrop,
        CursorKind::NotAllowed => Cursor::NotAllowed,
        CursorKind::Grab => Cursor::Grab,
        CursorKind::Grabbing => Cursor::Grabbing,
        CursorKind::EResize => Cursor::EResize,
        CursorKind::NResize => Cursor::NResize,
        CursorKind::NeResize => Cursor::NeResize,
        CursorKind::NwResize => Cursor::NwResize,
        CursorKind::SResize => Cursor::SResize,
        CursorKind::SeResize => Cursor::SeResize,
        CursorKind::SwResize => Cursor::SwResize,
        CursorKind::WResize => Cursor::WResize,
        CursorKind::EwResize => Cursor::EwResize,
        CursorKind::NsResize => Cursor::NsResize,
        CursorKind::NeswResize => Cursor::NeswResize,
        CursorKind::NwseResize => Cursor::NwseResize,
        CursorKind::ColResize => Cursor::ColResize,
        CursorKind::RowResize => Cursor::RowResize,
        CursorKind::AllScroll => Cursor::AllScroll,
        CursorKind::ZoomIn => Cursor::ZoomIn,
        CursorKind::ZoomOut => Cursor::ZoomOut,
    }
}
<|endoftext|>