<commit_before>//!
//! This module contains direct FFI calls to the NaCl library. The
//! Rust interface available in other crates in this package is much
//! easier to use, but this is conceviably necessary.
//!
//! See the [NaCl documentation](http://nacl.cr.yp.to/) for usage
//! information.
//!
//! (TODO: change this).
//!
//! For now, the relevant constants (`crypto_hash_BYTES`, etc.) are
//! available in the relevant Rust modules as statics.

use libc::*;

#[link(name = "tweetnacl", kind = "static")]
extern "C" {
    // --- Utilities ---

    /// Fill an array with secure random numbers.
    pub fn randombytes(ptr: *mut c_uchar, sz: u64);

    /// Perform scalar multiplication using Curve 25519's field.
    pub fn crypto_scalarmult(result: *mut c_uchar,
                             n: *c_uchar,
                             p: *c_uchar) -> c_int;
    /// Perform scalar multiplication against the Curve 25519 base point.
    pub fn crypto_scalarmult_base(result: *mut c_uchar, n: *c_uchar) -> c_int;

    // --- Crypto box ---

    /// Generate public and private keys for use with `crypto_box`.
    pub fn crypto_box_keypair(pk: *mut c_uchar, sk: *mut c_uchar) -> c_int;

    /// Sign and encrypt a message using asymmetric encryption.
    pub fn crypto_box(cipher: *mut c_uchar,
                      msg: *c_uchar,
                      len: c_ulonglong,
                      nonce: *c_uchar,
                      pk: *c_uchar,
                      sk: *c_uchar) -> c_int;

    /// Verify and decrypt a message generated with `crypto_box`.
    pub fn crypto_box_open(msg: *mut c_uchar,
                           cipher: *c_uchar,
                           len: c_ulonglong,
                           nonce: *c_uchar,
                           pk: *c_uchar,
                           sk: *c_uchar) -> c_int;

    // --- Secret box ---

    /// Symmetrically encrypt a message using a shared secret key.
    pub fn crypto_secretbox(cipher: *mut c_uchar,
                            msg: *c_uchar,
                            len: c_ulonglong,
                            nonce: *c_uchar,
                            k: *c_uchar) -> c_int;

    /// Decrypt a message encryped with `crypto_secretbox`.
    pub fn crypto_secretbox_open(msg: *mut c_uchar,
                                 cipher: *c_uchar,
                                 len: c_ulonglong,
                                 nonce: *c_uchar,
                                 k: *c_uchar) -> c_int;

    // --- Sign ---

    /// Generate signing keys to use with `crypto_sign`.
    pub fn crypto_sign_keypair(pk: *mut c_uchar,
                               sk: *mut c_uchar) -> c_int;

    /// Sign a message using a given secret key.
    pub fn crypto_sign(smsg: *mut c_uchar,
                       smsg_len: *mut c_ulonglong,
                       msg: *c_uchar,
                       msg_len: c_ulonglong,
                       sk: *c_uchar) -> c_int;

    /// Verify the validity of an asymmetrially signed message.
    pub fn crypto_sign_open(msg: *mut c_uchar,
                            msg_len: *mut c_ulonglong,
                            smsg: *c_uchar,
                            smsg_len: c_ulonglong,
                            pk: *c_uchar) -> c_int;

    // --- Hash ---
    /// Hash.
    pub fn crypto_hash(hash: *mut c_uchar,
                       msg: *c_uchar,
                       len: u64) -> c_int;
}
<commit_msg>Explicitly mark raw pointers as const<commit_after>//!
//! This module contains direct FFI calls to the NaCl library. The
//! Rust interface available in other crates in this package is much
//! easier to use, but this is conceviably necessary.
//!
//! See the [NaCl documentation](http://nacl.cr.yp.to/) for usage
//! information.
//!
//! (TODO: change this).
//!
//! For now, the relevant constants (`crypto_hash_BYTES`, etc.) are
//! available in the relevant Rust modules as statics.

use libc::*;

#[link(name = "tweetnacl", kind = "static")]
extern "C" {
    // --- Utilities ---

    /// Fill an array with secure random numbers.
    pub fn randombytes(ptr: *mut c_uchar, sz: u64);

    /// Perform scalar multiplication using Curve 25519's field.
    pub fn crypto_scalarmult(result: *mut c_uchar,
                             n: *const c_uchar,
                             p: *const c_uchar) -> c_int;
    /// Perform scalar multiplication against the Curve 25519 base point.
    pub fn crypto_scalarmult_base(result: *mut c_uchar, n: *const c_uchar) -> c_int;

    // --- Crypto box ---

    /// Generate public and private keys for use with `crypto_box`.
    pub fn crypto_box_keypair(pk: *mut c_uchar, sk: *mut c_uchar) -> c_int;

    /// Sign and encrypt a message using asymmetric encryption.
    pub fn crypto_box(cipher: *mut c_uchar,
                      msg: *const c_uchar,
                      len: c_ulonglong,
                      nonce: *const c_uchar,
                      pk: *const c_uchar,
                      sk: *const c_uchar) -> c_int;

    /// Verify and decrypt a message generated with `crypto_box`.
    pub fn crypto_box_open(msg: *mut c_uchar,
                           cipher: *const c_uchar,
                           len: c_ulonglong,
                           nonce: *const c_uchar,
                           pk: *const c_uchar,
                           sk: *const c_uchar) -> c_int;

    // --- Secret box ---

    /// Symmetrically encrypt a message using a shared secret key.
    pub fn crypto_secretbox(cipher: *mut c_uchar,
                            msg: *const c_uchar,
                            len: c_ulonglong,
                            nonce: *const c_uchar,
                            k: *const c_uchar) -> c_int;

    /// Decrypt a message encryped with `crypto_secretbox`.
    pub fn crypto_secretbox_open(msg: *mut c_uchar,
                                 cipher: *const c_uchar,
                                 len: c_ulonglong,
                                 nonce: *const c_uchar,
                                 k: *const c_uchar) -> c_int;

    // --- Sign ---

    /// Generate signing keys to use with `crypto_sign`.
    pub fn crypto_sign_keypair(pk: *mut c_uchar,
                               sk: *mut c_uchar) -> c_int;

    /// Sign a message using a given secret key.
    pub fn crypto_sign(smsg: *mut c_uchar,
                       smsg_len: *mut c_ulonglong,
                       msg: *const c_uchar,
                       msg_len: c_ulonglong,
                       sk: *const c_uchar) -> c_int;

    /// Verify the validity of an asymmetrially signed message.
    pub fn crypto_sign_open(msg: *mut c_uchar,
                            msg_len: *mut c_ulonglong,
                            smsg: *const c_uchar,
                            smsg_len: c_ulonglong,
                            pk: *const c_uchar) -> c_int;

    // --- Hash ---
    /// Hash.
    pub fn crypto_hash(hash: *mut c_uchar,
                       msg: *const c_uchar,
                       len: u64) -> c_int;
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(feature = "profiling-tracker")]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;
use gtk::{ApplicationWindow, Button, FileChooserAction, FileChooserDialog,
          HeaderBar, ResponseType, Label, ToolButton};

use ::media::{Context, ContextMessage, Timestamp};
use ::media::ContextMessage::*;

