<commit_before>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::Type;

#[test]
fn test_mut_self() {
    syn::parse_str::<Type>("fn(mut self)").unwrap();
    syn::parse_str::<Type>("fn(mut self: ())").unwrap();
    syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self::T)").unwrap_err();
}

#[test]
fn test_macro_variable_type() {
    // mimics the token stream corresponding to `$ty<T>`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
        TokenTree::Punct(Punct::new('<', Spacing::Alone)),
        TokenTree::Ident(Ident::new("T", Span::call_site())),
        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
    ]);

    snapshot!(tokens as Type, @r###"
    Type::Path {
        path: Path {
            segments: [
                PathSegment {
                    ident: "ty",
                    arguments: PathArguments::AngleBracketed {
                        args: [
                            Type(Type::Path {
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "T",
                                            arguments: None,
                                        },
                                    ],
                                },
                            }),
                        ],
                    },
                },
            ],
        },
    }
    "###);
}
<commit_msg>Add test of path type wrapped in None-delimited group<commit_after>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::Type;

#[test]
fn test_mut_self() {
    syn::parse_str::<Type>("fn(mut self)").unwrap();
    syn::parse_str::<Type>("fn(mut self: ())").unwrap();
    syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self::T)").unwrap_err();
}

#[test]
fn test_macro_variable_type() {
    // mimics the token stream corresponding to `$ty<T>`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
        TokenTree::Punct(Punct::new('<', Spacing::Alone)),
        TokenTree::Ident(Ident::new("T", Span::call_site())),
        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
    ]);

    snapshot!(tokens as Type, @r###"
    Type::Path {
        path: Path {
            segments: [
                PathSegment {
                    ident: "ty",
                    arguments: PathArguments::AngleBracketed {
                        args: [
                            Type(Type::Path {
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "T",
                                            arguments: None,
                                        },
                                    ],
                                },
                            }),
                        ],
                    },
                },
            ],
        },
    }
    "###);
}

#[test]
fn test_group_angle_brackets() {
    // mimics the token stream corresponding to `Option<$ty>`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("Option", Span::call_site())),
        TokenTree::Punct(Punct::new('<', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })),
        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
    ]);

    snapshot!(tokens as Type, @r###"
    Type::Path {
        path: Path {
            segments: [
                PathSegment {
                    ident: "Option",
                    arguments: PathArguments::AngleBracketed {
                        args: [
                            Type(Type::Path {
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "Vec",
                                            arguments: PathArguments::AngleBracketed {
                                                args: [
                                                    Type(Type::Path {
                                                        path: Path {
                                                            segments: [
                                                                PathSegment {
                                                                    ident: "u8",
                                                                    arguments: None,
                                                                },
                                                            ],
                                                        },
                                                    }),
                                                ],
                                            },
                                        },
                                    ],
                                },
                            }),
                        ],
                    },
                },
            ],
        },
    }
    "###);
}
<|endoftext|>


<commit_before>use std::env;
use std::error;
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// WorkDir represents a directory in which tests are run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Debug)]
pub struct WorkDir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here.
    dir: PathBuf,
}

impl WorkDir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> WorkDir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe().unwrap()
            .parent().expect("executable's directory").to_path_buf();
        let dir = root.join(TEST_DIR).join(name).join(&format!("{}", id));
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        WorkDir {
            root: root,
            dir: dir,
        }
    }

    /// Create a new file with the given name and contents in this directory, or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this directory.
    pub fn try_create<P: AsRef<Path>>(&self, name: P, contents: &str) -> io::Result<()> {
        self.try_create_bytes(name, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory, or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(name);
        nice_err(&path, self.try_create_bytes(&path, contents));
    }

    /// Try to create a new file with the given name and contents in this directory.
    fn try_create_bytes<P: AsRef<Path>>(&self, path: P, contents: &[u8]) -> io::Result<()> {
        let mut file = File::create(&path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    pub fn command(&self) -> process::Command {
        let mut cmd = process::Command::new(&self.bin());
        cmd.current_dir(&self.dir);
        cmd
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(not(windows))]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg")
        } else {
            path
        }
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(windows)]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg.exe");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg.exe")
        } else {
            path
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }

    /// Runs and captures the stdout of the given command.
    ///
    /// If the return type could not be created from a string, then this
    /// panics.
    pub fn stdout<E: fmt::Debug, T: FromStr<Err=E>>(
        &self,
        cmd: &mut process::Command,
    ) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!("could not convert from string: {:?}\n\n{}", err, stdout);
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        let output = cmd.output().unwrap();
        self.expect_success(cmd, output)
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(
        &self,
        cmd: &mut process::Command,
        input: &str
    ) -> process::Output {
        cmd.stdin(process::Stdio::piped());
        cmd.stdout(process::Stdio::piped());
        cmd.stderr(process::Stdio::piped());

        let mut child = cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || {
            write!(stdin, "{}", input)
        });

        let output = self.expect_success(cmd, child.wait_with_output().unwrap());
        worker.join().unwrap().unwrap();
        output
    }

    /// If `o` is not the output of a successful process run
    fn expect_success(
        &self,
        cmd: &process::Command,
        o: process::Output
    ) -> process::Output {
        if !o.status.success() {
            let suggest =
                if o.stderr.is_empty() {
                    "\n\nDid your search end up with no results?".to_string()
                } else {
                    "".to_string()
                };

            panic!("\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                   suggest, cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
        o
    }

    /// Runs the given command and asserts that it resulted in an error exit
    /// code.
    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    /// Runs the given command and asserts that something was printed to
    /// stderr.
    pub fn assert_non_empty_stderr(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }
}

fn nice_err<P: AsRef<Path>, T, E: error::Error>(
    path: P,
    res: Result<T, E>,
) -> T {
    match res {
        Ok(t) => t,
        Err(err) => {
            panic!("{}: {:?}", path.as_ref().display(), err);
        }
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}
<commit_msg>Wrap comments to 79 columns<commit_after>use std::env;
use std::error;
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// WorkDir represents a directory in which tests are run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Debug)]
pub struct WorkDir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here.
    dir: PathBuf,
}

impl WorkDir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> WorkDir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe().unwrap()
            .parent().expect("executable's directory").to_path_buf();
        let dir = root.join(TEST_DIR).join(name).join(&format!("{}", id));
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        WorkDir {
            root: root,
            dir: dir,
        }
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    pub fn try_create<P: AsRef<Path>>(&self, name: P, contents: &str) -> io::Result<()> {
        self.try_create_bytes(name, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(name);
        nice_err(&path, self.try_create_bytes(&path, contents));
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    fn try_create_bytes<P: AsRef<Path>>(&self, path: P, contents: &[u8]) -> io::Result<()> {
        let mut file = File::create(&path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    pub fn command(&self) -> process::Command {
        let mut cmd = process::Command::new(&self.bin());
        cmd.current_dir(&self.dir);
        cmd
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(not(windows))]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg")
        } else {
            path
        }
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(windows)]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg.exe");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg.exe")
        } else {
            path
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }

    /// Runs and captures the stdout of the given command.
    ///
    /// If the return type could not be created from a string, then this
    /// panics.
    pub fn stdout<E: fmt::Debug, T: FromStr<Err=E>>(
        &self,
        cmd: &mut process::Command,
    ) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!("could not convert from string: {:?}\n\n{}", err, stdout);
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        let output = cmd.output().unwrap();
        self.expect_success(cmd, output)
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(
        &self,
        cmd: &mut process::Command,
        input: &str
    ) -> process::Output {
        cmd.stdin(process::Stdio::piped());
        cmd.stdout(process::Stdio::piped());
        cmd.stderr(process::Stdio::piped());

        let mut child = cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || {
            write!(stdin, "{}", input)
        });

        let output = self.expect_success(cmd, child.wait_with_output().unwrap());
        worker.join().unwrap().unwrap();
        output
    }

    /// If `o` is not the output of a successful process run
    fn expect_success(
        &self,
        cmd: &process::Command,
        o: process::Output
    ) -> process::Output {
        if !o.status.success() {
            let suggest =
                if o.stderr.is_empty() {
                    "\n\nDid your search end up with no results?".to_string()
                } else {
                    "".to_string()
                };

            panic!("\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                   suggest, cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
        o
    }

    /// Runs the given command and asserts that it resulted in an error exit
    /// code.
    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    /// Runs the given command and asserts that something was printed to
    /// stderr.
    pub fn assert_non_empty_stderr(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }
}

fn nice_err<P: AsRef<Path>, T, E: error::Error>(
    path: P,
    res: Result<T, E>,
) -> T {
    match res {
        Ok(t) => t,
        Err(err) => {
            panic!("{}: {:?}", path.as_ref().display(), err);
        }
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}
<|endoftext|>


<commit_before>//! JSON and serialization
//!
//! # What is JSON?
//!
//! JSON (JavaScript Object Notation) is a way to write data in JavaScript.  Like XML, it allows to
//! encode structured data in a text format that can be easily read by humans.  Its simple syntax
//! and native compatibility with JavaScript have made it a widely used format.
//!
//! Data types that can be encoded are JavaScript types (see the `serde_json:Value` enum for more
//! details):
//!
//! * `Bool`: equivalent to rust's `bool`
//! * `I64`: equivalent to rust's `i64`
//! * `U64`: equivalent to rust's `u64`
//! * `F64`: equivalent to rust's `f64`
//! * `String`: equivalent to rust's `String`
//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
//!    same array
//! * `Object`: equivalent to rust's `BTreeMap<String, serde_json::Value>`; set the
//!    `preserve_order` feature to use `LinkedHashMap<String, serde_json::Value>` instead
//! * `Null`
//!
//! An object is a series of string keys mapping to values, in `"key": value` format.  Arrays are
//! enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).  A simple JSON
//! document encoding a person, his/her age, address and phone numbers could look like
//!
//! ```ignore
//! {
//!     "FirstName": "John",
//!     "LastName": "Doe",
//!     "Age": 43,
//!     "Address": {
//!         "Street": "Downing Street 10",
//!         "City": "London",
//!         "Country": "Great Britain"
//!     },
//!     "PhoneNumbers": [
//!         "+44 1234567",
//!         "+44 2345678"
//!     ]
//! }
//! ```
//!
//! If we assume that `FirstName` is optional and all other fields are mandatory, the above JSON could
//! correspond to the following Rust structs:
//!
//! ```ignore
//! #[derive(Serialize, Deserialize)]
//! struct Data {
//!     #[serde(rename="FirstName")] // to comply with Rust coding standards
//!     first_name: Option<String>,
//!     LastName: String,
//!     Age: u32,
//!     Address: Address,
//!     PhoneNumbers: Vec<String>,
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! struct Address {
//!     Street: String,
//!     City: String,
//!     Country: String,
//! }
//! ```
//!
//! # Type-based Serialization and Deserialization
//!
//! Serde provides a mechanism for low boilerplate serialization & deserialization of values to and
//! from JSON via the serialization API.  To be able to serialize a piece of data, it must implement
//! the `serde::Serialize` trait.  To be able to deserialize a piece of data, it must implement the
//! `serde::Deserialize` trait.  Serde provides provides an annotation to automatically generate
//! the code for these traits: `#[derive(Serialize, Deserialize)]`.
//!
//! The JSON API also provides an enum `serde_json::Value` and a method `to_value` to serialize
//! objects.  A `serde_json::Value` value can be serialized as a string or buffer using the
//! functions described above.  You can also use the `json::Serializer` object, which implements the
//! `Serializer` trait.
//!
//! # Examples of use
//!
//! ## Parsing a `str` to `Value` and reading the result
//!
//! ```rust
//! extern crate serde_json;
//!
//! use serde_json::Value;
//!
//! fn main() {
//!     let data: Value = serde_json::from_str("{\"foo\": 13, \"bar\": \"baz\"}").unwrap();
//!     println!("data: {:?}", data);
//!     // data: {"bar":"baz","foo":13}
//!     println!("object? {}", data.is_object());
//!     // object? true
//!
//!     let obj = data.as_object().unwrap();
//!     let foo = obj.get("foo").unwrap();
//!
//!     println!("array? {:?}", foo.as_array());
//!     // array? None
//!     println!("u64? {:?}", foo.as_u64());
//!     // u64? Some(13u64)
//!
//!     for (key, value) in obj.iter() {
//!         println!("{}: {}", key, match *value {
//!             Value::Number(ref v) => format!("{} (number)", v),
//!             Value::String(ref v) => format!("{} (string)", v),
//!             _ => format!("other")
//!         });
//!     }
//!     // bar: baz (string)
//!     // foo: 13 (u64)
//! }
//! ```

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", deny(clippy, clippy_pedantic))]
// Because of "JavaScript"... fixed in Manishearth/rust-clippy#1071
#![cfg_attr(feature = "clippy", allow(doc_markdown))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "clippy", allow(
// integer and float ser/de requires these sorts of casts
    cast_possible_truncation,
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
// string ser/de uses indexing and slicing
    indexing_slicing,
// things are often more readable this way
    shadow_reuse,
    shadow_unrelated,
    single_match_else,
    stutter,
// not practical
    missing_docs_in_private_items,
))]

#![deny(missing_docs)]

extern crate num_traits;
extern crate core;
#[macro_use]
extern crate serde;
extern crate itoa;
extern crate dtoa;
#[cfg(feature = "preserve_order")]
extern crate linked_hash_map;

pub use self::de::{Deserializer, StreamDeserializer, from_iter, from_reader,
                   from_slice, from_str};
pub use self::error::{Error, ErrorCode, Result};
pub use self::ser::{Serializer, escape_str, to_string, to_string_pretty,
                    to_vec, to_vec_pretty, to_writer, to_writer_pretty};
pub use self::value::{Map, Number, Value, from_value, to_value};

pub mod builder;
pub mod de;
pub mod error;
pub mod ser;
pub mod value;