use super::{AudioController, DoubleWaveformBuffer, InfoController, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    play_pause_btn: ToolButton,
    position_lbl: Label,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: Rc<RefCell<AudioController>>,

    context: Option<Context>,
    duration: u64,
    last_position: u64,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),
            position_lbl: builder.get_object("position-lbl").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            duration: 0,
            last_position: 0,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = this.clone();
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = this.clone();
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let this_rc = this.clone();
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn play_pause(&mut self) {
        let context =
            match self.context.take() {
                Some(context) => context,
                None => return,
            };

        match context.get_state() {
            gst::State::Paused => {
                self.register_tracker(17); // 60 Hz
                self.play_pause_btn.set_icon_name("media-playback-pause");
                context.play().unwrap();
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
            },
            state => println!("Can't play/pause in state {:?}", state),
        };

        self.context = Some(context);
    }

    pub fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.borrow_mut().cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        if file_dlg.run() == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut message_iter = ui_rx.try_iter();

            let mut keep_going = true;
            for message in message_iter.next() {
                match message {
                    AsyncDone => {
                        println!("Received AsyncDone");
                    },
                    InitDone => {
                        println!("Received InitDone");

                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("... but no context available");

                        this_mut.duration = context.get_duration();

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.borrow_mut().new_media(&context);

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        println!("Received Eos");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.remove_tracker();
                        let duration = this_mut.duration;
                        this_mut.tic(duration);

                        // TODO: exit tracker
                        this_mut.play_pause_btn.set_icon_name("media-playback-start");
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn tic(&mut self, position: u64) {
        self.position_lbl.set_text(&Timestamp::format(position));
        self.last_position = position;

        self.audio_ctrl.borrow_mut().tic(position);
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_position = Utc::now();

            let position = this_mut.context.as_mut()
                .expect("No context in tracker")
                .get_position();

            #[cfg(feature = "profiling-tracker")]
            let before_tic = Utc::now();

            if this_mut.last_position != position
            && position <= this_mut.duration {
                this_mut.tic(position);
            }

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_position.time().format("%H:%M:%S%.6f"),
                before_tic.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
            );

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.position_lbl.set_text("00:00.000");

        let (ctx_tx, ui_rx) = channel();

        self.keep_going = true;
        self.register_listener(500, ui_rx);

        match Context::new(
            filepath,
            5_000_000_000,
            DoubleWaveformBuffer::new(),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
                self.last_position = 0;
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<commit_msg>Add position to tracker profiling (#25)<commit_after>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(feature = "profiling-tracker")]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;
use gtk::{ApplicationWindow, Button, FileChooserAction, FileChooserDialog,
          HeaderBar, ResponseType, Label, ToolButton};

use ::media::{Context, ContextMessage, Timestamp};
use ::media::ContextMessage::*;

use super::{AudioController, DoubleWaveformBuffer, InfoController, VideoController};

pub struct MainController {
    window: ApplicationWindow,
    header_bar: HeaderBar,
    play_pause_btn: ToolButton,
    position_lbl: Label,
    info_ctrl: InfoController,
    video_ctrl: VideoController,
    audio_ctrl: Rc<RefCell<AudioController>>,

    context: Option<Context>,
    duration: u64,
    last_position: u64,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),
            position_lbl: builder.get_object("position-lbl").unwrap(),
            info_ctrl: InfoController::new(&builder),
            video_ctrl: VideoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            duration: 0,
            last_position: 0,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = this.clone();
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = this.clone();
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });
        }

        let open_btn: Button = builder.get_object("open-btn").unwrap();
        let this_rc = this.clone();
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    pub fn play_pause(&mut self) {
        let context =
            match self.context.take() {
                Some(context) => context,
                None => return,
            };

        match context.get_state() {
            gst::State::Paused => {
                self.register_tracker(17); // 60 Hz
                self.play_pause_btn.set_icon_name("media-playback-pause");
                context.play().unwrap();
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
            },
            state => println!("Can't play/pause in state {:?}", state),
        };

        self.context = Some(context);
    }

    pub fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.borrow_mut().cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", ResponseType::Ok.into());

        if file_dlg.run() == ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut message_iter = ui_rx.try_iter();

            let mut keep_going = true;
            for message in message_iter.next() {
                match message {
                    AsyncDone => {
                        println!("Received AsyncDone");
                    },
                    InitDone => {
                        println!("Received InitDone");

                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("... but no context available");

                        this_mut.duration = context.get_duration();

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.borrow_mut().new_media(&context);

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        println!("Received Eos");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.remove_tracker();
                        let duration = this_mut.duration;
                        this_mut.tic(duration);

                        // TODO: exit tracker
                        this_mut.play_pause_btn.set_icon_name("media-playback-start");
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn tic(&mut self, position: u64) {
        self.position_lbl.set_text(&Timestamp::format(position));
        self.last_position = position;

        self.audio_ctrl.borrow_mut().tic(position);
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_rc = self.this_opt.as_ref()
            .unwrap()
            .clone();

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_position = Utc::now();

            let position = this_mut.context.as_mut()
                .expect("No context in tracker")
                .get_position();

            #[cfg(feature = "profiling-tracker")]
            let before_tic = Utc::now();

            if this_mut.last_position != position
            && position <= this_mut.duration {
                this_mut.tic(position);
            }

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_position.time().format("%H:%M:%S%.6f"),
                before_tic.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
                position,
            );

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.position_lbl.set_text("00:00.000");

        let (ctx_tx, ui_rx) = channel();

        self.keep_going = true;
        self.register_listener(500, ui_rx);

        match Context::new(
            filepath,
            5_000_000_000,
            DoubleWaveformBuffer::new(),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
                self.last_position = 0;
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<|endoftext|>


<commit_before>/*!

Generates an iterator type `__Matcher` that looks roughly like

```ignore
mod __intern_token {
    extern crate regex as __regex;

    pub struct __Matcher<'input> {
        text: &'input str,
        consumed: usize,
        regex_set: __regex::RegexSet,
        regex_vec: Vec<__regex::Regex>,
    }

    impl __Matcher<'input> {
        fn __tokenize(&self, text: &str) -> Option<(usize, usize)> { ... }
    }

    impl<'input> Iterator for __Matcher<'input> {
        type Item = Result<(usize, (usize, &'input str), usize), ParseError>;
        //                  ~~~~~   ~~~~~  ~~~~~~~~~~~   ~~~~~
        //                  start   token  token         end
        //                          index  text
    }
}
```

 */

use intern;
use lexer::re;
use grammar::parse_tree::InternToken;
use grammar::repr::{Grammar, TerminalLiteral};
use rust::RustWrite;
use std::io::{self, Write};

pub fn compile<W: Write>(
    grammar: &Grammar,
    intern_token: &InternToken,
    out: &mut RustWrite<W>)
    -> io::Result<()>
{
    let prefix = &grammar.prefix;

    rust!(out, "mod {}intern_token {{", prefix);
    try!(out.write_standard_uses(prefix));
    rust!(out, "extern crate regex as {}regex;", prefix);
    rust!(out, "pub struct {}Matcher<'input> {{", prefix);
    rust!(out, "text: &'input str,"); // remaining input
    rust!(out, "consumed: usize,"); // number of chars consumed thus far
    rust!(out, "regex_set: {}regex::RegexSet,", prefix);
    rust!(out, "regex_vec: Vec<{}regex::Regex>,", prefix);
    rust!(out, "}}");
    rust!(out, "");
    rust!(out, "impl<'input> {}Matcher<'input> {{", prefix);
    rust!(out, "pub fn new(s: &'input str) -> {}Matcher<'input> {{", prefix);

    // create a vector of rust string literals with the text of each
    // regular expression
    let regex_strings: Vec<String> = intern::read(|interner| {
        intern_token.match_entries
                    .iter()
                    .map(|match_entry| match match_entry.match_literal {
                        TerminalLiteral::Quoted(s) => re::parse_literal(interner.data(s)),
                        TerminalLiteral::Regex(s) => re::parse_regex(interner.data(s)).unwrap(),
                    })
                    .map(|regex| {
                        // make sure all regex are anchored at the beginning of the input
                        format!("^{}", regex)
                    })
                    .map(|regex_str| {
                        // create a rust string with text of the regex; the Debug impl
                        // will add quotes and escape
                        format!("{:?}", regex_str)
                    })
                    .collect()
    });

    rust!(out, "let {}strs: &[&str] = &[", prefix);
    for literal in &regex_strings {
        rust!(out, "{},", literal);
    }
    rust!(out, "];");
    rust!(out, "let {}regex_set = {}regex::RegexSet::new({}strs).unwrap();",
          prefix, prefix, prefix);

    rust!(out, "let {}regex_vec = vec![", prefix);
    for literal in &regex_strings {
        rust!(out, "{}regex::Regex::new({}).unwrap(),", prefix, literal);
    }
    rust!(out, "];");

    rust!(out, "{}Matcher {{", prefix);
    rust!(out, "text: s,");
    rust!(out, "consumed: 0,");
    rust!(out, "regex_set: {}regex_set,", prefix);
    rust!(out, "regex_vec: {}regex_vec,", prefix);
    rust!(out, "}}"); // struct literal
    rust!(out, "}}"); // fn new()
    rust!(out, "}}"); // impl Matcher<'input>
    rust!(out, "");
    rust!(out, "impl<'input> Iterator for {}Matcher<'input> {{", prefix);
    rust!(out, "type Item = Result<(usize, (usize, &'input str), usize), \
                {}lalrpop_util::ParseError<usize,(usize, &'input str),{}>>;",
          prefix, grammar.types.error_type());
    rust!(out, "");
    rust!(out, "fn next(&mut self) -> Option<Self::Item> {{");

    // start by trimming whitespace from left
    rust!(out, "let {}text = self.text.trim_left();", prefix);
    rust!(out, "let {}whitespace = self.text.len() - {}text.len();", prefix, prefix);
    rust!(out, "let {}start_offset = self.consumed + {}whitespace;", prefix, prefix);

    // if nothing left, return None
    rust!(out, "if {}text.is_empty() {{", prefix);
    rust!(out, "self.text = {}text;", prefix);
    rust!(out, "self.consumed = {}start_offset;", prefix);
    rust!(out, "None");
    rust!(out, "}} else {{");

    // otherwise, use regex-set to find list of matching tokens
    rust!(out, "let {}matches = self.regex_set.matches({}text);", prefix, prefix);

    // if nothing matched, return an error
    rust!(out, "if !{}matches.matched_any() {{", prefix);
    rust!(out, "Some(Err({}lalrpop_util::ParseError::InvalidToken {{", prefix);
    rust!(out, "location: {}start_offset,", prefix);
    rust!(out, "}}))");
    rust!(out, "}} else {{");

    // otherwise, have to find longest, highest-priority match. We have the literals
    // sorted in order of increasing precedence, so we'll iterate over them one by one,
    // checking if each one matches, and remembering the longest one.
    rust!(out, "let mut {}longest_match = 0;", prefix); // length of longest match
    rust!(out, "let mut {}index = 0;", prefix); // index of longest match
    rust!(out, "for {}i in 0 .. {} {{", prefix, intern_token.match_entries.len());
    rust!(out, "if {}matches.matched({}i) {{", prefix, prefix);

    // re-run the regex to find out how long this particular match
    // was, then compare that against the longest-match so far. Note
    // that the order of the tuple is carefully constructed to ensure
    // that (a) we get the longest-match but (b) if two matches are
    // equal, we get the largest index. This is because the indices
    // are sorted in order of increasing priority, and because we know
    // that indices of equal priority cannot both match (because of
    // the DFA check).
    rust!(out, "let {}match = self.regex_vec[{}i].find({}text).unwrap();", prefix, prefix, prefix);
    rust!(out, "let {}len = {}match.end();", prefix, prefix);
    rust!(out, "if {}len >= {}longest_match {{", prefix, prefix);
    rust!(out, "{}longest_match = {}len;", prefix, prefix);
    rust!(out, "{}index = {}i;", prefix, prefix);
    rust!(out, "}}"); // if is longest match
    rust!(out, "}}"); // if matches.matched(i)
    rust!(out, "}}"); // for loop

    // transform the result into the expected return value
    rust!(out, "let {}result = &{}text[..{}longest_match];", prefix, prefix, prefix);
    rust!(out, "let {}remaining = &{}text[{}longest_match..];", prefix, prefix, prefix);
    rust!(out, "let {}end_offset = {}start_offset + {}longest_match;", prefix, prefix, prefix);
    rust!(out, "self.text = {}remaining;", prefix);
    rust!(out, "self.consumed = {}end_offset;", prefix);
    rust!(out, "Some(Ok(({}start_offset, ({}index, {}result), {}end_offset)))",
          prefix, prefix, prefix, prefix);

    rust!(out, "}}"); // else
    rust!(out, "}}"); // else
    rust!(out, "}}"); // fn
    rust!(out, "}}"); // impl
    rust!(out, "}}"); // mod
    Ok(())
}

<commit_msg>Add user uses in generated mod intern_token (should fix #113)<commit_after>/*!

Generates an iterator type `__Matcher` that looks roughly like

```ignore
mod __intern_token {
    extern crate regex as __regex;

    pub struct __Matcher<'input> {
        text: &'input str,
        consumed: usize,
        regex_set: __regex::RegexSet,
        regex_vec: Vec<__regex::Regex>,
    }

    impl __Matcher<'input> {
        fn __tokenize(&self, text: &str) -> Option<(usize, usize)> { ... }
    }

    impl<'input> Iterator for __Matcher<'input> {
        type Item = Result<(usize, (usize, &'input str), usize), ParseError>;
        //                  ~~~~~   ~~~~~  ~~~~~~~~~~~   ~~~~~
        //                  start   token  token         end
        //                          index  text
    }
}
```

 */

use intern;
use lexer::re;
use grammar::parse_tree::InternToken;
use grammar::repr::{Grammar, TerminalLiteral};
use rust::RustWrite;
use std::io::{self, Write};

pub fn compile<W: Write>(
    grammar: &Grammar,
    intern_token: &InternToken,
    out: &mut RustWrite<W>)
    -> io::Result<()>
{
    let prefix = &grammar.prefix;

    rust!(out, "mod {}intern_token {{", prefix);
    try!(out.write_uses("", &grammar));
    rust!(out, "extern crate regex as {}regex;", prefix);
    rust!(out, "pub struct {}Matcher<'input> {{", prefix);
    rust!(out, "text: &'input str,"); // remaining input
    rust!(out, "consumed: usize,"); // number of chars consumed thus far
    rust!(out, "regex_set: {}regex::RegexSet,", prefix);
    rust!(out, "regex_vec: Vec<{}regex::Regex>,", prefix);
    rust!(out, "}}");
    rust!(out, "");
    rust!(out, "impl<'input> {}Matcher<'input> {{", prefix);
    rust!(out, "pub fn new(s: &'input str) -> {}Matcher<'input> {{", prefix);

    // create a vector of rust string literals with the text of each
    // regular expression
    let regex_strings: Vec<String> = intern::read(|interner| {
        intern_token.match_entries
                    .iter()
                    .map(|match_entry| match match_entry.match_literal {
                        TerminalLiteral::Quoted(s) => re::parse_literal(interner.data(s)),
                        TerminalLiteral::Regex(s) => re::parse_regex(interner.data(s)).unwrap(),
                    })
                    .map(|regex| {
                        // make sure all regex are anchored at the beginning of the input
                        format!("^{}", regex)
                    })
                    .map(|regex_str| {
                        // create a rust string with text of the regex; the Debug impl
                        // will add quotes and escape
                        format!("{:?}", regex_str)
                    })
                    .collect()
    });

    rust!(out, "let {}strs: &[&str] = &[", prefix);
    for literal in &regex_strings {
        rust!(out, "{},", literal);
    }
    rust!(out, "];");
    rust!(out, "let {}regex_set = {}regex::RegexSet::new({}strs).unwrap();",
          prefix, prefix, prefix);

    rust!(out, "let {}regex_vec = vec![", prefix);
    for literal in &regex_strings {
        rust!(out, "{}regex::Regex::new({}).unwrap(),", prefix, literal);
    }
    rust!(out, "];");

    rust!(out, "{}Matcher {{", prefix);
    rust!(out, "text: s,");
    rust!(out, "consumed: 0,");
    rust!(out, "regex_set: {}regex_set,", prefix);
    rust!(out, "regex_vec: {}regex_vec,", prefix);
    rust!(out, "}}"); // struct literal
    rust!(out, "}}"); // fn new()
    rust!(out, "}}"); // impl Matcher<'input>
    rust!(out, "");
    rust!(out, "impl<'input> Iterator for {}Matcher<'input> {{", prefix);
    rust!(out, "type Item = Result<(usize, (usize, &'input str), usize), \
                {}lalrpop_util::ParseError<usize,(usize, &'input str),{}>>;",
          prefix, grammar.types.error_type());
    rust!(out, "");
    rust!(out, "fn next(&mut self) -> Option<Self::Item> {{");

    // start by trimming whitespace from left
    rust!(out, "let {}text = self.text.trim_left();", prefix);
    rust!(out, "let {}whitespace = self.text.len() - {}text.len();", prefix, prefix);
    rust!(out, "let {}start_offset = self.consumed + {}whitespace;", prefix, prefix);

    // if nothing left, return None
    rust!(out, "if {}text.is_empty() {{", prefix);
    rust!(out, "self.text = {}text;", prefix);
    rust!(out, "self.consumed = {}start_offset;", prefix);
    rust!(out, "None");
    rust!(out, "}} else {{");

    // otherwise, use regex-set to find list of matching tokens
    rust!(out, "let {}matches = self.regex_set.matches({}text);", prefix, prefix);

    // if nothing matched, return an error
    rust!(out, "if !{}matches.matched_any() {{", prefix);
    rust!(out, "Some(Err({}lalrpop_util::ParseError::InvalidToken {{", prefix);
    rust!(out, "location: {}start_offset,", prefix);
    rust!(out, "}}))");
    rust!(out, "}} else {{");

    // otherwise, have to find longest, highest-priority match. We have the literals
    // sorted in order of increasing precedence, so we'll iterate over them one by one,
    // checking if each one matches, and remembering the longest one.
    rust!(out, "let mut {}longest_match = 0;", prefix); // length of longest match
    rust!(out, "let mut {}index = 0;", prefix); // index of longest match
    rust!(out, "for {}i in 0 .. {} {{", prefix, intern_token.match_entries.len());
    rust!(out, "if {}matches.matched({}i) {{", prefix, prefix);

    // re-run the regex to find out how long this particular match
    // was, then compare that against the longest-match so far. Note
    // that the order of the tuple is carefully constructed to ensure
    // that (a) we get the longest-match but (b) if two matches are
    // equal, we get the largest index. This is because the indices
    // are sorted in order of increasing priority, and because we know
    // that indices of equal priority cannot both match (because of
    // the DFA check).
    rust!(out, "let {}match = self.regex_vec[{}i].find({}text).unwrap();", prefix, prefix, prefix);
    rust!(out, "let {}len = {}match.end();", prefix, prefix);
    rust!(out, "if {}len >= {}longest_match {{", prefix, prefix);
    rust!(out, "{}longest_match = {}len;", prefix, prefix);
    rust!(out, "{}index = {}i;", prefix, prefix);
    rust!(out, "}}"); // if is longest match
    rust!(out, "}}"); // if matches.matched(i)
    rust!(out, "}}"); // for loop

    // transform the result into the expected return value
    rust!(out, "let {}result = &{}text[..{}longest_match];", prefix, prefix, prefix);
    rust!(out, "let {}remaining = &{}text[{}longest_match..];", prefix, prefix, prefix);
    rust!(out, "let {}end_offset = {}start_offset + {}longest_match;", prefix, prefix, prefix);
    rust!(out, "self.text = {}remaining;", prefix);
    rust!(out, "self.consumed = {}end_offset;", prefix);
    rust!(out, "Some(Ok(({}start_offset, ({}index, {}result), {}end_offset)))",
          prefix, prefix, prefix, prefix);

    rust!(out, "}}"); // else
    rust!(out, "}}"); // else
    rust!(out, "}}"); // fn
    rust!(out, "}}"); // impl
    rust!(out, "}}"); // mod
    Ok(())
}

<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(test, feature(test))]

#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(test)]
#[macro_use]
extern crate tarpc;

#[cfg(test)]
#[allow(dead_code)] // generated Client isn't used in this benchmark
mod benchmark {
    extern crate env_logger;
    extern crate test;

    use tarpc::ServeHandle;
    use self::test::Bencher;
    use std::sync::{Arc, Mutex};

    service! {
        rpc hello(s: String) -> String;
    }

    struct HelloServer;
    impl Service for HelloServer {
        fn hello(&self, s: String) -> String {
            format!("Hello, {}!", s)
        }
    }

    // Prevents resource exhaustion when benching
    lazy_static! {
        static ref HANDLE: Arc<Mutex<ServeHandle>> = {
            let handle = serve("localhost:0", HelloServer, None).unwrap();
            Arc::new(Mutex::new(handle))
        };
        static ref CLIENT: Arc<Mutex<AsyncClient>> = {
            let addr = HANDLE.lock().unwrap().local_addr().clone();
            let client = AsyncClient::new(addr, None).unwrap();
            Arc::new(Mutex::new(client))
        };
    }

    #[bench]
    fn hello(bencher: &mut Bencher) {
        let _ = env_logger::init();
        let client = CLIENT.lock().unwrap();
        let concurrency = 100;
        let mut futures = Vec::with_capacity(concurrency);
        let mut count = 0;
        bencher.iter(|| {
            futures.push(client.hello("Bob".into()));
            count += 1;
            if count % concurrency == 0 {
                // We can't block on each rpc call, otherwise we'd be
                // benchmarking latency instead of throughput. It's also
                // not ideal to call more than one rpc per iteration, because
                // it makes the output of the bencher harder to parse (you have
                // to mentally divide the number by `concurrency` to get
                // the ns / iter for one rpc
                for f in futures.drain(..) {
                    f.get().unwrap();
                }
            }
        });
    }
}
<commit_msg>Fix tarpc_examples<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(test, feature(test))]

#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(test)]
#[macro_use]
extern crate tarpc;

#[cfg(test)]
#[allow(dead_code)] // generated Client isn't used in this benchmark
mod benchmark {
    extern crate env_logger;
    extern crate test;

    use tarpc::ServeHandle;
    use self::test::Bencher;
    use std::sync::{Arc, Mutex};

    service! {
        rpc hello(s: String) -> String;
    }

    struct HelloServer;
    impl Service for HelloServer {
        fn hello(&self, s: String) -> String {
            format!("Hello, {}!", s)
        }
    }

    // Prevents resource exhaustion when benching
    lazy_static! {
        static ref HANDLE: Arc<Mutex<ServeHandle>> = {
            let handle = HelloServer.spawn("localhost:0").unwrap();
            Arc::new(Mutex::new(handle))
        };
        static ref CLIENT: Arc<Mutex<AsyncClient>> = {
            let addr = HANDLE.lock().unwrap().local_addr().clone();
            let client = AsyncClient::new(addr).unwrap();
            Arc::new(Mutex::new(client))
        };
    }

    #[bench]
    fn hello(bencher: &mut Bencher) {
        let _ = env_logger::init();
        let client = CLIENT.lock().unwrap();
        let concurrency = 100;
        let mut futures = Vec::with_capacity(concurrency);
        let mut count = 0;
        bencher.iter(|| {
            futures.push(client.hello("Bob".into()));
            count += 1;
            if count % concurrency == 0 {
                // We can't block on each rpc call, otherwise we'd be
                // benchmarking latency instead of throughput. It's also
                // not ideal to call more than one rpc per iteration, because
                // it makes the output of the bencher harder to parse (you have
                // to mentally divide the number by `concurrency` to get
                // the ns / iter for one rpc
                for f in futures.drain(..) {
                    f.get().unwrap();
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>//! Abstractions for page tables and other paging related structures.

pub use self::page_table::*;

use addr::{VirtAddr, PhysAddr};
use core::ops::Add;
use ux::*;

mod page_table;

/// The default page size on x86_64.
pub const PAGE_SIZE: u16 = 4096;

/// A virtual 4kB page.
pub struct Page {
   number: u64,
}

impl Page {
    /// Returns the page that contains the given virtual address.
    pub fn containing_address(address: VirtAddr) -> Page {
        Page { number: address.as_u64() / u64::from(PAGE_SIZE) }
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> VirtAddr {
        VirtAddr::new(self.number * u64::from(PAGE_SIZE))
    }

    /// Returns the level 4 page table index of this page.
    pub fn p4_index(&self) -> u9 {
        self.start_address().p4_index()
    }

    /// Returns the level 3 page table index of this page.
    pub fn p3_index(&self) -> u9 {
        self.start_address().p3_index()
    }

    /// Returns the level 2 page table index of this page.
    pub fn p2_index(&self) -> u9 {
        self.start_address().p2_index()
    }

    /// Returns the level 1 page table index of this page.
    pub fn p1_index(&self) -> u9 {
        self.start_address().p1_index()
    }
}

impl Add<u64> for Page {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}

/// A physical 4kB frame.
pub struct PhysFrame {
   number: u64,
}

impl PhysFrame {
    /// Returns the frame that contains the given physical address.
    pub fn containing_address(address: PhysAddr) -> PhysFrame {
        PhysFrame { number: address.as_u64() / u64::from(PAGE_SIZE) }
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> PhysAddr {
        PhysAddr::new(self.number * u64::from(PAGE_SIZE))
    }
}

impl Add<u64> for PhysFrame {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysFrame::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}
<commit_msg>Implement AddAssing, Sub, SubAssign, Debug and clone for Page and PhysFrame<commit_after>//! Abstractions for page tables and other paging related structures.

pub use self::page_table::*;

use addr::{VirtAddr, PhysAddr};
use core::ops::{Add, AddAssign, Sub, SubAssign};
use ux::*;

mod page_table;

/// The default page size on x86_64.
pub const PAGE_SIZE: u16 = 4096;

/// A virtual 4kB page.
#[derive(Debug, Clone)]
pub struct Page {
   number: u64,
}

impl Page {
    /// Returns the page that contains the given virtual address.
    pub fn containing_address(address: VirtAddr) -> Page {
        Page { number: address.as_u64() / u64::from(PAGE_SIZE) }
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> VirtAddr {
        VirtAddr::new(self.number * u64::from(PAGE_SIZE))
    }

    /// Returns the level 4 page table index of this page.
    pub fn p4_index(&self) -> u9 {
        self.start_address().p4_index()
    }

    /// Returns the level 3 page table index of this page.
    pub fn p3_index(&self) -> u9 {
        self.start_address().p3_index()
    }

    /// Returns the level 2 page table index of this page.
    pub fn p2_index(&self) -> u9 {
        self.start_address().p2_index()
    }

    /// Returns the level 1 page table index of this page.
    pub fn p1_index(&self) -> u9 {
        self.start_address().p1_index()
    }
}

impl Add<u64> for Page {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}

impl AddAssign<u64> for Page {
    fn add_assign(&mut self, rhs: u64) {
        *self = self.clone() + rhs;
    }
}

impl Sub<u64> for Page {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() - rhs * u64::from(PAGE_SIZE))
    }
}

impl SubAssign<u64> for Page {
    fn sub_assign(&mut self, rhs: u64) {
        *self = self.clone() - rhs;
    }
}

/// A physical 4kB frame.
#[derive(Debug, Clone)]
pub struct PhysFrame {
   number: u64,
}

impl PhysFrame {
    /// Returns the frame that contains the given physical address.
    pub fn containing_address(address: PhysAddr) -> PhysFrame {
        PhysFrame { number: address.as_u64() / u64::from(PAGE_SIZE) }
    }

    /// Returns the start address of the page.
    pub fn start_address(&self) -> PhysAddr {
        PhysAddr::new(self.number * u64::from(PAGE_SIZE))
    }
}

impl Add<u64> for PhysFrame {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysFrame::containing_address(self.start_address() + rhs * u64::from(PAGE_SIZE))
    }
}

impl AddAssign<u64> for PhysFrame {
    fn add_assign(&mut self, rhs: u64) {
        *self = self.clone() + rhs;
    }
}

impl Sub<u64> for PhysFrame {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        PhysFrame::containing_address(self.start_address() - rhs * u64::from(PAGE_SIZE))
    }
}

impl SubAssign<u64> for PhysFrame {
    fn sub_assign(&mut self, rhs: u64) {
        *self = self.clone() - rhs;
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::hash;
use std::marker::{MarkerTrait, PhantomData};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

use {Encode, EncodePtr, Message, ToMessage};
use runtime::Object;

#[link(name = "objc", kind = "dylib")]
extern {
    fn objc_retain(obj: *mut Object) -> *mut Object;
    fn objc_release(obj: *mut Object);
}

unsafe fn retain<T: Message>(ptr: *mut T) -> *mut T {
    objc_retain(ptr as *mut Object) as *mut T
}

unsafe fn release<T: Message>(ptr: *mut T) {
    objc_release(ptr as *mut Object);
}

/// A type used to mark that a struct owns the object(s) it contains,
/// so it has the sole references to them.
pub enum Owned { }
/// A type used to mark that the object(s) a struct contains are shared,
/// so there may be other references to them.
pub enum Shared { }

/// A type that marks what type of ownership a struct has over the object(s)
/// it contains; specifically, either `Owned` or `Shared`.
pub trait Ownership : 'static + MarkerTrait { }
impl Ownership for Owned { }
impl Ownership for Shared { }

/// A pointer type for Objective-C's reference counted objects. The object of
/// an `Id` is retained and sent a `release` message when the `Id` is dropped.
///
/// An `Id` may be either `Owned` or `Shared`, represented by the types `Id`
/// and `ShareId`, respectively. If owned, there are no other references to the
/// object and the `Id` can be mutably dereferenced. `ShareId`, however, can
/// only be immutably dereferenced because there may be other references to the
/// object, but a `ShareId` can be cloned to provide more references to the
/// object. An owned `Id` can be "downgraded" freely to a `ShareId`, but there
/// is no way to safely upgrade back.
#[unsafe_no_drop_flag]
pub struct Id<T, O = Owned> {
    ptr: *mut T,
    own: PhantomData<O>,
}

impl<T, O> Id<T, O> where T: Message, O: Ownership {
    unsafe fn from_ptr_unchecked(ptr: *mut T) -> Id<T, O> {
        Id { ptr: ptr, own: PhantomData }
    }

    /// Constructs an `Id` from a pointer to an unretained object and
    /// retains it. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        let ptr = retain(ptr);
        Id::from_ptr_unchecked(ptr)
    }

    /// Constructs an `Id` from a pointer to a retained object; this won't
    /// retain the pointer, so the caller must ensure the object has a +1
    /// retain count. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        Id::from_ptr_unchecked(ptr)
    }
}

impl<T> Id<T, Owned> where T: Message {
    /// "Downgrade" an owned `Id` to a `ShareId`, allowing it to be cloned.
    pub fn share(self) -> ShareId<T> {
        unsafe {
            let ptr = self.ptr;
            mem::forget(self);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

impl<T, O> Encode for Id<T, O> where T: EncodePtr {
    fn code() -> &'static str {
        <T as EncodePtr>::ptr_code()
    }
}

impl<T, O> ToMessage for Id<T, O> where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        self.ptr as *mut Object
    }
}

impl<T> Clone for Id<T, Shared> where T: Message {
    fn clone(&self) -> ShareId<T> {
        unsafe {
            let ptr = retain(self.ptr);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

#[unsafe_destructor]
impl<T, O> Drop for Id<T, O> where T: Message {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            let ptr = mem::replace(&mut self.ptr, ptr::null_mut());
            unsafe {
                release(ptr);
            }
        }
    }
}

unsafe impl<T, O> Sync for Id<T, O> where T: Sync { }

unsafe impl<T> Send for Id<T, Owned> where T: Send { }

unsafe impl<T> Send for Id<T, Shared> where T: Sync { }

impl<T, O> Deref for Id<T, O> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for Id<T, Owned> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T, O> PartialEq for Id<T, O> where T: PartialEq {
    fn eq(&self, other: &Id<T, O>) -> bool {
        self.deref() == other.deref()
    }

    fn ne(&self, other: &Id<T, O>) -> bool {
        self.deref() != other.deref()
    }
}

impl<T, O> Eq for Id<T, O> where T: Eq { }

impl<T, O> hash::Hash for Id<T, O> where T: hash::Hash {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        self.deref().hash(state)
    }
}

impl<T, O> fmt::Debug for Id<T, O> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.deref().fmt(f)
    }
}

/// A convenient alias for a shared `Id`.
pub type ShareId<T> = Id<T, Shared>;

/// Extension methods for slices containing `Id`s.
pub trait IdSlice {
    type Item;

    /// Convert a slice of `Id`s into a slice of references
    fn as_refs_slice(&self) -> &[&Self::Item];
}

impl<T, O> IdSlice for [Id<T, O>] {
    type Item = T;

    fn as_refs_slice(&self) -> &[&T] {
        unsafe {
            mem::transmute(self)
        }
    }
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;

    fn retain_count(obj: &Object) -> usize {
        unsafe { msg_send![obj, retainCount] }
    }

    #[test]
    fn test_clone() {
        let obj = test_utils::sample_object();
        assert!(retain_count(&obj) == 1);

        let obj = obj.share();
        assert!(retain_count(&obj) == 1);

        let cloned = obj.clone();
        assert!(retain_count(&cloned) == 2);
        assert!(retain_count(&obj) == 2);

        drop(obj);
        assert!(retain_count(&cloned) == 1);
    }
}
<commit_msg>Added a size test for Id.<commit_after>use std::fmt;
use std::hash;
use std::marker::{MarkerTrait, PhantomData};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

use {Encode, EncodePtr, Message, ToMessage};
use runtime::Object;

#[link(name = "objc", kind = "dylib")]
extern {
    fn objc_retain(obj: *mut Object) -> *mut Object;
    fn objc_release(obj: *mut Object);
}

unsafe fn retain<T: Message>(ptr: *mut T) -> *mut T {
    objc_retain(ptr as *mut Object) as *mut T
}

unsafe fn release<T: Message>(ptr: *mut T) {
    objc_release(ptr as *mut Object);
}

/// A type used to mark that a struct owns the object(s) it contains,
/// so it has the sole references to them.
pub enum Owned { }
/// A type used to mark that the object(s) a struct contains are shared,
/// so there may be other references to them.
pub enum Shared { }

/// A type that marks what type of ownership a struct has over the object(s)
/// it contains; specifically, either `Owned` or `Shared`.
pub trait Ownership : 'static + MarkerTrait { }
impl Ownership for Owned { }
impl Ownership for Shared { }

/// A pointer type for Objective-C's reference counted objects. The object of
/// an `Id` is retained and sent a `release` message when the `Id` is dropped.
///
/// An `Id` may be either `Owned` or `Shared`, represented by the types `Id`
/// and `ShareId`, respectively. If owned, there are no other references to the
/// object and the `Id` can be mutably dereferenced. `ShareId`, however, can
/// only be immutably dereferenced because there may be other references to the
/// object, but a `ShareId` can be cloned to provide more references to the
/// object. An owned `Id` can be "downgraded" freely to a `ShareId`, but there
/// is no way to safely upgrade back.
#[unsafe_no_drop_flag]
pub struct Id<T, O = Owned> {
    ptr: *mut T,
    own: PhantomData<O>,
}

impl<T, O> Id<T, O> where T: Message, O: Ownership {
    unsafe fn from_ptr_unchecked(ptr: *mut T) -> Id<T, O> {
        Id { ptr: ptr, own: PhantomData }
    }

    /// Constructs an `Id` from a pointer to an unretained object and
    /// retains it. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        let ptr = retain(ptr);
        Id::from_ptr_unchecked(ptr)
    }

    /// Constructs an `Id` from a pointer to a retained object; this won't
    /// retain the pointer, so the caller must ensure the object has a +1
    /// retain count. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        Id::from_ptr_unchecked(ptr)
    }
}

impl<T> Id<T, Owned> where T: Message {
    /// "Downgrade" an owned `Id` to a `ShareId`, allowing it to be cloned.
    pub fn share(self) -> ShareId<T> {
        unsafe {
            let ptr = self.ptr;
            mem::forget(self);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

impl<T, O> Encode for Id<T, O> where T: EncodePtr {
    fn code() -> &'static str {
        <T as EncodePtr>::ptr_code()
    }
}

impl<T, O> ToMessage for Id<T, O> where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        self.ptr as *mut Object
    }
}

impl<T> Clone for Id<T, Shared> where T: Message {
    fn clone(&self) -> ShareId<T> {
        unsafe {
            let ptr = retain(self.ptr);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

#[unsafe_destructor]
impl<T, O> Drop for Id<T, O> where T: Message {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            let ptr = mem::replace(&mut self.ptr, ptr::null_mut());
            unsafe {
                release(ptr);
            }
        }
    }
}

unsafe impl<T, O> Sync for Id<T, O> where T: Sync { }

unsafe impl<T> Send for Id<T, Owned> where T: Send { }

unsafe impl<T> Send for Id<T, Shared> where T: Sync { }

impl<T, O> Deref for Id<T, O> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for Id<T, Owned> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T, O> PartialEq for Id<T, O> where T: PartialEq {
    fn eq(&self, other: &Id<T, O>) -> bool {
        self.deref() == other.deref()
    }

    fn ne(&self, other: &Id<T, O>) -> bool {
        self.deref() != other.deref()
    }
}

impl<T, O> Eq for Id<T, O> where T: Eq { }

impl<T, O> hash::Hash for Id<T, O> where T: hash::Hash {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        self.deref().hash(state)
    }
}

impl<T, O> fmt::Debug for Id<T, O> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.deref().fmt(f)
    }
}

/// A convenient alias for a shared `Id`.
pub type ShareId<T> = Id<T, Shared>;

/// Extension methods for slices containing `Id`s.
pub trait IdSlice {
    type Item;

    /// Convert a slice of `Id`s into a slice of references
    fn as_refs_slice(&self) -> &[&Self::Item];
}

impl<T, O> IdSlice for [Id<T, O>] {
    type Item = T;

    fn as_refs_slice(&self) -> &[&T] {
        unsafe {
            mem::transmute(self)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;

    use runtime::Object;
    use test_utils;
    use super::Id;

    fn retain_count(obj: &Object) -> usize {
        unsafe { msg_send![obj, retainCount] }
    }

    #[test]
    fn test_clone() {
        let obj = test_utils::sample_object();
        assert!(retain_count(&obj) == 1);

        let obj = obj.share();
        assert!(retain_count(&obj) == 1);

        let cloned = obj.clone();
        assert!(retain_count(&cloned) == 2);
        assert!(retain_count(&obj) == 2);

        drop(obj);
        assert!(retain_count(&cloned) == 1);
    }

    #[test]
    fn test_size() {
        let id_size = mem::size_of::<Id<Object>>();
        let ptr_size = mem::size_of::<*const Object>();
        assert!(id_size == ptr_size);
    }
}
<|endoftext|>


<commit_before>//! Traits for building lightweight asynchronous APIs. These traits lack the
//! dynamic capabilities of `core::future::Future`, but have much smaller code
//! size and RAM usage costs.
//!
//! Tock kernel developers will be familiar with the 2-phase pattern of
//! operation these traits support. Client code (code using an asynchronous
//! component) calls a function or method provided by the asynchronous component
//! to start an asynchronous operation. When the operation is complete, the
//! asynchronous component calls a callback defined using the `FreeCallback`
//! and/or `MethodCallback` traits.
//!
//! Note that asynchronous callbacks must only be called from within "callback
//! context" -- that is, within a kernel callback (registered using the
//! `subscribe` system call). To enforce that, the callback traits require the
//! `CallbackContext` type, which is only instantiated by an instance of the
//! `Syscalls` trait.
//!
//! There is no prohibition on a callback calling back into the asynchronous
//! component that called it. In other words, if component B calls
//! `<A as FreeCallback<Done>>::call(...)`, then `call()` can call back into B
//! to start a new operation. Asynchronous components should clean up their
//! state internally before calling callbacks so as to support reentrant calls
//! into themselves!
//!
//! In client code, prefer to implement `FreeCallback` instead of
//! `MethodCallback` when possible, as it is easier to pass a `FreeCallback` to
//! an asynchronous component.
//!
//! To bridge the gap between `FreeCallback` and `MethodCallback`, we also have
//! the `Locator` trait. `Locator` allows `FreeCallback` implementations to find
//! their global state, and also provides `FreeCallback` versions of callbacks
//! for types that implement `MethodCallback`. In general, `Locator` should be
//! implemented by `libtock_runtime::static_component!` (in real Tock apps) and
//! `libtock_unittest::test_component!` (in unit tests), rather than directly by
//! user code.
// TODO: At the time of this writing, neither `libtock_runtime` nor
// `libtock_unittest` are implemented. Remove this TODO when they are
// implemented.

/// `FreeCallback` is the callback equivalent of a free function: it does not
/// have access to the client component's data. `FreeCallback` is used by
/// asynchronous components -- such as `Syscalls` -- which cannot efficiently
/// store a client reference.
pub trait FreeCallback<AsyncResponse> {
    fn call(context: CallbackContext, response: AsyncResponse);
}

/// `MethodCallback` is a callback method; it can access the client component's
/// data. Note that asynchronous components generally need to use interior
/// mutability to mutate data, as `MethodCallback` is designed under the
/// assumption that there are multiple references to most asynchronous
/// components at any given time.
pub trait MethodCallback<AsyncResponse> {
    fn call(&self, context: CallbackContext, response: AsyncResponse);
}

/// `Syscalls` instantiates a `CallbackContext` when a kernel callback is
/// called. The lifetime prevents the `CallbackContext` from being copied into
/// storage that outlives the callback. Code that is only safe to call from
/// callback context can request a `CallbackContext` argument. `CallbackContext`
/// is a zero-sized type so passing it around has no runtime cost.
#[derive(Clone, Copy)]
pub struct CallbackContext<'c> {
    // `_phantom` serves three purposes. It uses the `c lifetime to avoid an
    // "unused lifetime" error, it provides the proper variance over 'c, and it
    // prevents code outside this crate from constructing a CallbackContext
    // (because of its visibility control).
    pub(crate) _phantom: core::marker::PhantomData<&'c ()>,
}

/// Provides access to a global instance of type `Target`. Every call to
/// `locate()` on a given Locator type should return a reference to the same
/// instance of `Target`. An instance of `Locator` generally isn't instantiated
/// directly; instead, its type is passed to where it is needed via generic
/// arguments.
///
/// For convenience, Locator provides a `FreeCallback` implementation for every
/// `MethodCallback` implementation that `Target` has.
pub trait Locator: 'static {
    type Target;
    fn locate() -> &'static Self::Target;
}

impl<L: Locator, AsyncResponse> FreeCallback<AsyncResponse> for L
where
    L::Target: MethodCallback<AsyncResponse>,
{
    fn call(context: CallbackContext, response: AsyncResponse) {
        L::locate().call(context, response);
    }
}
<commit_msg>Add a note about how CallbackContext can be copied by code outside `libtock_platform`.<commit_after>//! Traits for building lightweight asynchronous APIs. These traits lack the
//! dynamic capabilities of `core::future::Future`, but have much smaller code
//! size and RAM usage costs.
//!
//! Tock kernel developers will be familiar with the 2-phase pattern of
//! operation these traits support. Client code (code using an asynchronous
//! component) calls a function or method provided by the asynchronous component
//! to start an asynchronous operation. When the operation is complete, the
//! asynchronous component calls a callback defined using the `FreeCallback`
//! and/or `MethodCallback` traits.
//!
//! Note that asynchronous callbacks must only be called from within "callback
//! context" -- that is, within a kernel callback (registered using the
//! `subscribe` system call). To enforce that, the callback traits require the
//! `CallbackContext` type, which is only instantiated by an instance of the
//! `Syscalls` trait.
//!
//! There is no prohibition on a callback calling back into the asynchronous
//! component that called it. In other words, if component B calls
//! `<A as FreeCallback<Done>>::call(...)`, then `call()` can call back into B
//! to start a new operation. Asynchronous components should clean up their
//! state internally before calling callbacks so as to support reentrant calls
//! into themselves!
//!
//! In client code, prefer to implement `FreeCallback` instead of
//! `MethodCallback` when possible, as it is easier to pass a `FreeCallback` to
//! an asynchronous component.
//!
//! To bridge the gap between `FreeCallback` and `MethodCallback`, we also have
//! the `Locator` trait. `Locator` allows `FreeCallback` implementations to find
//! their global state, and also provides `FreeCallback` versions of callbacks
//! for types that implement `MethodCallback`. In general, `Locator` should be
//! implemented by `libtock_runtime::static_component!` (in real Tock apps) and
//! `libtock_unittest::test_component!` (in unit tests), rather than directly by
//! user code.
// TODO: At the time of this writing, neither `libtock_runtime` nor
// `libtock_unittest` are implemented. Remove this TODO when they are
// implemented.

/// `FreeCallback` is the callback equivalent of a free function: it does not
/// have access to the client component's data. `FreeCallback` is used by
/// asynchronous components -- such as `Syscalls` -- which cannot efficiently
/// store a client reference.
pub trait FreeCallback<AsyncResponse> {
    fn call(context: CallbackContext, response: AsyncResponse);
}

/// `MethodCallback` is a callback method; it can access the client component's
/// data. Note that asynchronous components generally need to use interior
/// mutability to mutate data, as `MethodCallback` is designed under the
/// assumption that there are multiple references to most asynchronous
/// components at any given time.
pub trait MethodCallback<AsyncResponse> {
    fn call(&self, context: CallbackContext, response: AsyncResponse);
}

/// `Syscalls` instantiates a `CallbackContext` when a kernel callback is
/// called. The lifetime prevents the `CallbackContext` from being copied into
/// storage that outlives the callback. Code that is only safe to call from
/// callback context can request a `CallbackContext` argument. `CallbackContext`
/// is a zero-sized type so passing it around has no runtime cost.
#[derive(Clone, Copy)]
pub struct CallbackContext<'c> {
    // `_phantom` serves three purposes. It uses the `c lifetime to avoid an
    // "unused lifetime" error, it provides the proper variance over 'c, and it
    // prevents code outside this crate from directly constructing a
    // CallbackContext (because of its visibility control). Code outside this
    // crate can copy a CallbackContext, but that is fine as copying the
    // CallbackContext preserves its associated lifetime.
    pub(crate) _phantom: core::marker::PhantomData<&'c ()>,
}

/// Provides access to a global instance of type `Target`. Every call to
/// `locate()` on a given Locator type should return a reference to the same
/// instance of `Target`. An instance of `Locator` generally isn't instantiated
/// directly; instead, its type is passed to where it is needed via generic
/// arguments.
///
/// For convenience, Locator provides a `FreeCallback` implementation for every
/// `MethodCallback` implementation that `Target` has.
pub trait Locator: 'static {
    type Target;
    fn locate() -> &'static Self::Target;
}

impl<L: Locator, AsyncResponse> FreeCallback<AsyncResponse> for L
where
    L::Target: MethodCallback<AsyncResponse>,
{
    fn call(context: CallbackContext, response: AsyncResponse) {
        L::locate().call(context, response);
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use super::*;

pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
    L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, IMPL_KW,
    DYN_KW, L_ANGLE,
]);

const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA];

pub(crate) fn type_(p: &mut Parser) {
    type_with_bounds_cond(p, true);
}

pub(super) fn type_no_bounds(p: &mut Parser) {
    type_with_bounds_cond(p, false);
}

fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
    match p.current() {
        T!['('] => paren_or_tuple_type(p),
        T![!] => never_type(p),
        T![*] => pointer_type(p),
        T!['['] => array_or_slice_type(p),
        T![&] => reference_type(p),
        T![_] => placeholder_type(p),
        T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p),
        T![for] => for_type(p),
        T![impl] => impl_trait_type(p),
        T![dyn ] => dyn_trait_type(p),
        // Some path types are not allowed to have bounds (no plus)
        T![<] => path_type_(p, allow_bounds),
        _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds),
        _ => {
            p.err_recover("expected type", TYPE_RECOVERY_SET);
        }
    }
}