mod map;
mod number;
mod read;
<commit_msg>Whitelist should_implement_trait<commit_after>//! JSON and serialization
//!
//! # What is JSON?
//!
//! JSON (JavaScript Object Notation) is a way to write data in JavaScript.  Like XML, it allows to
//! encode structured data in a text format that can be easily read by humans.  Its simple syntax
//! and native compatibility with JavaScript have made it a widely used format.
//!
//! Data types that can be encoded are JavaScript types (see the `serde_json:Value` enum for more
//! details):
//!
//! * `Bool`: equivalent to rust's `bool`
//! * `I64`: equivalent to rust's `i64`
//! * `U64`: equivalent to rust's `u64`
//! * `F64`: equivalent to rust's `f64`
//! * `String`: equivalent to rust's `String`
//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
//!    same array
//! * `Object`: equivalent to rust's `BTreeMap<String, serde_json::Value>`; set the
//!    `preserve_order` feature to use `LinkedHashMap<String, serde_json::Value>` instead
//! * `Null`
//!
//! An object is a series of string keys mapping to values, in `"key": value` format.  Arrays are
//! enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).  A simple JSON
//! document encoding a person, his/her age, address and phone numbers could look like
//!
//! ```ignore
//! {
//!     "FirstName": "John",
//!     "LastName": "Doe",
//!     "Age": 43,
//!     "Address": {
//!         "Street": "Downing Street 10",
//!         "City": "London",
//!         "Country": "Great Britain"
//!     },
//!     "PhoneNumbers": [
//!         "+44 1234567",
//!         "+44 2345678"
//!     ]
//! }
//! ```
//!
//! If we assume that `FirstName` is optional and all other fields are mandatory, the above JSON could
//! correspond to the following Rust structs:
//!
//! ```ignore
//! #[derive(Serialize, Deserialize)]
//! struct Data {
//!     #[serde(rename="FirstName")] // to comply with Rust coding standards
//!     first_name: Option<String>,
//!     LastName: String,
//!     Age: u32,
//!     Address: Address,
//!     PhoneNumbers: Vec<String>,
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! struct Address {
//!     Street: String,
//!     City: String,
//!     Country: String,
//! }
//! ```
//!
//! # Type-based Serialization and Deserialization
//!
//! Serde provides a mechanism for low boilerplate serialization & deserialization of values to and
//! from JSON via the serialization API.  To be able to serialize a piece of data, it must implement
//! the `serde::Serialize` trait.  To be able to deserialize a piece of data, it must implement the
//! `serde::Deserialize` trait.  Serde provides provides an annotation to automatically generate
//! the code for these traits: `#[derive(Serialize, Deserialize)]`.
//!
//! The JSON API also provides an enum `serde_json::Value` and a method `to_value` to serialize
//! objects.  A `serde_json::Value` value can be serialized as a string or buffer using the
//! functions described above.  You can also use the `json::Serializer` object, which implements the
//! `Serializer` trait.
//!
//! # Examples of use
//!
//! ## Parsing a `str` to `Value` and reading the result
//!
//! ```rust
//! extern crate serde_json;
//!
//! use serde_json::Value;
//!
//! fn main() {
//!     let data: Value = serde_json::from_str("{\"foo\": 13, \"bar\": \"baz\"}").unwrap();
//!     println!("data: {:?}", data);
//!     // data: {"bar":"baz","foo":13}
//!     println!("object? {}", data.is_object());
//!     // object? true
//!
//!     let obj = data.as_object().unwrap();
//!     let foo = obj.get("foo").unwrap();
//!
//!     println!("array? {:?}", foo.as_array());
//!     // array? None
//!     println!("u64? {:?}", foo.as_u64());
//!     // u64? Some(13u64)
//!
//!     for (key, value) in obj.iter() {
//!         println!("{}: {}", key, match *value {
//!             Value::Number(ref v) => format!("{} (number)", v),
//!             Value::String(ref v) => format!("{} (string)", v),
//!             _ => format!("other")
//!         });
//!     }
//!     // bar: baz (string)
//!     // foo: 13 (u64)
//! }
//! ```

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", deny(clippy, clippy_pedantic))]
// Because of "JavaScript"... fixed in Manishearth/rust-clippy#1071
#![cfg_attr(feature = "clippy", allow(doc_markdown))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "clippy", allow(
// Deserializer::from_str, from_iter, into_iter
    should_implement_trait,
// integer and float ser/de requires these sorts of casts
    cast_possible_truncation,
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
// string ser/de uses indexing and slicing
    indexing_slicing,
// things are often more readable this way
    shadow_reuse,
    shadow_unrelated,
    single_match_else,
    stutter,
// not practical
    missing_docs_in_private_items,
))]

#![deny(missing_docs)]

extern crate num_traits;
extern crate core;
#[macro_use]
extern crate serde;
extern crate itoa;
extern crate dtoa;
#[cfg(feature = "preserve_order")]
extern crate linked_hash_map;

pub use self::de::{Deserializer, StreamDeserializer, from_iter, from_reader,
                   from_slice, from_str};
pub use self::error::{Error, ErrorCode, Result};
pub use self::ser::{Serializer, escape_str, to_string, to_string_pretty,
                    to_vec, to_vec_pretty, to_writer, to_writer_pretty};
pub use self::value::{Map, Number, Value, from_value, to_value};

pub mod builder;
pub mod de;
pub mod error;
pub mod ser;
pub mod value;

mod map;
mod number;
mod read;
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::apply_transforms::Programs;
use crate::config::ConfigProject;
use crate::errors::BuildProjectError;
use graphql_ir::FragmentDefinition;
use graphql_text_printer::print_full_operation;
use interner::StringKey;
use persist_query::persist;
use signedsource::{sign_file, SIGNING_TOKEN};

/// Represents a generated output artifact.
pub struct Artifact {
    pub name: StringKey,
    pub content: String,
}

pub async fn generate_artifacts(
    project_config: &ConfigProject,
    programs: &Programs<'_>,
) -> Result<Vec<Artifact>, BuildProjectError> {
    let mut artifacts = Vec::new();
    for node in programs.normalization.operations() {
        let name = node.name.item;
        let print_operation_node = programs
            .operation_text
            .operation(name)
            .expect("a query text operation should be generated for this operation");
        let text = print_full_operation(&programs.operation_text, print_operation_node);
        let id = if let Some(ref persist_config) = project_config.persist {
            persist(&text, &persist_config.url, &persist_config.params)
                .await
                .map_err(BuildProjectError::PersistError)?
        } else {
            "null".to_string()
        };
        let reader_operation = programs
            .reader
            .operation(name)
            .expect("a reader fragment should be generated for this operation");
        let operation_fragment = FragmentDefinition {
            name: reader_operation.name,
            variable_definitions: reader_operation.variable_definitions.clone(),
            selections: reader_operation.selections.clone(),
            used_global_variables: Default::default(),
            directives: reader_operation.directives.clone(),
            type_condition: reader_operation.type_,
        };
        artifacts.push(Artifact {
            name,
            content: sign_file(&format!(
                "// {}\n\nconst request = {};\n\nconst text = `{}`;\n\nconst id = '{}';\n",
                SIGNING_TOKEN,
                relay_codegen::print_request_deduped(
                    programs.normalization.schema(),
                    node,
                    &operation_fragment,
                ),
                text,
                id,
            )),
        });
    }
    for node in programs.reader.fragments() {
        artifacts.push(Artifact {
            name: node.name.item,
            content: sign_file(&format!(
                "// {}\n\nconst fragment = {};\n",
                SIGNING_TOKEN,
                relay_codegen::print_fragment_deduped(programs.normalization.schema(), node),
            )),
        });
    }

    Ok(artifacts)
}
<commit_msg>re-order generated file output<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::apply_transforms::Programs;
use crate::config::ConfigProject;
use crate::errors::BuildProjectError;
use graphql_ir::FragmentDefinition;
use graphql_text_printer::print_full_operation;
use interner::StringKey;
use persist_query::persist;
use signedsource::{sign_file, SIGNING_TOKEN};

/// Represents a generated output artifact.
pub struct Artifact {
    pub name: StringKey,
    pub content: String,
}