pub(super) fn ascription(p: &mut Parser) {
    p.expect(T![:]);
    type_(p)
}

fn paren_or_tuple_type(p: &mut Parser) {
    assert!(p.at(T!['(']));
    let m = p.start();
    p.bump(T!['(']);
    let mut n_types: u32 = 0;
    let mut trailing_comma: bool = false;
    while !p.at(EOF) && !p.at(T![')']) {
        n_types += 1;
        type_(p);
        if p.eat(T![,]) {
            trailing_comma = true;
        } else {
            trailing_comma = false;
            break;
        }
    }
    p.expect(T![')']);

    let kind = if n_types == 1 && !trailing_comma {
        // test paren_type
        // type T = (i32);
        PAREN_TYPE
    } else {
        // test unit_type
        // type T = ();

        // test singleton_tuple_type
        // type T = (i32,);
        TUPLE_TYPE
    };
    m.complete(p, kind);
}

// test never_type
// type Never = !;
fn never_type(p: &mut Parser) {
    assert!(p.at(T![!]));
    let m = p.start();
    p.bump(T![!]);
    m.complete(p, NEVER_TYPE);
}

fn pointer_type(p: &mut Parser) {
    assert!(p.at(T![*]));
    let m = p.start();
    p.bump(T![*]);

    match p.current() {
        // test pointer_type_mut
        // type M = *mut ();
        // type C = *mut ();
        T![mut] | T![const] => p.bump_any(),
        _ => {
            // test_err pointer_type_no_mutability
            // type T = *();
            p.error(
                "expected mut or const in raw pointer type \
                 (use `*mut T` or `*const T` as appropriate)",
            );
        }
    };

    type_no_bounds(p);
    m.complete(p, POINTER_TYPE);
}