pub async fn generate_artifacts(
    project_config: &ConfigProject,
    programs: &Programs<'_>,
) -> Result<Vec<Artifact>, BuildProjectError> {
    let mut artifacts = Vec::new();
    for node in programs.normalization.operations() {
        let name = node.name.item;
        let print_operation_node = programs
            .operation_text
            .operation(name)
            .expect("a query text operation should be generated for this operation");
        let text = print_full_operation(&programs.operation_text, print_operation_node);
        let id = if let Some(ref persist_config) = project_config.persist {
            persist(&text, &persist_config.url, &persist_config.params)
                .await
                .map_err(BuildProjectError::PersistError)?
        } else {
            "null".to_string()
        };
        let reader_operation = programs
            .reader
            .operation(name)
            .expect("a reader fragment should be generated for this operation");
        let operation_fragment = FragmentDefinition {
            name: reader_operation.name,
            variable_definitions: reader_operation.variable_definitions.clone(),
            selections: reader_operation.selections.clone(),
            used_global_variables: Default::default(),
            directives: reader_operation.directives.clone(),
            type_condition: reader_operation.type_,
        };
        artifacts.push(Artifact {
            name,
            content: sign_file(&format!(
                "// {}\n\n/*\n{}\n*/\n\nvar node/*: ConcreteRequest*/ = {};\n\nconst id = '{}';\n",
                SIGNING_TOKEN,
                text,
                relay_codegen::print_request_deduped(
                    programs.normalization.schema(),
                    node,
                    &operation_fragment,
                ),
                id,
            )),
        });
    }
    for node in programs.reader.fragments() {
        artifacts.push(Artifact {
            name: node.name.item,
            content: sign_file(&format!(
                "// {}\n\nconst fragment = {};\n",
                SIGNING_TOKEN,
                relay_codegen::print_fragment_deduped(programs.normalization.schema(), node),
            )),
        });
    }

    Ok(artifacts)
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate rusttype;
extern crate arrayvec;
extern crate unicode_normalization;

use glium::{DisplayBuild, Surface};
use glium::glutin;

use rusttype::{FontCollection, Font, Scale, point, vector, PositionedGlyph};
use rusttype::gpu_cache::{Cache};
use rusttype::Rect;

use std::borrow::Cow;

fn layout_paragraph<'a>(font: &'a Font,
                        scale: Scale,
                        width: u32,
                        text: &str) -> Vec<PositionedGlyph<'a>> {
    use unicode_normalization::UnicodeNormalization;
    let mut result = Vec::new();
    let v_metrics = font.v_metrics(scale);
    let advance_height = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;
    let mut caret = point(0.0, v_metrics.ascent);
    let mut last_glyph_id = None;
    for c in text.nfc() {
        if c.is_control() {
            match c {
                '\r' => {
                    caret = point(0.0, caret.y + advance_height);
                }
                '\n' => {},
                _ => {}
            }
            continue;
        }
        let base_glyph = if let Some(glyph) = font.glyph(c) {
            glyph
        } else {
            continue;
        };
        if let Some(id) = last_glyph_id.take() {
            caret.x += font.pair_kerning(scale, id, base_glyph.id());
        }
        last_glyph_id = Some(base_glyph.id());
        let mut glyph = base_glyph.scaled(scale).positioned(caret);
        if let Some(bb) = glyph.pixel_bounding_box() {
            if bb.max.x > width as i32 {
                caret = point(0.0, caret.y + advance_height);
                glyph = glyph.into_unpositioned().positioned(caret);
                last_glyph_id = None;
            }
        }
        caret.x += glyph.unpositioned().h_metrics().advance_width;
        result.push(glyph);
    }
    result
}

fn main() {
    let font_data = include_bytes!("Arial Unicode.ttf");
    let font = FontCollection::from_bytes(font_data as &[u8]).into_font().unwrap();

    let display = glutin::WindowBuilder::new()
        .with_vsync()
        .with_dimensions(512, 512)
        .with_title("RustType GPU cache example".into())
        .build_glium()
        .unwrap();

    let dpi_factor = display.get_window().unwrap().hidpi_factor();

    let (cache_width, cache_height) = (512 * dpi_factor as u32, 512 * dpi_factor as u32);
    let mut cache = Cache::new(cache_width, cache_height, 0.1, 0.1);

    let program = program!(
        &display,
        140 => {
            vertex: "
                #version 140

                in vec2 position;
                in vec2 tex_coords;
                in vec4 colour;

                out vec2 v_tex_coords;
                out vec4 v_colour;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0);
                    v_tex_coords = tex_coords;
                    v_colour = colour;
                }
            ",

            fragment: "
                #version 140
                uniform sampler2D tex;
                in vec2 v_tex_coords;
                in vec4 v_colour;
                out vec4 f_colour;

                void main() {
                    f_colour = v_colour * vec4(1.0, 1.0, 1.0, texture(tex, v_tex_coords).r);
                }
            "
        }).unwrap();
    let cache_tex = glium::texture::Texture2d::with_format(
        &display,
        glium::texture::RawImage2d {
            data: Cow::Owned(vec![128u8; cache_width as usize * cache_height as usize]),
            width: cache_width,
            height: cache_height,
            format: glium::texture::ClientFormat::U8
        },
        glium::texture::UncompressedFloatFormat::U8,
        glium::texture::MipmapsOption::NoMipmap).unwrap();
    let mut text: String = "A japanese poem:\r
\r
色は匂へど散りぬるを我が世誰ぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず\r
\r
Feel free to type out some text, and delete it with Backspace. You can also try resizing this window."
        .into();
    'main: loop {
        let width = display.get_window().unwrap().get_inner_size_pixels().unwrap().0;
        let glyphs = layout_paragraph(&font, Scale::uniform(24.0 * dpi_factor), width, &text);
        for glyph in &glyphs {
            cache.queue_glyph(0, glyph.clone());
        }
        cache.cache_queued(|rect, data| {
            cache_tex.main_level().write(glium::Rect {
                left: rect.min.x,
                bottom: rect.min.y,
                width: rect.width(),
                height: rect.height()
            }, glium::texture::RawImage2d {
                data: Cow::Borrowed(data),
                width: rect.width(),
                height: rect.height(),
                format: glium::texture::ClientFormat::U8
            });
        }).unwrap();

        let uniforms = uniform! {
            tex: cache_tex.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
        };

        let vertex_buffer = {
            #[derive(Copy, Clone)]
            struct Vertex {
                position: [f32; 2],
                tex_coords: [f32; 2],
                colour: [f32; 4]
            }

            implement_vertex!(Vertex, position, tex_coords, colour);
            let colour = [0.0, 0.0, 0.0, 1.0];
            let (screen_width, screen_height) = {
                let (w, h) = display.get_framebuffer_dimensions();
                (w as f32, h as f32)
            };
            let origin = point(0.0, 0.0);
            let vertices: Vec<Vertex> = glyphs.iter().flat_map(|g| {
                if let Ok(Some((uv_rect, screen_rect))) = cache.rect_for(0, g) {
                    let gl_rect = Rect {
                        min: origin
                            + (vector(screen_rect.min.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.min.y as f32 / screen_height - 0.5)) * 2.0,
                        max: origin
                            + (vector(screen_rect.max.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.max.y as f32 / screen_height - 0.5)) * 2.0
                    };
                    arrayvec::ArrayVec::<[Vertex; 6]>::from([
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.min.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour },
                        Vertex {
                            position: [gl_rect.max.x, gl_rect.max.y],
                            tex_coords: [uv_rect.max.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        }])
                } else {
                    arrayvec::ArrayVec::new()
                }
            }).collect();

            glium::VertexBuffer::new(
                &display,
                &vertices).unwrap()
        };

        let mut target = display.draw();
        target.clear_color(1.0, 1.0, 1.0, 0.0);
        target.draw(&vertex_buffer,
                    glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms,
                    &glium::DrawParameters {
                        blend: glium::Blend::alpha_blending(),
                        ..Default::default()
                    }).unwrap();

        target.finish().unwrap();

        for event in display.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                glutin::Event::ReceivedCharacter(c) => if c != '\u{7f}' && c != '\u{8}' {
                    text.push(c);
                },
                glutin::Event::KeyboardInput(
                    glutin::ElementState::Pressed,
                    _,
                    Some(glutin::VirtualKeyCode::Back)) => {
                    text.pop();
                },
                _ => {}
            }
        }
    }
}
<commit_msg>Ensure that gpu_cache.rs example always uses current DPI factor.<commit_after>#[macro_use]
extern crate glium;
extern crate rusttype;
extern crate arrayvec;
extern crate unicode_normalization;