fn array_or_slice_type(p: &mut Parser) {
    assert!(p.at(T!['[']));
    let m = p.start();
    p.bump(T!['[']);

    type_(p);
    let kind = match p.current() {
        // test slice_type
        // type T = [()];
        T![']'] => {
            p.bump(T![']']);
            SLICE_TYPE
        }

        // test array_type
        // type T = [(); 92];
        T![;] => {
            p.bump(T![;]);
            expressions::expr(p);
            p.expect(T![']']);
            ARRAY_TYPE
        }
        // test_err array_type_missing_semi
        // type T = [() 92];
        _ => {
            p.error("expected `;` or `]`");
            SLICE_TYPE
        }
    };
    m.complete(p, kind);
}

// test reference_type;
// type A = &();
// type B = &'static ();
// type C = &mut ();
fn reference_type(p: &mut Parser) {
    assert!(p.at(T![&]));
    let m = p.start();
    p.bump(T![&]);
    p.eat(LIFETIME);
    p.eat(T![mut]);
    type_no_bounds(p);
    m.complete(p, REFERENCE_TYPE);
}

// test placeholder_type
// type Placeholder = _;
fn placeholder_type(p: &mut Parser) {
    assert!(p.at(T![_]));
    let m = p.start();
    p.bump(T![_]);
    m.complete(p, PLACEHOLDER_TYPE);
}

// test fn_pointer_type
// type A = fn();
// type B = unsafe fn();
// type C = unsafe extern "C" fn();
// type D = extern "C" fn ( u8 , ... ) -> u8;
fn fn_pointer_type(p: &mut Parser) {
    let m = p.start();
    p.eat(T![unsafe]);
    if p.at(T![extern]) {
        abi(p);
    }
    // test_err fn_pointer_type_missing_fn
    // type F = unsafe ();
    if !p.eat(T![fn]) {
        m.abandon(p);
        p.error("expected `fn`");
        return;
    }
    if p.at(T!['(']) {
        params::param_list_opt_patterns(p);
    } else {
        p.error("expected parameters")
    }
    // test fn_pointer_type_with_ret
    // type F = fn() -> ();
    opt_fn_ret_type(p);
    m.complete(p, FN_POINTER_TYPE);
}

pub(super) fn for_binder(p: &mut Parser) {
    assert!(p.at(T![for]));
    p.bump(T![for]);
    if p.at(T![<]) {
        type_params::opt_type_param_list(p);
    } else {
        p.error("expected `<`");
    }
}

// test for_type
// type A = for<'a> fn() -> ();
// fn foo<T>(_t: &T) where for<'a> &'a T: Iterator {}
// fn bar<T>(_t: &T) where for<'a> &'a mut T: Iterator {}
// fn baz<T>(_t: &T) where for<'a> <&'a T as Baz>::Foo: Iterator {}
pub(super) fn for_type(p: &mut Parser) {
    assert!(p.at(T![for]));
    let m = p.start();
    for_binder(p);
    match p.current() {
        T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p),
        T![&] => reference_type(p),
        _ if paths::is_path_start(p) => path_type_(p, false),
        _ => p.error("expected a path"),
    }
    m.complete(p, FOR_TYPE);
}