use glium::{DisplayBuild, Surface};
use glium::glutin;

use rusttype::{FontCollection, Font, Scale, point, vector, PositionedGlyph};
use rusttype::gpu_cache::{Cache};
use rusttype::Rect;

use std::borrow::Cow;

fn layout_paragraph<'a>(font: &'a Font,
                        scale: Scale,
                        width: u32,
                        text: &str) -> Vec<PositionedGlyph<'a>> {
    use unicode_normalization::UnicodeNormalization;
    let mut result = Vec::new();
    let v_metrics = font.v_metrics(scale);
    let advance_height = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;
    let mut caret = point(0.0, v_metrics.ascent);
    let mut last_glyph_id = None;
    for c in text.nfc() {
        if c.is_control() {
            match c {
                '\r' => {
                    caret = point(0.0, caret.y + advance_height);
                }
                '\n' => {},
                _ => {}
            }
            continue;
        }
        let base_glyph = if let Some(glyph) = font.glyph(c) {
            glyph
        } else {
            continue;
        };
        if let Some(id) = last_glyph_id.take() {
            caret.x += font.pair_kerning(scale, id, base_glyph.id());
        }
        last_glyph_id = Some(base_glyph.id());
        let mut glyph = base_glyph.scaled(scale).positioned(caret);
        if let Some(bb) = glyph.pixel_bounding_box() {
            if bb.max.x > width as i32 {
                caret = point(0.0, caret.y + advance_height);
                glyph = glyph.into_unpositioned().positioned(caret);
                last_glyph_id = None;
            }
        }
        caret.x += glyph.unpositioned().h_metrics().advance_width;
        result.push(glyph);
    }
    result
}

fn main() {
    let font_data = include_bytes!("Arial Unicode.ttf");
    let font = FontCollection::from_bytes(font_data as &[u8]).into_font().unwrap();

    let display = glutin::WindowBuilder::new()
        .with_vsync()
        .with_dimensions(512, 512)
        .with_title("RustType GPU cache example".into())
        .build_glium()
        .unwrap();

    let dpi_factor = display.get_window().unwrap().hidpi_factor();

    let (cache_width, cache_height) = (512 * dpi_factor as u32, 512 * dpi_factor as u32);
    let mut cache = Cache::new(cache_width, cache_height, 0.1, 0.1);

    let program = program!(
        &display,
        140 => {
            vertex: "
                #version 140

                in vec2 position;
                in vec2 tex_coords;
                in vec4 colour;

                out vec2 v_tex_coords;
                out vec4 v_colour;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0);
                    v_tex_coords = tex_coords;
                    v_colour = colour;
                }
            ",

            fragment: "
                #version 140
                uniform sampler2D tex;
                in vec2 v_tex_coords;
                in vec4 v_colour;
                out vec4 f_colour;

                void main() {
                    f_colour = v_colour * vec4(1.0, 1.0, 1.0, texture(tex, v_tex_coords).r);
                }
            "
        }).unwrap();
    let cache_tex = glium::texture::Texture2d::with_format(
        &display,
        glium::texture::RawImage2d {
            data: Cow::Owned(vec![128u8; cache_width as usize * cache_height as usize]),
            width: cache_width,
            height: cache_height,
            format: glium::texture::ClientFormat::U8
        },
        glium::texture::UncompressedFloatFormat::U8,
        glium::texture::MipmapsOption::NoMipmap).unwrap();
    let mut text: String = "A japanese poem:\r
\r
色は匂へど散りぬるを我が世誰ぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず\r
\r
Feel free to type out some text, and delete it with Backspace. You can also try resizing this window."
        .into();
    'main: loop {
        let (width, dpi_factor) = {
            let window = display.get_window().unwrap();
            (window.get_inner_size_pixels().unwrap().0, window.hidpi_factor())
        };
        let glyphs = layout_paragraph(&font, Scale::uniform(24.0 * dpi_factor), width, &text);
        for glyph in &glyphs {
            cache.queue_glyph(0, glyph.clone());
        }
        cache.cache_queued(|rect, data| {
            cache_tex.main_level().write(glium::Rect {
                left: rect.min.x,
                bottom: rect.min.y,
                width: rect.width(),
                height: rect.height()
            }, glium::texture::RawImage2d {
                data: Cow::Borrowed(data),
                width: rect.width(),
                height: rect.height(),
                format: glium::texture::ClientFormat::U8
            });
        }).unwrap();

        let uniforms = uniform! {
            tex: cache_tex.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
        };

        let vertex_buffer = {
            #[derive(Copy, Clone)]
            struct Vertex {
                position: [f32; 2],
                tex_coords: [f32; 2],
                colour: [f32; 4]
            }

            implement_vertex!(Vertex, position, tex_coords, colour);
            let colour = [0.0, 0.0, 0.0, 1.0];
            let (screen_width, screen_height) = {
                let (w, h) = display.get_framebuffer_dimensions();
                (w as f32, h as f32)
            };
            let origin = point(0.0, 0.0);
            let vertices: Vec<Vertex> = glyphs.iter().flat_map(|g| {
                if let Ok(Some((uv_rect, screen_rect))) = cache.rect_for(0, g) {
                    let gl_rect = Rect {
                        min: origin
                            + (vector(screen_rect.min.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.min.y as f32 / screen_height - 0.5)) * 2.0,
                        max: origin
                            + (vector(screen_rect.max.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.max.y as f32 / screen_height - 0.5)) * 2.0
                    };
                    arrayvec::ArrayVec::<[Vertex; 6]>::from([
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.min.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour },
                        Vertex {
                            position: [gl_rect.max.x, gl_rect.max.y],
                            tex_coords: [uv_rect.max.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        }])
                } else {
                    arrayvec::ArrayVec::new()
                }
            }).collect();

            glium::VertexBuffer::new(
                &display,
                &vertices).unwrap()
        };

        let mut target = display.draw();
        target.clear_color(1.0, 1.0, 1.0, 0.0);
        target.draw(&vertex_buffer,
                    glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms,
                    &glium::DrawParameters {
                        blend: glium::Blend::alpha_blending(),
                        ..Default::default()
                    }).unwrap();

        target.finish().unwrap();

        for event in display.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                glutin::Event::ReceivedCharacter(c) => if c != '\u{7f}' && c != '\u{8}' {
                    text.push(c);
                },
                glutin::Event::KeyboardInput(
                    glutin::ElementState::Pressed,
                    _,
                    Some(glutin::VirtualKeyCode::Back)) => {
                    text.pop();
                },
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>#[derive(PartialEq, Eq, Debug)]
struct Age(u8);

struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// This cannot be elided because Rust doesn't know to use lifetime of "a" or "b".
fn double_first_five<'a>(a: &'a String, b: &'a String) -> (&'a str, &'a str) {
    (&a[..5], &b[..5])
}

// Output borrows generally must have an input value from which it can borrow. The exception is
// the static lifetime.
// Couldn't Rust infer from the body of the function that the borrows are from the static lifetime?
//   - I feel that Rust favours explicitness over terseness. A functions behaviour should be
//   encoded directly into it's signature.
fn output_only<'a>() -> (&'static u8, &'static u8) {
    static X: u8 = 8;
    static Y: u8 = 9;

    (&X, &Y)
}

// Here we are promising Rust that all of the borrowed u8's
// live for the same scope.
// Q: Why do I need a lifetime here?
fn join_ages<'a, T: Iterator>(iters: T) -> Vec<&'a Age>
        where T::Item: IntoIterator<Item=&'a Age> {
    iters.flat_map(|b| b.into_iter())
         .collect()
}