// test impl_trait_type
// type A = impl Iterator<Item=Foo<'a>> + 'a;
fn impl_trait_type(p: &mut Parser) {
    assert!(p.at(T![impl]));
    let m = p.start();
    p.bump(T![impl]);
    type_params::bounds_without_colon(p);
    m.complete(p, IMPL_TRAIT_TYPE);
}

// test dyn_trait_type
// type A = dyn Iterator<Item=Foo<'a>> + 'a;
fn dyn_trait_type(p: &mut Parser) {
    assert!(p.at(T![dyn ]));
    let m = p.start();
    p.bump(T![dyn ]);
    type_params::bounds_without_colon(p);
    m.complete(p, DYN_TRAIT_TYPE);
}

// test path_type
// type A = Foo;
// type B = ::Foo;
// type C = self::Foo;
// type D = super::Foo;
pub(super) fn path_type(p: &mut Parser) {
    path_type_(p, true)
}

// test macro_call_type
// type A = foo!();
// type B = crate::foo!();
fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::type_path(p);

    let kind = if p.at(T![!]) && !p.at(T![!=]) {
        items::macro_call_after_excl(p);
        MACRO_CALL
    } else {
        PATH_TYPE
    };

    let path = m.complete(p, kind);

    if allow_bounds {
        opt_path_type_bounds_as_dyn_trait_type(p, path);
    }
}

pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::type_path(p);

    // test path_type_with_bounds
    // fn foo() -> Box<T + 'f> {}
    // fn foo() -> Box<dyn T + 'f> {}
    let path = m.complete(p, PATH_TYPE);
    if allow_bounds {
        opt_path_type_bounds_as_dyn_trait_type(p, path);
    }
}

/// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE
/// with a TYPE_BOUND_LIST
fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) {
    if !p.at(T![+]) {
        return;
    }

    // First create a TYPE_BOUND from the completed PATH_TYPE
    let m = path_type_marker.precede(p).complete(p, TYPE_BOUND);

    // Next setup a marker for the TYPE_BOUND_LIST
    let m = m.precede(p);

    // This gets consumed here so it gets properly set
    // in the TYPE_BOUND_LIST
    p.eat(T![+]);

    // Parse rest of the bounds into the TYPE_BOUND_LIST
    let m = type_params::bounds_without_colon_m(p, m);

    // Finally precede everything with DYN_TRAIT_TYPE
    m.precede(p).complete(p, DYN_TRAIT_TYPE);
}
<commit_msg>cargo xtask format with 1.39<commit_after>//! FIXME: write short doc here

use super::*;

pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
    L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, IMPL_KW,
    DYN_KW, L_ANGLE,
]);

const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA];

pub(crate) fn type_(p: &mut Parser) {
    type_with_bounds_cond(p, true);
}

pub(super) fn type_no_bounds(p: &mut Parser) {
    type_with_bounds_cond(p, false);
}

fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
    match p.current() {
        T!['('] => paren_or_tuple_type(p),
        T![!] => never_type(p),
        T![*] => pointer_type(p),
        T!['['] => array_or_slice_type(p),
        T![&] => reference_type(p),
        T![_] => placeholder_type(p),
        T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p),
        T![for] => for_type(p),
        T![impl] => impl_trait_type(p),
        T![dyn] => dyn_trait_type(p),
        // Some path types are not allowed to have bounds (no plus)
        T![<] => path_type_(p, allow_bounds),
        _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds),
        _ => {
            p.err_recover("expected type", TYPE_RECOVERY_SET);
        }
    }
}

pub(super) fn ascription(p: &mut Parser) {
    p.expect(T![:]);
    type_(p)
}

fn paren_or_tuple_type(p: &mut Parser) {
    assert!(p.at(T!['(']));
    let m = p.start();
    p.bump(T!['(']);
    let mut n_types: u32 = 0;
    let mut trailing_comma: bool = false;
    while !p.at(EOF) && !p.at(T![')']) {
        n_types += 1;
        type_(p);
        if p.eat(T![,]) {
            trailing_comma = true;
        } else {
            trailing_comma = false;
            break;
        }
    }
    p.expect(T![')']);

    let kind = if n_types == 1 && !trailing_comma {
        // test paren_type
        // type T = (i32);
        PAREN_TYPE
    } else {
        // test unit_type
        // type T = ();

        // test singleton_tuple_type
        // type T = (i32,);
        TUPLE_TYPE
    };
    m.complete(p, kind);
}

// test never_type
// type Never = !;
fn never_type(p: &mut Parser) {
    assert!(p.at(T![!]));
    let m = p.start();
    p.bump(T![!]);
    m.complete(p, NEVER_TYPE);
}

fn pointer_type(p: &mut Parser) {
    assert!(p.at(T![*]));
    let m = p.start();
    p.bump(T![*]);

    match p.current() {
        // test pointer_type_mut
        // type M = *mut ();
        // type C = *mut ();
        T![mut] | T![const] => p.bump_any(),
        _ => {
            // test_err pointer_type_no_mutability
            // type T = *();
            p.error(
                "expected mut or const in raw pointer type \
                 (use `*mut T` or `*const T` as appropriate)",
            );
        }
    };

    type_no_bounds(p);
    m.complete(p, POINTER_TYPE);
}

fn array_or_slice_type(p: &mut Parser) {
    assert!(p.at(T!['[']));
    let m = p.start();
    p.bump(T!['[']);

    type_(p);
    let kind = match p.current() {
        // test slice_type
        // type T = [()];
        T![']'] => {
            p.bump(T![']']);
            SLICE_TYPE
        }

        // test array_type
        // type T = [(); 92];
        T![;] => {
            p.bump(T![;]);
            expressions::expr(p);
            p.expect(T![']']);
            ARRAY_TYPE
        }
        // test_err array_type_missing_semi
        // type T = [() 92];
        _ => {
            p.error("expected `;` or `]`");
            SLICE_TYPE
        }
    };
    m.complete(p, kind);
}

// test reference_type;
// type A = &();
// type B = &'static ();
// type C = &mut ();
fn reference_type(p: &mut Parser) {
    assert!(p.at(T![&]));
    let m = p.start();
    p.bump(T![&]);
    p.eat(LIFETIME);
    p.eat(T![mut]);
    type_no_bounds(p);
    m.complete(p, REFERENCE_TYPE);
}

// test placeholder_type
// type Placeholder = _;
fn placeholder_type(p: &mut Parser) {
    assert!(p.at(T![_]));
    let m = p.start();
    p.bump(T![_]);
    m.complete(p, PLACEHOLDER_TYPE);
}

// test fn_pointer_type
// type A = fn();
// type B = unsafe fn();
// type C = unsafe extern "C" fn();
// type D = extern "C" fn ( u8 , ... ) -> u8;
fn fn_pointer_type(p: &mut Parser) {
    let m = p.start();
    p.eat(T![unsafe]);
    if p.at(T![extern]) {
        abi(p);
    }
    // test_err fn_pointer_type_missing_fn
    // type F = unsafe ();
    if !p.eat(T![fn]) {
        m.abandon(p);
        p.error("expected `fn`");
        return;
    }
    if p.at(T!['(']) {
        params::param_list_opt_patterns(p);
    } else {
        p.error("expected parameters")
    }
    // test fn_pointer_type_with_ret
    // type F = fn() -> ();
    opt_fn_ret_type(p);
    m.complete(p, FN_POINTER_TYPE);
}

pub(super) fn for_binder(p: &mut Parser) {
    assert!(p.at(T![for]));
    p.bump(T![for]);
    if p.at(T![<]) {
        type_params::opt_type_param_list(p);
    } else {
        p.error("expected `<`");
    }
}

// test for_type
// type A = for<'a> fn() -> ();
// fn foo<T>(_t: &T) where for<'a> &'a T: Iterator {}
// fn bar<T>(_t: &T) where for<'a> &'a mut T: Iterator {}
// fn baz<T>(_t: &T) where for<'a> <&'a T as Baz>::Foo: Iterator {}
pub(super) fn for_type(p: &mut Parser) {
    assert!(p.at(T![for]));
    let m = p.start();
    for_binder(p);
    match p.current() {
        T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p),
        T![&] => reference_type(p),
        _ if paths::is_path_start(p) => path_type_(p, false),
        _ => p.error("expected a path"),
    }
    m.complete(p, FOR_TYPE);
}

// test impl_trait_type
// type A = impl Iterator<Item=Foo<'a>> + 'a;
fn impl_trait_type(p: &mut Parser) {
    assert!(p.at(T![impl]));
    let m = p.start();
    p.bump(T![impl]);
    type_params::bounds_without_colon(p);
    m.complete(p, IMPL_TRAIT_TYPE);
}

// test dyn_trait_type
// type A = dyn Iterator<Item=Foo<'a>> + 'a;
fn dyn_trait_type(p: &mut Parser) {
    assert!(p.at(T![dyn]));
    let m = p.start();
    p.bump(T![dyn]);
    type_params::bounds_without_colon(p);
    m.complete(p, DYN_TRAIT_TYPE);
}

// test path_type
// type A = Foo;
// type B = ::Foo;
// type C = self::Foo;
// type D = super::Foo;
pub(super) fn path_type(p: &mut Parser) {
    path_type_(p, true)
}

// test macro_call_type
// type A = foo!();
// type B = crate::foo!();
fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::type_path(p);

    let kind = if p.at(T![!]) && !p.at(T![!=]) {
        items::macro_call_after_excl(p);
        MACRO_CALL
    } else {
        PATH_TYPE
    };

    let path = m.complete(p, kind);

    if allow_bounds {
        opt_path_type_bounds_as_dyn_trait_type(p, path);
    }
}

pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::type_path(p);

    // test path_type_with_bounds
    // fn foo() -> Box<T + 'f> {}
    // fn foo() -> Box<dyn T + 'f> {}
    let path = m.complete(p, PATH_TYPE);
    if allow_bounds {
        opt_path_type_bounds_as_dyn_trait_type(p, path);
    }
}

/// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE
/// with a TYPE_BOUND_LIST
fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) {
    if !p.at(T![+]) {
        return;
    }

    // First create a TYPE_BOUND from the completed PATH_TYPE
    let m = path_type_marker.precede(p).complete(p, TYPE_BOUND);

    // Next setup a marker for the TYPE_BOUND_LIST
    let m = m.precede(p);

    // This gets consumed here so it gets properly set
    // in the TYPE_BOUND_LIST
    p.eat(T![+]);

    // Parse rest of the bounds into the TYPE_BOUND_LIST
    let m = type_params::bounds_without_colon_m(p, m);

    // Finally precede everything with DYN_TRAIT_TYPE
    m.precede(p).complete(p, DYN_TRAIT_TYPE);
}
<|endoftext|>