fn multi_lifetimes<'a, 'b>(a: &'a u8, b: &'b u8) -> bool {
    (a + b) > 10
}

fn multiple_lifetimes() -> bool {
    let a = &9;

    {
        let b = &9;

        multi_lifetimes(a, b)
    }
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();
    let another = "Timothy".to_owned();
    let a = 43;
    let vec_ages = vec![vec![Age(90), Age(80)],
                        vec![Age(2)]];

    let arr_ages = vec![[Age(90), Age(80)],
                        [Age(2), Age(45)]];

    assert_eq!(output_only(), (&8, &9));

    assert_eq!(first_five(&name), "Andre");
    assert_eq!(double_first_five(&name, &another), ("Andre", "Timot"));

    assert!(multiple_lifetimes());

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_ages(vec_ages.iter()), vec![&Age(90), &Age(80), &Age(2)]);
    assert_eq!(join_ages(arr_ages.iter()), vec![&Age(90), &Age(80), &Age(2), &Age(45)]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Nor are you telling Rust to "allow" a binding to be available in a given named scope/lifetime.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - When we say "'a", we are talking about a scope in the calling environment.
// - Question: Why can't Rust ensure/infer/elide the struct scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<commit_msg>Multiple input lifetimes can also be elided<commit_after>#[derive(PartialEq, Eq, Debug)]
struct Age(u8);

struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// This cannot be elided because Rust doesn't know to use lifetime of "a" or "b".
fn double_first_five<'a>(a: &'a String, b: &'a String) -> (&'a str, &'a str) {
    (&a[..5], &b[..5])
}

// Output borrows generally must have an input value from which it can borrow. The exception is
// the static lifetime.
// Couldn't Rust infer from the body of the function that the borrows are from the static lifetime?
//   - I feel that Rust favours explicitness over terseness. A functions behaviour should be
//   encoded directly into it's signature.
fn output_only<'a>() -> (&'static u8, &'static u8) {
    static X: u8 = 8;
    static Y: u8 = 9;

    (&X, &Y)
}

// Here we are promising Rust that all of the borrowed u8's
// live for the same scope.
// Q: Why do I need a lifetime here?
fn join_ages<'a, T: Iterator>(iters: T) -> Vec<&'a Age>
        where T::Item: IntoIterator<Item=&'a Age> {
    iters.flat_map(|b| b.into_iter())
         .collect()
}

// This is not really necessary here. Both a and b could use the same lifetime
// as Rust only cares that a and b are available for the scope of this function.
// This could also be elided.
fn multi_lifetimes<'a, 'b>(a: &'a u8, b: &'b u8) -> bool {
    (a + b) > 10
}

fn multiple_lifetimes() -> bool {
    let a = &9;

    {
        let b = &9;

        multi_lifetimes(a, b)
    }
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();
    let another = "Timothy".to_owned();
    let a = 43;
    let vec_ages = vec![vec![Age(90), Age(80)],
                        vec![Age(2)]];

    let arr_ages = vec![[Age(90), Age(80)],
                        [Age(2), Age(45)]];

    assert_eq!(output_only(), (&8, &9));

    assert_eq!(first_five(&name), "Andre");
    assert_eq!(double_first_five(&name, &another), ("Andre", "Timot"));

    assert!(multiple_lifetimes());

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_ages(vec_ages.iter()), vec![&Age(90), &Age(80), &Age(2)]);
    assert_eq!(join_ages(arr_ages.iter()), vec![&Age(90), &Age(80), &Age(2), &Age(45)]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Nor are you telling Rust to "allow" a binding to be available in a given named scope/lifetime.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - When we say "'a", we are talking about a scope in the calling environment.
// - Question: Why can't Rust ensure/infer/elide the struct scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<|endoftext|>


<commit_before>#![no_std]

extern crate alloc;
extern crate lang_items;

use core::fmt::Write;
use libtock_drivers::console::Console;
use libtock_drivers::nfc::NfcTag;
use libtock_drivers::nfc::RecvOp;

#[allow(dead_code)]
/// Helper function to write a slice into a fixed
/// length transmission buffer.
fn write_tx_buffer(buf: &mut [u8], slice: &[u8]) {
    for (i, &byte) in slice.iter().enumerate() {
        buf[i] = byte;
    }
}

#[derive(PartialEq, Eq)]
enum State {
    Enabled,
    Disabled,
}

fn main() {
    let mut console = Console::new();

    writeln!(console, "****************************************").unwrap();
    writeln!(console, "nfct_test application is installed").unwrap();

    let mut state = State::Disabled;
    let mut state_change_cntr = 0;
    loop {
        match state {
            State::Enabled => {
                let mut rx_buf = [0; 256];
                loop {
                    match NfcTag::receive(&mut rx_buf) {
                        Ok(RecvOp {
                            recv_amount: amount,
                            ..
                        }) => match amount {
                            1 => writeln!(console, " -- RX Packet: {:02x?}", rx_buf[0],).unwrap(),
                            2 => writeln!(
                                console,
                                " -- RX Packet: {:02x?} {:02x?}",
                                rx_buf[0], rx_buf[1],
                            )
                            .unwrap(),
                            3 => writeln!(
                                console,
                                " -- RX Packet: {:02x?} {:02x?} {:02x?}",
                                rx_buf[0], rx_buf[1], rx_buf[2],
                            )
                            .unwrap(),
                            _ => writeln!(
                                console,
                                " -- RX Packet: {:02x?} {:02x?} {:02x?} {:02x?}",
                                rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3],
                            )
                            .unwrap(),
                        },
                        Err(_) => writeln!(console, " -- rx error!").unwrap(),
                    }

                    match rx_buf[0] {
                        0xe0 /* RATS */=> {
                            let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
                            let amount = answer_to_select.len();
                            match NfcTag::transmit(&mut answer_to_select, amount) {
                                Ok(_) => (),
                                Err(_) => writeln!(console, " -- tx error!").unwrap(),
                            }
                        }
                        0xc2 /* DESELECT */ => {
                            // Ignore the request
                            let mut command_error = [0x6A, 0x81];
                            let amount = command_error.len();
                            match NfcTag::transmit(&mut command_error, amount) {
                                Ok(_) => (),
                                Err(_) => writeln!(console, " -- tx error!").unwrap(),
                            }
                        }
                        0x02 | 0x03 /* APDU Prefix */ => {
                            let mut reply = [rx_buf[0], 0x90, 0x00];
                            let amount = reply.len();
                            match NfcTag::transmit(&mut reply, amount) {
                                Ok(_) => (),
                                Err(_) => writeln!(console, " -- tx error!").unwrap(),
                            }
                        }
                        0x52 | 0x50 /* WUPA | Halt */ => {
                            if NfcTag::disable_emulation() {
                                writeln!(console, " -- TAG DISABLED").unwrap();
                            }
                            state = State::Disabled;
                            break;
                        }
                        _ => {
                        }
                    }
                }
            }
            State::Disabled => {
                if NfcTag::enable_emulation() {
                    writeln!(console, " -- TAG ENABLED").unwrap();
                }
                // 1. Configure Type 4 tag
                if NfcTag::configure(4) {
                    writeln!(console, " -- TAG CONFIGURED").unwrap();
                }
                // 2. Subscribe to a SELECTED CALLBACK
                if NfcTag::selected() {
                    writeln!(console, " -- TAG SELECTED").unwrap();
                    // 0xfffff results in 1048575 / 13.56e6 = 77ms
                    NfcTag::set_framedelaymax(0xfffff);
                }
                state = State::Enabled;
            }
        }
        state_change_cntr += 1;
        if state_change_cntr > 10 && state == State::Disabled {
            break;
        }
    }
    writeln!(console, "****************************************").unwrap();
}
<commit_msg>Updates in the application logic<commit_after>#![no_std]
#![allow(unused_imports)]

extern crate alloc;
extern crate lang_items;
extern crate libtock_drivers;

use core::fmt::Write;
use libtock_core::result::CommandError;
use libtock_drivers::console::Console;
#[cfg(feature = "with_nfc")]
use libtock_drivers::nfc::NfcTag;
#[cfg(feature = "with_nfc")]
use libtock_drivers::nfc::RecvOp;
use libtock_drivers::result::TockError;

#[allow(dead_code)]
/// Helper function to write a slice into a transmission buffer.
fn write_tx_buffer(buf: &mut [u8], slice: &[u8]) {
    for (i, &byte) in slice.iter().enumerate() {
        buf[i] = byte;
    }
}

#[allow(dead_code)]
/// Helper function to write on console the received packet.
fn print_rx_buffer(buf: &mut [u8], amount: usize) {
    if amount < 1 || amount > buf.len() {
        return;
    }
    let mut console = Console::new();
    write!(console, " -- RX Packet:").unwrap();
    for byte in buf.iter().take(amount - 1) {
        write!(console, " {:02x?}", byte).unwrap();
    }
    writeln!(console, " {:02x?}", buf[amount - 1]).unwrap();
}

#[cfg(feature = "with_nfc")]
#[derive(PartialEq, Eq)]
/// enum for reserving the NFC tag state.
enum State {
    Enabled,
    Disabled,
}

fn main() {
    let mut console = Console::new();

    writeln!(console, "****************************************").unwrap();
    writeln!(console, "nfct_test application is installed").unwrap();

    #[cfg(feature = "with_nfc")]
    let mut state = State::Disabled;
    #[cfg(feature = "with_nfc")]
    let mut state_change_cntr = 0;
    #[cfg(feature = "with_nfc")]
    loop {
        match state {
            State::Enabled => {
                let mut rx_buf = [0; 256];
                loop {
                    match NfcTag::receive(&mut rx_buf) {
                        Ok(RecvOp {
                            recv_amount: amount,
                            ..
                        }) => print_rx_buffer(&mut rx_buf, amount),
                        Err(TockError::Command(CommandError {
                            return_code: -4, /* EOFF: Not Ready */
                            ..
                        })) => (),
                        Err(TockError::Command(CommandError {
                            return_code: value, ..
                        })) => writeln!(console, " -- Err({})!", value).unwrap(),
                        Err(_) => writeln!(console, " -- RX ERROR").unwrap(),
                    }

                    match rx_buf[0] {
                        0xe0 /* RATS */=> {
                            let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
                            let amount = answer_to_select.len();
                            match NfcTag::transmit(&mut answer_to_select, amount) {
                                Ok(_) => (),
                                Err(_) => writeln!(console, " -- tx error!").unwrap(),
                            }
                        }
                        0xc2 /* DESELECT */ => {
                            // Ignore the request
                            let mut command_error = [0x6A, 0x81];
                            let amount = command_error.len();
                            match NfcTag::transmit(&mut command_error, amount) {
                                Ok(_) => (),
                                Err(_) => writeln!(console, " -- tx error!").unwrap(),
                            }
                        }
                        0x02 | 0x03 /* APDU Prefix */ => {
                            // If the received packet is applet selection command (FIDO 2)
                            if rx_buf[1] == 0x00 && rx_buf[2] == 0xa4 && rx_buf[3] == 0x04 {
                                // Vesion: "U2F_V2"
                                // let mut reply = [rx_buf[0], 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x90, 0x00,];
                                // Vesion: "FIDO_2_0"
                                let mut reply = [rx_buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
                                let amount = reply.len();
                                match NfcTag::transmit(&mut reply, amount) {
                                    Ok(_) => (),
                                    Err(_) => writeln!(console, " -- tx error!").unwrap(),
                                }
                            } else {
                                let mut reply = [rx_buf[0], 0x90, 0x00];
                                let amount = reply.len();
                                match NfcTag::transmit(&mut reply, amount) {
                                    Ok(_) => (),
                                    Err(_) => writeln!(console, " -- tx error!").unwrap(),
                                }
                            }
                        }
                        0x52 | 0x50 /* WUPA | Halt */ => {
                            if NfcTag::disable_emulation() {
                                writeln!(console, " -- TAG DISABLED").unwrap();
                            }
                            state = State::Disabled;
                            break;
                        }
                        _ => (),
                    }
                }
            }
            State::Disabled => {
                NfcTag::enable_emulation();
                // Configure Type 4 tag
                if NfcTag::configure(4) {
                    state = State::Enabled;
                }
            }
        }
        state_change_cntr += 1;
        if state_change_cntr > 100 && state == State::Disabled {
            break;
        }
    }
    writeln!(console, "****************************************").unwrap();
}
<|endoftext|>


<commit_before>use regex::Regex;
use fall_tree::{NodeType, TextRange, ERROR};

pub type CustomRule = fn(&str) -> Option<usize>;

pub struct Rule {
    pub ty: NodeType,
    pub re: &'static str,
    pub f: Option<CustomRule>,
}

#[derive(Debug, Clone, Copy)]
pub struct Token {
    pub ty: NodeType,
    pub range: TextRange,
}

pub fn tokenize<'t>(text: &'t str, tokenizer: &[Rule]) -> TokenIter<'t> {
    TokenIter {
        rest: text,
        offset: 0,
        rules: tokenizer.iter().map(|r| {
            (r.ty, Regex::new(&format!("^{}", r.re)).unwrap(), r.f)
        }).collect(),
    }
}

pub struct TokenIter<'t> {
    rest: &'t str,
    offset: usize,
    rules: Vec<(NodeType, Regex, Option<CustomRule>)>,
}

impl<'t> Iterator for TokenIter<'t> {
    type Item = Token;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rest.is_empty() {
            return None;
        }

        let longest_match = self.rules.iter().rev()
            .filter_map(|&(ty, ref re, f)| {
                re.find(self.rest).map(|m| (m.end(), (ty, f)))
            })
            .max_by_key(|&(len, _)| len);

        let (len, (ty, custom_rule)) = match longest_match {
            Some(m) => m,
            None => return Some(self.bad_char()),
        };

        assert!(len > 0, "Empty Token {:?}", ty);

        let token = match custom_rule {
            None => self.token(ty, len),
            Some(f) => if let Some(len) = f(self.rest) {
                self.token(ty, len)
            } else {
                self.bad_char()
            }
        };

        Some(token)
    }
}

impl<'t> TokenIter<'t> {
    fn bad_char(&mut self) -> Token {
        let char_len = self.rest.chars().next().unwrap().len_utf8();
        self.token(ERROR, char_len)
    }

    fn token(&mut self, ty: NodeType, len: usize) -> Token {
        let range = TextRange::from_to(self.offset as u32, (self.offset + len) as u32);
        self.rest = &self.rest[len..];
        self.offset += len;
        Token { ty: ty, range: range }
    }
}

#[test]
fn tokenize_longest_first_wins() {
    let rules = &[
        Rule { ty: ::fall_tree::WHITESPACE, re: r"\s+", f: None },
        Rule { ty: NodeType(10), re: "foo", f: None },
        Rule { ty: NodeType(11), re: r"\w+", f: None },
        Rule { ty: NodeType(12), re: "foobar", f: None },
    ];

    let tokens: Vec<_> = tokenize("foo foob foobar", rules)
        .map(|t| t.ty.0)
        .collect();
    assert_eq!(tokens, vec![10, 1, 11, 1, 11]);
}
<commit_msg>Add ^ more carefully<commit_after>use regex::Regex;
use fall_tree::{NodeType, TextRange, ERROR};

pub type CustomRule = fn(&str) -> Option<usize>;

pub struct Rule {
    pub ty: NodeType,
    pub re: &'static str,
    pub f: Option<CustomRule>,
}

#[derive(Debug, Clone, Copy)]
pub struct Token {
    pub ty: NodeType,
    pub range: TextRange,
}

pub fn tokenize<'t>(text: &'t str, tokenizer: &[Rule]) -> TokenIter<'t> {
    TokenIter {
        rest: text,
        offset: 0,
        rules: tokenizer.iter().map(|r| {
            (r.ty, Regex::new(&format!("^({})", r.re)).unwrap(), r.f)
        }).collect(),
    }
}

pub struct TokenIter<'t> {
    rest: &'t str,
    offset: usize,
    rules: Vec<(NodeType, Regex, Option<CustomRule>)>,
}

impl<'t> Iterator for TokenIter<'t> {
    type Item = Token;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rest.is_empty() {
            return None;
        }

        let longest_match = self.rules.iter().rev()
            .filter_map(|&(ty, ref re, f)| {
                re.find(self.rest).map(|m| (m.end(), (ty, f)))
            })
            .max_by_key(|&(len, _)| len);

        let (len, (ty, custom_rule)) = match longest_match {
            Some(m) => m,
            None => return Some(self.bad_char()),
        };

        assert!(len > 0, "Empty Token {:?}", ty);

        let token = match custom_rule {
            None => self.token(ty, len),
            Some(f) => if let Some(len) = f(self.rest) {
                self.token(ty, len)
            } else {
                self.bad_char()
            }
        };

        Some(token)
    }
}

impl<'t> TokenIter<'t> {
    fn bad_char(&mut self) -> Token {
        let char_len = self.rest.chars().next().unwrap().len_utf8();
        self.token(ERROR, char_len)
    }

    fn token(&mut self, ty: NodeType, len: usize) -> Token {
        let range = TextRange::from_to(self.offset as u32, (self.offset + len) as u32);
        self.rest = &self.rest[len..];
        self.offset += len;
        Token { ty: ty, range: range }
    }
}

#[test]
fn tokenize_longest_first_wins() {
    let rules = &[
        Rule { ty: ::fall_tree::WHITESPACE, re: r"\s+", f: None },
        Rule { ty: NodeType(10), re: "foo", f: None },
        Rule { ty: NodeType(11), re: r"\w+", f: None },
        Rule { ty: NodeType(12), re: "foobar", f: None },
    ];

    let tokens: Vec<_> = tokenize("foo foob foobar", rules)
        .map(|t| t.ty.0)
        .collect();
    assert_eq!(tokens, vec![10, 1, 11, 1, 11]);
}
<|endoftext|>


<commit_before>//! Yet another index-based arena.

use std::{
    fmt,
    marker::PhantomData,
    ops::{Index, IndexMut},
    iter::FromIterator,
};

pub mod map;

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawId(u32);

impl From<RawId> for u32 {
    fn from(raw: RawId) -> u32 {
        raw.0
    }
}

impl From<u32> for RawId {
    fn from(id: u32) -> RawId {
        RawId(id)
    }
}

impl fmt::Debug for RawId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for RawId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct Arena<ID: ArenaId, T> {
    data: Vec<T>,
    _ty: PhantomData<ID>,
}

impl<ID: ArenaId, T: fmt::Debug> fmt::Debug for Arena<ID, T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Arena").field("len", &self.len()).field("data", &self.data).finish()
    }
}

#[macro_export]
macro_rules! impl_arena_id {
    ($name:ident) => {
        impl $crate::ArenaId for $name {
            fn from_raw(raw: $crate::RawId) -> Self {
                $name(raw)
            }
            fn into_raw(self) -> $crate::RawId {
                self.0
            }
        }
    };
}

pub trait ArenaId {
    fn from_raw(raw: RawId) -> Self;
    fn into_raw(self) -> RawId;
}

impl<ID: ArenaId, T> Arena<ID, T> {
    pub fn len(&self) -> usize {
        self.data.len()
    }
    pub fn alloc(&mut self, value: T) -> ID {
        let id = RawId(self.data.len() as u32);
        self.data.push(value);
        ID::from_raw(id)
    }
    pub fn iter<'a>(&'a self) -> impl Iterator<Item = (ID, &'a T)> {
        self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
    }
}

impl<ID: ArenaId, T> Default for Arena<ID, T> {
    fn default() -> Arena<ID, T> {
        Arena { data: Vec::new(), _ty: PhantomData }
    }
}

impl<ID: ArenaId, T> Index<ID> for Arena<ID, T> {
    type Output = T;
    fn index(&self, idx: ID) -> &T {
        let idx = idx.into_raw().0 as usize;
        &self.data[idx]
    }
}

impl<ID: ArenaId, T> IndexMut<ID> for Arena<ID, T> {
    fn index_mut(&mut self, idx: ID) -> &mut T {
        let idx = idx.into_raw().0 as usize;
        &mut self.data[idx]
    }
}

impl<ID: ArenaId, T> FromIterator<T> for Arena<ID, T> {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        Arena { data: Vec::from_iter(iter), _ty: PhantomData }
    }
}
<commit_msg>Elide lifetime<commit_after>//! Yet another index-based arena.

use std::{
    fmt,
    marker::PhantomData,
    ops::{Index, IndexMut},
    iter::FromIterator,
};

pub mod map;

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawId(u32);

impl From<RawId> for u32 {
    fn from(raw: RawId) -> u32 {
        raw.0
    }
}

impl From<u32> for RawId {
    fn from(id: u32) -> RawId {
        RawId(id)
    }
}

impl fmt::Debug for RawId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for RawId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct Arena<ID: ArenaId, T> {
    data: Vec<T>,
    _ty: PhantomData<ID>,
}

impl<ID: ArenaId, T: fmt::Debug> fmt::Debug for Arena<ID, T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Arena").field("len", &self.len()).field("data", &self.data).finish()
    }
}

#[macro_export]
macro_rules! impl_arena_id {
    ($name:ident) => {
        impl $crate::ArenaId for $name {
            fn from_raw(raw: $crate::RawId) -> Self {
                $name(raw)
            }
            fn into_raw(self) -> $crate::RawId {
                self.0
            }
        }
    };
}

pub trait ArenaId {
    fn from_raw(raw: RawId) -> Self;
    fn into_raw(self) -> RawId;
}

impl<ID: ArenaId, T> Arena<ID, T> {
    pub fn len(&self) -> usize {
        self.data.len()
    }
    pub fn alloc(&mut self, value: T) -> ID {
        let id = RawId(self.data.len() as u32);
        self.data.push(value);
        ID::from_raw(id)
    }
    pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> {
        self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
    }
}

impl<ID: ArenaId, T> Default for Arena<ID, T> {
    fn default() -> Arena<ID, T> {
        Arena { data: Vec::new(), _ty: PhantomData }
    }
}

impl<ID: ArenaId, T> Index<ID> for Arena<ID, T> {
    type Output = T;
    fn index(&self, idx: ID) -> &T {
        let idx = idx.into_raw().0 as usize;
        &self.data[idx]
    }
}

impl<ID: ArenaId, T> IndexMut<ID> for Arena<ID, T> {
    fn index_mut(&mut self, idx: ID) -> &mut T {
        let idx = idx.into_raw().0 as usize;
        &mut self.data[idx]
    }
}

impl<ID: ArenaId, T> FromIterator<T> for Arena<ID, T> {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        Arena { data: Vec::from_iter(iter), _ty: PhantomData }
    }
}
<|endoftext|>