<commit_before>// check-pass

// Bastion of the Turbofish
// ------------------------
// Beware travellers, lest you venture into waters callous and unforgiving,
// where hope must be abandoned, ere it is cruelly torn from you. For here
// stands the bastion of the Turbofish: an impenetrable fortress holding
// unshaking against those who would dare suggest the supererogation of the
// Turbofish.
//
// Once I was young and foolish and had the impudence to imagine that I could
// shake free from the coils by which that creature had us tightly bound. I
// dared to suggest that there was a better way: a brighter future, in which
// Rustaceans both new and old could be rid of that vile beast. But alas! In
// my foolhardiness my ignorance was unveiled and my dreams were dashed
// unforgivingly against the rock of syntactic ambiguity.
//
// This humble program, small and insignificant though it might seem,
// demonstrates that to which we had previously cast a blind eye: an ambiguity
// in permitting generic arguments to be provided without the consent of the
// Great Turbofish. Should you be so naïve as to try to revolt against its
// mighty clutches, here shall its wrath be indomitably displayed. This
// program must pass for all eternity, fundamentally at odds with an impetuous
// rebellion against the Turbofish.
//
// My heart aches in sorrow, for I know I am defeated. Let this be a warning
// to all those who come after. Here stands the bastion of the Turbofish.

// See https://github.com/rust-lang/rust/pull/53562
// and https://github.com/rust-lang/rfcs/pull/2527
// for context.

fn main() {
    let (oh, woe, is, me) = ("the", "Turbofish", "remains", "undefeated");
    let _: (bool, bool) = (oh<woe, is>(me));
}
<commit_msg>Rollup merge of #87298 - boringcactus:patch-2, r=steveklabnik<commit_after>// check-pass

// Bastion of the Turbofish
// ------------------------
// Beware travellers, lest you venture into waters callous and unforgiving,
// where hope must be abandoned, ere it is cruelly torn from you. For here
// stands the bastion of the Turbofish: an impenetrable fortress holding
// unshaking against those who would dare suggest the supererogation of the
// Turbofish.
//
// Once I was young and foolish and had the impudence to imagine that I could
// shake free from the coils by which that creature had us tightly bound. I
// dared to suggest that there was a better way: a brighter future, in which
// Rustaceans both new and old could be rid of that vile beast. But alas! In
// my foolhardiness my ignorance was unveiled and my dreams were dashed
// unforgivingly against the rock of syntactic ambiguity.
//
// This humble program, small and insignificant though it might seem,
// demonstrates that to which we had previously cast a blind eye: an ambiguity
// in permitting generic arguments to be provided without the consent of the
// Great Turbofish. Should you be so naïve as to try to revolt against its
// mighty clutches, here shall its wrath be indomitably displayed. This
// program must pass for all eternity, fundamentally at odds with an impetuous
// rebellion against the Turbofish.
//
// My heart aches in sorrow, for I know I am defeated. Let this be a warning
// to all those who come after. Here stands the bastion of the Turbofish.
//
// RIP Anna Harren, Guardian Angel of the Hallowed Turbofish. <3

// See https://github.com/rust-lang/rust/pull/53562
// and https://github.com/rust-lang/rfcs/pull/2527
// and https://twitter.com/garblefart/status/1393236602856611843
// for context.

fn main() {
    let (oh, woe, is, me) = ("the", "Turbofish", "remains", "undefeated");
    let _: (bool, bool) = (oh<woe, is>(me));
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]

extern crate serde;
extern crate rmp;
extern crate rmp_serde;

use std::io::Cursor;
use std::result;

use serde::Deserialize;

use rmp_serde::Deserializer;
use rmp_serde::decode::Error;

type Result<T> = result::Result<T, Error>;

#[cfg(feature = "serde_macros")]
#[test]
fn pass_tuple_struct() {
    let buf = [0x92, 0x2a, 0xce, 0x0, 0x1, 0x88, 0x94];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    struct Decoded(u32, u32);

    let mut deserializer = Deserializer::new(cur);
    let actual: Decoded = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Decoded(42, 100500), actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct() {
    let buf = [0x92, 0x2a, 0xce, 0x0, 0x1, 0x88, 0x94];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    struct Decoded { id: u32, value: u32 };

    let mut deserializer = Deserializer::new(cur);
    let actual: Decoded = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Decoded { id: 42, value: 100500 }, actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct_map() {
    #[derive(Debug, PartialEq, Deserialize)]
    struct Custom {
        et: String,
        le: u8,
        shit: u8,
    }

    let buf = [
        0x83, // 3 (size)
        0xa2, 0x65, 0x74, // "et"
        0xa5, 0x76, 0x6f, 0x69, 0x6c, 0x61, // "voila"
        0xa2, 0x6c, 0x65, // "le"
        0x00, // 0
        0xa4, 0x73, 0x68, 0x69, 0x74, // "shit"
        0x01, // 1
    ];
    let cur = Cursor::new(&buf[..]);

    // it appears no special behavior is needed for deserializing structs encoded as maps
    let mut deserializer = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();
    let voila = "voila".to_string(); // so the next line looks more funny
    let expected = Custom { et: voila, le: 0, shit: 1 };

    assert_eq!(expected, actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_enum() {
    // We expect enums to be endoded as [id, [...]]

    let buf = [0x92, 0x01, 0x90];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second,
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Custom::Second, actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_enum_variant_with_arg() {
    let buf = [0x92, 0x01, 0x91, 0x2a];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second(u32),
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Custom::Second(42), actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn fail_enum_sequence_mismatch() {
    let buf = [0x93, 0x1, 0x2a, 0xce, 0x0, 0x1, 0x88, 0x94];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second,
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Result<Custom> = Deserialize::deserialize(&mut deserializer);

    match actual.err() {
        Some(Error::Uncategorized(..)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
}

#[cfg(feature = "serde_macros")]
#[test]
fn fail_enum_overflow() {
    let buf = [0x92, 0x01, 0x2a];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Result<Custom> = Deserialize::deserialize(&mut deserializer);

    match actual.err() {
        Some(Error::Uncategorized(..)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct_enum_with_arg() {
    let buf = [0x92, 0x01, 0x91, 0x2a];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second { id: u32 },
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Custom::Second { id: 42 }, actual);
}
<commit_msg>UT(serde): check read size.<commit_after>#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]

extern crate serde;
extern crate rmp;
extern crate rmp_serde;

use std::io::Cursor;
use std::result;

use serde::Deserialize;

use rmp_serde::Deserializer;
use rmp_serde::decode::Error;

type Result<T> = result::Result<T, Error>;

#[cfg(feature = "serde_macros")]
#[test]
fn pass_tuple_struct() {
    let buf = [0x92, 0x2a, 0xce, 0x0, 0x1, 0x88, 0x94];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    struct Decoded(u32, u32);

    let mut deserializer = Deserializer::new(cur);
    let actual: Decoded = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Decoded(42, 100500), actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct() {
    let buf = [0x92, 0x2a, 0xce, 0x0, 0x1, 0x88, 0x94];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    struct Decoded { id: u32, value: u32 };

    let mut deserializer = Deserializer::new(cur);
    let actual: Decoded = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Decoded { id: 42, value: 100500 }, actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct_map() {
    #[derive(Debug, PartialEq, Deserialize)]
    struct Custom {
        et: String,
        le: u8,
        shit: u8,
    }

    let buf = [
        0x83, // 3 (size)
        0xa2, 0x65, 0x74, // "et"
        0xa5, 0x76, 0x6f, 0x69, 0x6c, 0x61, // "voila"
        0xa2, 0x6c, 0x65, // "le"
        0x00, // 0
        0xa4, 0x73, 0x68, 0x69, 0x74, // "shit"
        0x01, // 1
    ];
    let cur = Cursor::new(&buf[..]);

    // it appears no special behavior is needed for deserializing structs encoded as maps
    let mut deserializer = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();
    let voila = "voila".to_string(); // so the next line looks more funny
    let expected = Custom { et: voila, le: 0, shit: 1 };

    assert_eq!(expected, actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_enum() {
    // We expect enums to be endoded as [id, [...]]

    let buf = [0x92, 0x01, 0x90];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second,
    }

    let mut de = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut de).unwrap();

    assert_eq!(Custom::Second, actual);
    assert_eq!(3, de.get_ref().position());
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_enum_variant_with_arg() {
    let buf = [0x92, 0x01, 0x91, 0x2a];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second(u32),
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Custom::Second(42), actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn fail_enum_sequence_mismatch() {
    let buf = [0x93, 0x1, 0x2a, 0xce, 0x0, 0x1, 0x88, 0x94];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second,
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Result<Custom> = Deserialize::deserialize(&mut deserializer);

    match actual.err() {
        Some(Error::Uncategorized(..)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
}

#[cfg(feature = "serde_macros")]
#[test]
fn fail_enum_overflow() {
    let buf = [0x92, 0x01, 0x2a];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Result<Custom> = Deserialize::deserialize(&mut deserializer);

    match actual.err() {
        Some(Error::Uncategorized(..)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct_enum_with_arg() {
    let buf = [0x92, 0x01, 0x91, 0x2a];
    let cur = Cursor::new(&buf[..]);

    #[derive(Debug, PartialEq, Deserialize)]
    enum Custom {
        First,
        Second { id: u32 },
    }

    let mut deserializer = Deserializer::new(cur);
    let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();

    assert_eq!(Custom::Second { id: 42 }, actual);
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::path::Path;
use std::collections::HashSet;

use rustc_hash::FxHashMap;

use ra_db::{
    CrateGraph, FileId, SourceRoot, SourceRootId, SourceDatabase, salsa,
};
use ra_hir::{db, HirInterner};
use ra_project_model::ProjectWorkspace;
use ra_vfs::{Vfs, VfsChange};

type Result<T> = std::result::Result<T, failure::Error>;

#[salsa::database(
    ra_db::SourceDatabaseStorage,
    db::HirDatabaseStorage,
    db::PersistentHirDatabaseStorage
)]
#[derive(Debug)]
pub struct BatchDatabase {
    runtime: salsa::Runtime<BatchDatabase>,
    interner: Arc<HirInterner>,
}

impl salsa::Database for BatchDatabase {
    fn salsa_runtime(&self) -> &salsa::Runtime<BatchDatabase> {
        &self.runtime
    }
}

impl AsRef<HirInterner> for BatchDatabase {
    fn as_ref(&self) -> &HirInterner {
        &self.interner
    }
}

fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId {
    FileId(f.0.into())
}
fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
    SourceRootId(r.0.into())
}

impl BatchDatabase {
    pub fn load(crate_graph: CrateGraph, vfs: &mut Vfs) -> BatchDatabase {
        let mut db =
            BatchDatabase { runtime: salsa::Runtime::default(), interner: Default::default() };
        db.set_crate_graph(Arc::new(crate_graph));

        // wait until Vfs has loaded all roots
        let receiver = vfs.task_receiver().clone();
        let mut roots_loaded = HashSet::new();
        for task in receiver {
            vfs.handle_task(task);
            let mut done = false;
            for change in vfs.commit_changes() {
                match change {
                    VfsChange::AddRoot { root, files } => {
                        let source_root_id = vfs_root_to_id(root);
                        log::debug!(
                            "loaded source root {:?} with path {:?}",
                            source_root_id,
                            vfs.root2path(root)
                        );
                        let mut file_map = FxHashMap::default();
                        for (vfs_file, path, text) in files {
                            let file_id = vfs_file_to_id(vfs_file);
                            db.set_file_text(file_id, text);
                            db.set_file_relative_path(file_id, path.clone());
                            db.set_file_source_root(file_id, source_root_id);
                            file_map.insert(path, file_id);
                        }
                        let source_root = SourceRoot { files: file_map };
                        db.set_source_root(source_root_id, Arc::new(source_root));
                        roots_loaded.insert(source_root_id);
                        if roots_loaded.len() == vfs.num_roots() {
                            done = true;
                        }
                    }
                    VfsChange::AddFile { .. }
                    | VfsChange::RemoveFile { .. }
                    | VfsChange::ChangeFile { .. } => {
                        // We just need the first scan, so just ignore these
                    }
                }
            }
            if done {
                break;
            }
        }

        db
    }

    pub fn load_cargo(root: impl AsRef<Path>) -> Result<(BatchDatabase, Vec<SourceRootId>)> {
        let root = std::env::current_dir()?.join(root);
        let ws = ProjectWorkspace::discover(root.as_ref())?;
        let mut roots = Vec::new();
        roots.push(root.clone());
        for pkg in ws.cargo.packages() {
            roots.push(pkg.root(&ws.cargo).to_path_buf());
        }
        for krate in ws.sysroot.crates() {
            roots.push(krate.root_dir(&ws.sysroot).to_path_buf())
        }
        let (mut vfs, roots) = Vfs::new(roots);
        let mut load = |path: &Path| {
            let vfs_file = vfs.load(path);
            log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
            vfs_file.map(vfs_file_to_id)
        };
        let crate_graph = ws.to_crate_graph(&mut load);
        log::debug!("crate graph: {:?}", crate_graph);

        let local_roots = roots
            .into_iter()
            .filter(|r| vfs.root2path(*r).starts_with(&root))
            .map(vfs_root_to_id)
            .collect();

        let db = BatchDatabase::load(crate_graph, &mut vfs);
        Ok((db, local_roots))
    }
}

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

    #[test]
    fn test_loading_rust_analyzer() {
        let mut path = std::env::current_exe().unwrap();
        while !path.join("Cargo.toml").is_file() {
            path = path.parent().unwrap().to_owned();
        }
        let (db, roots) = BatchDatabase::load_cargo(path).unwrap();
        let mut num_crates = 0;
        for root in roots {
            for _krate in Crate::source_root_crates(&db, root) {
                num_crates += 1;
            }
        }

        // RA has quite a few crates, but the exact count doesn't matter
        assert!(num_crates > 20);
    }
}
<commit_msg>fix-tests<commit_after>use std::sync::Arc;
use std::path::Path;
use std::collections::HashSet;

use rustc_hash::FxHashMap;

use ra_db::{
    CrateGraph, FileId, SourceRoot, SourceRootId, SourceDatabase, salsa,
};
use ra_hir::{db, HirInterner};
use ra_project_model::ProjectWorkspace;
use ra_vfs::{Vfs, VfsChange};

type Result<T> = std::result::Result<T, failure::Error>;

#[salsa::database(
    ra_db::SourceDatabaseStorage,
    db::HirDatabaseStorage,
    db::PersistentHirDatabaseStorage
)]
#[derive(Debug)]
pub struct BatchDatabase {
    runtime: salsa::Runtime<BatchDatabase>,
    interner: Arc<HirInterner>,
}

impl salsa::Database for BatchDatabase {
    fn salsa_runtime(&self) -> &salsa::Runtime<BatchDatabase> {
        &self.runtime
    }
}

impl AsRef<HirInterner> for BatchDatabase {
    fn as_ref(&self) -> &HirInterner {
        &self.interner
    }
}

fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId {
    FileId(f.0.into())
}
fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
    SourceRootId(r.0.into())
}

impl BatchDatabase {
    pub fn load(crate_graph: CrateGraph, vfs: &mut Vfs) -> BatchDatabase {
        let mut db =
            BatchDatabase { runtime: salsa::Runtime::default(), interner: Default::default() };
        db.set_crate_graph(Arc::new(crate_graph));

        // wait until Vfs has loaded all roots
        let receiver = vfs.task_receiver().clone();
        let mut roots_loaded = HashSet::new();
        for task in receiver {
            vfs.handle_task(task);
            let mut done = false;
            for change in vfs.commit_changes() {
                match change {
                    VfsChange::AddRoot { root, files } => {
                        let source_root_id = vfs_root_to_id(root);
                        log::debug!(
                            "loaded source root {:?} with path {:?}",
                            source_root_id,
                            vfs.root2path(root)
                        );
                        let mut file_map = FxHashMap::default();
                        for (vfs_file, path, text) in files {
                            let file_id = vfs_file_to_id(vfs_file);
                            db.set_file_text(file_id, text);
                            db.set_file_relative_path(file_id, path.clone());
                            db.set_file_source_root(file_id, source_root_id);
                            file_map.insert(path, file_id);
                        }
                        let source_root = SourceRoot { files: file_map };
                        db.set_source_root(source_root_id, Arc::new(source_root));
                        roots_loaded.insert(source_root_id);
                        if roots_loaded.len() == vfs.n_roots() {
                            done = true;
                        }
                    }
                    VfsChange::AddFile { .. }
                    | VfsChange::RemoveFile { .. }
                    | VfsChange::ChangeFile { .. } => {
                        // We just need the first scan, so just ignore these
                    }
                }
            }
            if done {
                break;
            }
        }

        db
    }

    pub fn load_cargo(root: impl AsRef<Path>) -> Result<(BatchDatabase, Vec<SourceRootId>)> {
        let root = std::env::current_dir()?.join(root);
        let ws = ProjectWorkspace::discover(root.as_ref())?;
        let mut roots = Vec::new();
        roots.push(root.clone());
        for pkg in ws.cargo.packages() {
            roots.push(pkg.root(&ws.cargo).to_path_buf());
        }
        for krate in ws.sysroot.crates() {
            roots.push(krate.root_dir(&ws.sysroot).to_path_buf())
        }
        let (mut vfs, roots) = Vfs::new(roots);
        let mut load = |path: &Path| {
            let vfs_file = vfs.load(path);
            log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
            vfs_file.map(vfs_file_to_id)
        };
        let crate_graph = ws.to_crate_graph(&mut load);
        log::debug!("crate graph: {:?}", crate_graph);

        let local_roots = roots
            .into_iter()
            .filter(|r| vfs.root2path(*r).starts_with(&root))
            .map(vfs_root_to_id)
            .collect();

        let db = BatchDatabase::load(crate_graph, &mut vfs);
        Ok((db, local_roots))
    }
}

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

    #[test]
    fn test_loading_rust_analyzer() {
        let mut path = std::env::current_exe().unwrap();
        while !path.join("Cargo.toml").is_file() {
            path = path.parent().unwrap().to_owned();
        }
        let (db, roots) = BatchDatabase::load_cargo(path).unwrap();
        let mut n_crates = 0;
        for root in roots {
            for _krate in Crate::source_root_crates(&db, root) {
                n_crates += 1;
            }
        }

        // RA has quite a few crates, but the exact count doesn't matter
        assert!(n_crates > 20);
    }
}
<|endoftext|>


<commit_before>//! Song analysis module.
//!
//! Contains various functions to extract meaningful features from a `Song`,
//! e.g. tempo features, spectral features, etc.
#[cfg(feature = "aubio-lib")]
extern crate aubio_lib;

use aubio_rs::{bin_to_freq, silence_detection, OnsetMode, PVoc, SpecDesc, SpecShape, Tempo};

use super::{Analysis, Song};

pub fn analyze_song(song: Song) -> Analysis {
    Analysis {
        tempo: get_tempo(&song),
        spectral_centroid: get_centroid(&song),
    }
}

/**
 * Compute score related to tempo.
 * Right now, basically returns the song's BPM.
 *
 * - `song` Song to compute score from
 */
fn get_tempo(song: &Song) -> f32 {
    const WINDOW_SIZE: usize = 1024;
    const HOP_SIZE: usize = 256;
    let mut tempo =
        Tempo::new(OnsetMode::SpecDiff, WINDOW_SIZE, HOP_SIZE, song.sample_rate).unwrap();
    for chunk in song.sample_array.chunks(HOP_SIZE) {
        tempo.do_result(chunk).unwrap();
    }
    tempo.get_bpm()
}

/**
 * Compute score related to spectral centroid.
 * Returns the mean of computed spectral centroids over the song.
 *
 * - `song` Song to compute score from
 */
fn get_centroid(song: &Song) -> f32 {
    const WINDOW_SIZE: usize = 512;
    let hop_size = WINDOW_SIZE / 4;
    let silence_threshold = -60.;
    let mut centroid = SpecDesc::new(SpecShape::Centroid, WINDOW_SIZE).unwrap();
    let mut phase_vocoder = PVoc::new(WINDOW_SIZE, hop_size).unwrap();

    let mut freqs: Vec<f32> = Vec::with_capacity(song.sample_array.chunks(hop_size).len());
    for chunk in song.sample_array.chunks(hop_size) {
        let mut fftgrain: Vec<f32> = vec![0.0; WINDOW_SIZE + 2];
        // If silence, centroid will be off, so skip instead
        if silence_detection(chunk, silence_threshold) {
            continue;
        }
        phase_vocoder.do_(chunk, fftgrain.as_mut_slice()).unwrap();
        let bin = centroid.do_result(fftgrain.as_slice()).unwrap();
        let freq = bin_to_freq(bin, song.sample_rate as f32, WINDOW_SIZE as f32);
        freqs.push(freq);
    }

    // return mean
    freqs.iter().sum::<f32>() / freqs.len() as f32
}

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

    #[test]
    fn tempo() {
        let song = decode_song("data/s16_mono_22_5kHz.flac").unwrap();
        assert!(0.01 > (142.38 - get_tempo(&song)).abs());
    }

    #[test]
    fn centroid() {
        let song = decode_song("data/s16_mono_22_5kHz.flac").unwrap();
        assert!(0.01 > (1236.39 - get_centroid(&song).abs()));
    }
}
<commit_msg>Fixed tests that were daubed du cul<commit_after>//! Song analysis module.
//!
//! Contains various functions to extract meaningful features from a `Song`,
//! e.g. tempo features, spectral features, etc.
#[cfg(feature = "aubio-lib")]
extern crate aubio_lib;

use aubio_rs::{bin_to_freq, silence_detection, OnsetMode, PVoc, SpecDesc, SpecShape, Tempo};

use super::{Analysis, Song};

pub fn analyze_song(song: Song) -> Analysis {
    Analysis {
        tempo: get_tempo(&song),
        spectral_centroid: get_centroid(&song),
    }
}

/**
 * Compute score related to tempo.
 * Right now, basically returns the song's BPM.
 *
 * - `song` Song to compute score from
 */
fn get_tempo(song: &Song) -> f32 {
    const WINDOW_SIZE: usize = 1024;
    const HOP_SIZE: usize = 256;
    let mut tempo =
        Tempo::new(OnsetMode::SpecDiff, WINDOW_SIZE, HOP_SIZE, song.sample_rate).unwrap();
    for chunk in song.sample_array.chunks(HOP_SIZE) {
        tempo.do_result(chunk).unwrap();
    }
    tempo.get_bpm()
}

/**
 * Compute score related to spectral centroid.
 * Returns the mean of computed spectral centroids over the song.
 *
 * - `song` Song to compute score from
 */
fn get_centroid(song: &Song) -> f32 {
    const WINDOW_SIZE: usize = 512;
    let hop_size = WINDOW_SIZE / 4;
    let silence_threshold = -60.;
    let mut centroid = SpecDesc::new(SpecShape::Centroid, WINDOW_SIZE).unwrap();
    let mut phase_vocoder = PVoc::new(WINDOW_SIZE, hop_size).unwrap();

    let mut freqs: Vec<f32> = Vec::with_capacity(song.sample_array.chunks(hop_size).len());
    for chunk in song.sample_array.chunks(hop_size) {
        let mut fftgrain: Vec<f32> = vec![0.0; WINDOW_SIZE + 2];
        // If silence, centroid will be off, so skip instead
        if !silence_detection(chunk, silence_threshold) {
            continue;
        }
        phase_vocoder.do_(chunk, fftgrain.as_mut_slice()).unwrap();
        let bin = centroid.do_result(fftgrain.as_slice()).unwrap();
        let freq = bin_to_freq(bin, song.sample_rate as f32, WINDOW_SIZE as f32);
        freqs.push(freq);
    }

    // return mean
    freqs.iter().sum::<f32>() / freqs.len() as f32
}

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

    #[test]
    fn tempo() {
        let song = decode_song("data/s16_mono_22_5kHz.flac").unwrap();
        assert!(0.01 > (142.38 - get_tempo(&song)).abs());
    }

    #[test]
    fn centroid() {
        let song = decode_song("data/s16_mono_22_5kHz.flac").unwrap();
        assert!(0.01 > (1236.39 - get_centroid(&song)).abs());
    }
}
<|endoftext|>


<commit_before>use std::{convert::TryFrom, ffi::CStr, os::raw::c_char};

use scan_fmt::scan_fmt;

use super::ffi::{self, Gles2};

pub const GLES_3_0: GlVersion = GlVersion::new(3, 0);
pub const GLES_2_0: GlVersion = GlVersion::new(2, 0);

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct GlVersion {
    pub major: i32,
    pub minor: i32,
}

impl GlVersion {
    pub const fn new(major: i32, minor: i32) -> Self {
        GlVersion { major, minor }
    }
}

impl Eq for GlVersion {}

impl Ord for GlVersion {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        match self.major.cmp(&other.major) {
            std::cmp::Ordering::Equal => self.minor.cmp(&other.minor),
            ord => ord,
        }
    }
}

impl PartialOrd for GlVersion {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl TryFrom<&CStr> for GlVersion {
    type Error = scan_fmt::parse::ScanError;

    fn try_from(value: &CStr) -> Result<Self, Self::Error> {
        scan_fmt!(&value.to_string_lossy(), "{d}.{d}", i32, i32)
            .or_else(|_| scan_fmt!(&value.to_string_lossy(), "OpenGL ES {d}.{d}", i32, i32))
            .map(|(major, minor)| GlVersion::new(major, minor))
    }
}

impl TryFrom<&Gles2> for GlVersion {
    type Error = scan_fmt::parse::ScanError;

    fn try_from(value: &Gles2) -> Result<Self, Self::Error> {
        let version = unsafe { CStr::from_ptr(value.GetString(ffi::VERSION) as *const c_char) };
        GlVersion::try_from(version)
    }
}

#[cfg(test)]
mod tests {
    use super::GlVersion;
    use std::{convert::TryFrom, ffi::CStr, os::raw::c_char};

    #[test]
    fn test_parse_mesa_3_2() {
        let gl_version = "OpenGL ES 3.2 Mesa 20.3.5";
        let gl_version_str = unsafe { CStr::from_ptr(gl_version.as_ptr() as *const c_char) };
        assert_eq!(GlVersion::try_from(gl_version_str), Ok(GlVersion::new(3, 2)))
    }

    #[test]
    fn test_3_2_greater_3_0() {
        assert!(GlVersion::new(3,2) > GlVersion::new(3,0))
    }

    #[test]
    fn test_3_0_greater_or_equal_3_0() {
        assert!(GlVersion::new(3,0) >= GlVersion::new(3,0))
    }

    #[test]
    fn test_3_0_less_or_equal_3_0() {
        assert!(GlVersion::new(3,0) <= GlVersion::new(3,0))
    }

    #[test]
    fn test_3_0_eq_3_0() {
        assert!(GlVersion::new(3,0) == GlVersion::new(3,0))
    }

    #[test]
    fn test_2_0_less_3_0() {
        assert!(GlVersion::new(2,0) < GlVersion::new(3,0))
    }
}
<commit_msg>fixed formatting in gles2 version.rs<commit_after>use std::{convert::TryFrom, ffi::CStr, os::raw::c_char};

use scan_fmt::scan_fmt;

use super::ffi::{self, Gles2};

pub const GLES_3_0: GlVersion = GlVersion::new(3, 0);
pub const GLES_2_0: GlVersion = GlVersion::new(2, 0);

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct GlVersion {
    pub major: i32,
    pub minor: i32,
}

impl GlVersion {
    pub const fn new(major: i32, minor: i32) -> Self {
        GlVersion { major, minor }
    }
}

impl Eq for GlVersion {}

impl Ord for GlVersion {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        match self.major.cmp(&other.major) {
            std::cmp::Ordering::Equal => self.minor.cmp(&other.minor),
            ord => ord,
        }
    }
}

impl PartialOrd for GlVersion {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl TryFrom<&CStr> for GlVersion {
    type Error = scan_fmt::parse::ScanError;

    fn try_from(value: &CStr) -> Result<Self, Self::Error> {
        scan_fmt!(&value.to_string_lossy(), "{d}.{d}", i32, i32)
            .or_else(|_| scan_fmt!(&value.to_string_lossy(), "OpenGL ES {d}.{d}", i32, i32))
            .map(|(major, minor)| GlVersion::new(major, minor))
    }
}

impl TryFrom<&Gles2> for GlVersion {
    type Error = scan_fmt::parse::ScanError;

    fn try_from(value: &Gles2) -> Result<Self, Self::Error> {
        let version = unsafe { CStr::from_ptr(value.GetString(ffi::VERSION) as *const c_char) };
        GlVersion::try_from(version)
    }
}

#[cfg(test)]
mod tests {
    use super::GlVersion;
    use std::{convert::TryFrom, ffi::CStr, os::raw::c_char};

    #[test]
    fn test_parse_mesa_3_2() {
        let gl_version = "OpenGL ES 3.2 Mesa 20.3.5";
        let gl_version_str = unsafe { CStr::from_ptr(gl_version.as_ptr() as *const c_char) };
        assert_eq!(GlVersion::try_from(gl_version_str), Ok(GlVersion::new(3, 2)))
    }

    #[test]
    fn test_3_2_greater_3_0() {
        assert!(GlVersion::new(3, 2) > GlVersion::new(3, 0))
    }

    #[test]
    fn test_3_0_greater_or_equal_3_0() {
        assert!(GlVersion::new(3, 0) >= GlVersion::new(3, 0))
    }

    #[test]
    fn test_3_0_less_or_equal_3_0() {
        assert!(GlVersion::new(3, 0) <= GlVersion::new(3, 0))
    }

    #[test]
    fn test_3_0_eq_3_0() {
        assert!(GlVersion::new(3, 0) == GlVersion::new(3, 0))
    }

    #[test]
    fn test_2_0_less_3_0() {
        assert!(GlVersion::new(2, 0) < GlVersion::new(3, 0))
    }
}
<|endoftext|>


<commit_before>use std::mem::MaybeUninit;
use std::os::raw::c_void;
use std::ptr::null_mut;
use raw::{FunctionCallbackInfo, Env, Local};

use nodejs_sys as napi;

#[repr(C)]
pub struct CCallback {
    pub static_callback: *mut c_void,
    pub dynamic_callback: *mut c_void
}

impl Default for CCallback {
    fn default() -> Self {
        CCallback {
            static_callback: null_mut(),
            dynamic_callback: null_mut()
        }
    }
}

pub unsafe extern "C" fn set_return(_info: FunctionCallbackInfo, _value: Local) {

}

pub unsafe extern "C" fn get_isolate(_info: FunctionCallbackInfo) -> Env { unimplemented!() }

// FIXME: Remove. This will never be implemented
pub unsafe extern "C" fn current_isolate() -> Env { panic!("current_isolate won't be implemented in n-api") }

pub unsafe extern "C" fn is_construct(env: Env, info: FunctionCallbackInfo) -> bool {
    let mut target: MaybeUninit<napi::napi_value> = MaybeUninit::zeroed();
    let status = napi::napi_get_new_target(
        env,
        info,
        target.as_mut_ptr()
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    let target: napi::napi_value = target.assume_init();
    !target.is_null()
}

pub unsafe extern "C" fn this(env: Env, info: FunctionCallbackInfo, out: &mut Local) {
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        out as *mut _,
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
}

/// Mutates the `out` argument provided to refer to the associated data value of the
/// `napi_callback_info`.
pub unsafe extern "C" fn data(env: Env, info: FunctionCallbackInfo, out: &mut *mut c_void) {
    let mut data = null_mut();
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        null_mut(),
        &mut data as *mut _,
    );
    if status == napi::napi_status::napi_ok {
        *out = data;
    }
}

/// Gets the number of arguments passed to the function.
pub unsafe extern "C" fn len(env: Env, info: FunctionCallbackInfo) -> i32 {
    let mut argc = 0usize;
    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut argc as *mut _,
        null_mut(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    argc as i32
}

/// Returns the function arguments as a `Vec<Local>`
pub unsafe extern "C" fn argv(env: Env, info: FunctionCallbackInfo) -> Vec<Local> {
    let len = len(env, info);
    let mut args = vec![null_mut(); len as usize];
    let mut num_args = args.len();
    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut num_args as *mut _,
        args.as_mut_ptr(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    args
}
<commit_msg>Address feedback in review: - Use `Local` instead of `napi_value`, for consistency - Comment that `target` is guaranteed to be initialized but may be NULL<commit_after>use std::mem::MaybeUninit;
use std::os::raw::c_void;
use std::ptr::null_mut;
use raw::{FunctionCallbackInfo, Env, Local};

use nodejs_sys as napi;

#[repr(C)]
pub struct CCallback {
    pub static_callback: *mut c_void,
    pub dynamic_callback: *mut c_void
}

impl Default for CCallback {
    fn default() -> Self {
        CCallback {
            static_callback: null_mut(),
            dynamic_callback: null_mut()
        }
    }
}

pub unsafe extern "C" fn set_return(_info: FunctionCallbackInfo, _value: Local) {

}

pub unsafe extern "C" fn get_isolate(_info: FunctionCallbackInfo) -> Env { unimplemented!() }

// FIXME: Remove. This will never be implemented
pub unsafe extern "C" fn current_isolate() -> Env { panic!("current_isolate won't be implemented in n-api") }

pub unsafe extern "C" fn is_construct(env: Env, info: FunctionCallbackInfo) -> bool {
    let mut target: MaybeUninit<Local> = MaybeUninit::zeroed();

    let status = napi::napi_get_new_target(
        env,
        info,
        target.as_mut_ptr()
    );

    assert_eq!(status, napi::napi_status::napi_ok);

    // napi_get_new_target is guaranteed to assign to target, so it's initialized.
    let target: Local = target.assume_init();

    // By the napi_get_new_target contract, target will either be NULL if the current
    // function was called without `new`, or a valid napi_value handle if the current
    // function was called with `new`.
    !target.is_null()
}

pub unsafe extern "C" fn this(env: Env, info: FunctionCallbackInfo, out: &mut Local) {
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        out as *mut _,
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
}

/// Mutates the `out` argument provided to refer to the associated data value of the
/// `napi_callback_info`.
pub unsafe extern "C" fn data(env: Env, info: FunctionCallbackInfo, out: &mut *mut c_void) {
    let mut data = null_mut();
    let status = napi::napi_get_cb_info(
        env,
        info,
        null_mut(),
        null_mut(),
        null_mut(),
        &mut data as *mut _,
    );
    if status == napi::napi_status::napi_ok {
        *out = data;
    }
}

/// Gets the number of arguments passed to the function.
pub unsafe extern "C" fn len(env: Env, info: FunctionCallbackInfo) -> i32 {
    let mut argc = 0usize;
    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut argc as *mut _,
        null_mut(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    argc as i32
}

/// Returns the function arguments as a `Vec<Local>`
pub unsafe extern "C" fn argv(env: Env, info: FunctionCallbackInfo) -> Vec<Local> {
    let len = len(env, info);
    let mut args = vec![null_mut(); len as usize];
    let mut num_args = args.len();
    let status = napi::napi_get_cb_info(
        env,
        info,
        &mut num_args as *mut _,
        args.as_mut_ptr(),
        null_mut(),
        null_mut(),
    );
    assert_eq!(status, napi::napi_status::napi_ok);
    args
}
<|endoftext|>


<commit_before>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             align: AlignMode::XmidYmid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum AlignMode {
    XminYmin,
    XmidYmin,
    XmaxYmin,
    XminYmid,
    XmidYmid,
    XmaxYmid,
    XminYmax,
    XmidYmax,
    XmaxYmax,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    align: AlignMode,
    fit: FitMode,
}

#[derive(Debug, Copy, Clone)]
enum Align1D {
    Min,
    Mid,
    Max,
}

fn align_1d(a: Align1D, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
    match a {
        Align1D::Min => dest_pos,
        Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
        Align1D::Max => dest_pos + dest_size - obj_size,
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { align, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor: f64;

                match fit {
                    FitMode::Meet => {
                        factor = w_factor.min(h_factor);
                    }
                    FitMode::Slice => {
                        factor = w_factor.max(h_factor);
                    }
                }

                let w = object_width * factor;
                let h = object_height * factor;

                let xalign: Align1D;
                let yalign: Align1D;

                match align {
                    AlignMode::XminYmin => {
                        xalign = Align1D::Min;
                        yalign = Align1D::Min;
                    }
                    AlignMode::XminYmid => {
                        xalign = Align1D::Min;
                        yalign = Align1D::Mid;
                    }
                    AlignMode::XminYmax => {
                        xalign = Align1D::Min;
                        yalign = Align1D::Max;
                    }
                    AlignMode::XmidYmin => {
                        xalign = Align1D::Mid;
                        yalign = Align1D::Min;
                    }
                    AlignMode::XmidYmid => {
                        xalign = Align1D::Mid;
                        yalign = Align1D::Mid;
                    }
                    AlignMode::XmidYmax => {
                        xalign = Align1D::Mid;
                        yalign = Align1D::Max;
                    }
                    AlignMode::XmaxYmin => {
                        xalign = Align1D::Max;
                        yalign = Align1D::Min;
                    }
                    AlignMode::XmaxYmid => {
                        xalign = Align1D::Max;
                        yalign = Align1D::Mid;
                    }
                    AlignMode::XmaxYmax => {
                        xalign = Align1D::Max;
                        yalign = Align1D::Max;
                    }
                }

                let xpos = align_1d(xalign, dest_x, dest_width, w);
                let ypos = align_1d(yalign, dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }
}

impl Default for Align {
    fn default() -> Self {
        Align {
            align: AlignMode::XmidYmid,
            fit: FitMode::Meet,
        }
    }
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

fn parse_align_mode(s: &str) -> Result<Option<Align>, AttributeError> {
    match s {
        "none" => Ok(None),
        "xMinYMin" => Ok(Some(Align {
            align: AlignMode::XminYmin,
            fit: FitMode::Meet,
        })),
        "xMidYMin" => Ok(Some(Align {
            align: AlignMode::XmidYmin,
            fit: FitMode::Meet,
        })),
        "xMaxYMin" => Ok(Some(Align {
            align: AlignMode::XmaxYmin,
            fit: FitMode::Meet,
        })),
        "xMinYMid" => Ok(Some(Align {
            align: AlignMode::XminYmid,
            fit: FitMode::Meet,
        })),
        "xMidYMid" => Ok(Some(Align {
            align: AlignMode::XmidYmid,
            fit: FitMode::Meet,
        })),
        "xMaxYMid" => Ok(Some(Align {
            align: AlignMode::XmaxYmid,
            fit: FitMode::Meet,
        })),
        "xMinYMax" => Ok(Some(Align {
            align: AlignMode::XminYmax,
            fit: FitMode::Meet,
        })),
        "xMidYMax" => Ok(Some(Align {
            align: AlignMode::XmidYmax,
            fit: FitMode::Meet,
        })),
        "xMaxYMax" => Ok(Some(Align {
            align: AlignMode::XmaxYmax,
            fit: FitMode::Meet,
        })),
        _ => Err(make_err()),
    }
}

fn parse_fit_mode(s: &str) -> Result<FitMode, AttributeError> {
    match s {
        "meet" => Ok(FitMode::Meet),
        "slice" => Ok(FitMode::Slice),
        _ => Err(make_err()),
    }
}

enum ParseState {
    Defer,
    Align,
    Fit,
    Finished,
}

fn make_err() -> AttributeError {
    AttributeError::Parse(ParseError::new(
        "expected \"[defer] <align> [meet | slice]\"",
    ))
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut defer = false;
        let mut align = Some(Align::default());
        let mut fit_mode = FitMode::Meet;

        let mut state = ParseState::Defer;

        for v in s.split_whitespace() {
            match state {
                ParseState::Defer => {
                    if v == "defer" {
                        defer = true;
                        state = ParseState::Align;
                    } else {
                        align = parse_align_mode(v)?;
                        state = ParseState::Fit;
                    }
                },

                ParseState::Align => {
                    align = parse_align_mode(v)?;
                    state = ParseState::Fit;
                },

                ParseState::Fit => {
                    fit_mode = parse_fit_mode(v)?;
                    state = ParseState::Finished;
                },

                _ => {
                    return Err(make_err());
                }
            }
        }

        // The string must match "[defer] <align> [meet | slice]".
        // Since the meet|slice is optional, we can end up in either
        // of the following states:
        match state {
            ParseState::Fit | ParseState::Finished => {}
            _ => {
                return Err(make_err());
            }
        }

        Ok(AspectRatio {
            defer,
            align: match align {
                None => None,
                Some(Align { align, .. }) => Some(Align {
                    align,
                    fit: fit_mode,
                }),
            },
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());

        assert!(AspectRatio::parse("defer", ()).is_err());

        assert!(AspectRatio::parse("defer foo", ()).is_err());

        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("xmidymid", ()).is_err());

        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            })
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    align: AlignMode::XmidYmid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XmidYmid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XminYmax,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XmaxYmid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XminYmax,
                    fit: FitMode::Slice,
                }),
            })
        );
    }

    #[test]
    fn aligns() {
        assert_eq!(
            AspectRatio::parse("xMinYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -99.0, 10.0, 100.0)
        );
    }
}
<commit_msg>aspect_ratio.rs: Simplify parse_align()<commit_after>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             align: AlignMode::XmidYmid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum AlignMode {
    XminYmin,
    XmidYmin,
    XmaxYmin,
    XminYmid,
    XmidYmid,
    XmaxYmid,
    XminYmax,
    XmidYmax,
    XmaxYmax,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    align: AlignMode,
    fit: FitMode,
}

#[derive(Debug, Copy, Clone)]
enum Align1D {
    Min,
    Mid,
    Max,
}

fn align_1d(a: Align1D, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
    match a {
        Align1D::Min => dest_pos,
        Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
        Align1D::Max => dest_pos + dest_size - obj_size,
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { align, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor: f64;

                match fit {
                    FitMode::Meet => {
                        factor = w_factor.min(h_factor);
                    }
                    FitMode::Slice => {
                        factor = w_factor.max(h_factor);
                    }
                }

                let w = object_width * factor;
                let h = object_height * factor;

                let xalign: Align1D;
                let yalign: Align1D;

                match align {
                    AlignMode::XminYmin => {
                        xalign = Align1D::Min;
                        yalign = Align1D::Min;
                    }
                    AlignMode::XminYmid => {
                        xalign = Align1D::Min;
                        yalign = Align1D::Mid;
                    }
                    AlignMode::XminYmax => {
                        xalign = Align1D::Min;
                        yalign = Align1D::Max;
                    }
                    AlignMode::XmidYmin => {
                        xalign = Align1D::Mid;
                        yalign = Align1D::Min;
                    }
                    AlignMode::XmidYmid => {
                        xalign = Align1D::Mid;
                        yalign = Align1D::Mid;
                    }
                    AlignMode::XmidYmax => {
                        xalign = Align1D::Mid;
                        yalign = Align1D::Max;
                    }
                    AlignMode::XmaxYmin => {
                        xalign = Align1D::Max;
                        yalign = Align1D::Min;
                    }
                    AlignMode::XmaxYmid => {
                        xalign = Align1D::Max;
                        yalign = Align1D::Mid;
                    }
                    AlignMode::XmaxYmax => {
                        xalign = Align1D::Max;
                        yalign = Align1D::Max;
                    }
                }

                let xpos = align_1d(xalign, dest_x, dest_width, w);
                let ypos = align_1d(yalign, dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }
}

impl Default for Align {
    fn default() -> Self {
        Align {
            align: AlignMode::XmidYmid,
            fit: FitMode::Meet,
        }
    }
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

fn parse_align(s: &str) -> Result<Option<AlignMode>, AttributeError> {
    match s {
        "none" => Ok(None),

        "xMinYMin" => Ok(Some(AlignMode::XminYmin)),
        "xMidYMin" => Ok(Some(AlignMode::XmidYmin)),
        "xMaxYMin" => Ok(Some(AlignMode::XmaxYmin)),

        "xMinYMid" => Ok(Some(AlignMode::XminYmid)),
        "xMidYMid" => Ok(Some(AlignMode::XmidYmid)),
        "xMaxYMid" => Ok(Some(AlignMode::XmaxYmid)),

        "xMinYMax" => Ok(Some(AlignMode::XminYmax)),
        "xMidYMax" => Ok(Some(AlignMode::XmidYmax)),
        "xMaxYMax" => Ok(Some(AlignMode::XmaxYmax)),

        _ => Err(make_err()),
    }
}

fn parse_fit_mode(s: &str) -> Result<FitMode, AttributeError> {
    match s {
        "meet" => Ok(FitMode::Meet),
        "slice" => Ok(FitMode::Slice),
        _ => Err(make_err()),
    }
}

enum ParseState {
    Defer,
    Align,
    Fit,
    Finished,
}

fn make_err() -> AttributeError {
    AttributeError::Parse(ParseError::new(
        "expected \"[defer] <align> [meet | slice]\"",
    ))
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut defer = false;
        let mut align = Some(AlignMode::XmidYmid);
        let mut fit_mode = FitMode::Meet;

        let mut state = ParseState::Defer;

        for v in s.split_whitespace() {
            match state {
                ParseState::Defer => {
                    if v == "defer" {
                        defer = true;
                        state = ParseState::Align;
                    } else {
                        align = parse_align(v)?;
                        state = ParseState::Fit;
                    }
                },

                ParseState::Align => {
                    align = parse_align(v)?;
                    state = ParseState::Fit;
                },

                ParseState::Fit => {
                    fit_mode = parse_fit_mode(v)?;
                    state = ParseState::Finished;
                },

                _ => {
                    return Err(make_err());
                }
            }
        }

        // The string must match "[defer] <align> [meet | slice]".
        // Since the meet|slice is optional, we can end up in either
        // of the following states:
        match state {
            ParseState::Fit | ParseState::Finished => {}
            _ => {
                return Err(make_err());
            }
        }

        Ok(AspectRatio {
            defer,
            align: match align {
                None => None,
                Some(align_mode) => Some(Align {
                    align: align_mode,
                    fit: fit_mode,
                }),
            },
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());

        assert!(AspectRatio::parse("defer", ()).is_err());

        assert!(AspectRatio::parse("defer foo", ()).is_err());

        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("xmidymid", ()).is_err());

        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            })
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    align: AlignMode::XmidYmid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XmidYmid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XminYmax,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XmaxYmid,
                    fit: FitMode::Meet,
                }),
            })
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    align: AlignMode::XminYmax,
                    fit: FitMode::Slice,
                }),
            })
        );
    }

    #[test]
    fn aligns() {
        assert_eq!(
            AspectRatio::parse("xMinYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0
            ),
            (0.0, -99.0, 10.0, 100.0)
        );
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

// NOTE: For the example to compile, you will need to first run the following:
//   rustup component add rustc-dev

// version: 1.53.0-nightly (9b0edb7fd 2021-03-27)

extern crate rustc_error_codes;
extern crate rustc_errors;
extern crate rustc_hash;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_session;
extern crate rustc_span;

use rustc_errors::registry;
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_session::config;
use rustc_span::source_map;
use std::path;
use std::process;
use std::str;

fn main() {
    let out = process::Command::new("rustc")
        .arg("--print=sysroot")
        .current_dir(".")
        .output()
        .unwrap();
    let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
    let config = rustc_interface::Config {
        // Command line options
        opts: config::Options {
            maybe_sysroot: Some(path::PathBuf::from(sysroot)),
            ..config::Options::default()
        },
        // cfg! configuration in addition to the default ones
        crate_cfg: FxHashSet::default(), // FxHashSet<(String, Option<String>)>
        input: config::Input::Str {
            name: source_map::FileName::Custom("main.rs".to_string()),
            input: "static HELLO: &str = \"Hello, world!\"; fn main() { println!(\"{}\", HELLO); }"
                .to_string(),
        },
        input_path: None,  // Option<PathBuf>
        output_dir: None,  // Option<PathBuf>
        output_file: None, // Option<PathBuf>
        file_loader: None, // Option<Box<dyn FileLoader + Send + Sync>>
        diagnostic_output: rustc_session::DiagnosticOutput::Default,
        // Set to capture stderr output during compiler execution
        stderr: None,                    // Option<Arc<Mutex<Vec<u8>>>>
        lint_caps: FxHashMap::default(), // FxHashMap<lint::LintId, lint::Level>
        // This is a callback from the driver that is called when [`ParseSess`] is created.
        parse_sess_created: None, //Option<Box<dyn FnOnce(&mut ParseSess) + Send>>
        // This is a callback from the driver that is called when we're registering lints;
        // it is called during plugin registration when we have the LintStore in a non-shared state.
        //
        // Note that if you find a Some here you probably want to call that function in the new
        // function being registered.
        register_lints: None, // Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>
        // This is a callback from the driver that is called just after we have populated
        // the list of queries.
        //
        // The second parameter is local providers and the third parameter is external providers.
        override_queries: None, // Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>
        // Registry of diagnostics codes.
        registry: registry::Registry::new(&rustc_error_codes::DIAGNOSTICS),
        make_codegen_backend: None,
    };
    rustc_interface::run_compiler(config, |compiler| {
        compiler.enter(|queries| {
            // Parse the program and print the syntax tree.
            let parse = queries.parse().unwrap().take();
            println!("{:#?}", parse);
            // Analyze the program and inspect the types of definitions.
            queries.global_ctxt().unwrap().take().enter(|tcx| {
                for (_, item) in &tcx.hir().krate().items {
                    match item.kind {
                        rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => {
                            let name = item.ident;
                            let ty = tcx.type_of(tcx.hir().local_def_id(item.hir_id()));
                            println!("{:?}:\t{:?}", name, ty)
                        }
                        _ => (),
                    }
                }
            })
        });
    });
}
<commit_msg>make it compile with 1.56.0<commit_after>#![feature(rustc_private)]

// NOTE: For the example to compile, you will need to first run the following:
//   rustup component add rustc-dev

// version: 1.53.0-nightly (9b0edb7fd 2021-03-27)

extern crate rustc_error_codes;
extern crate rustc_errors;
extern crate rustc_hash;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_session;
extern crate rustc_span;

use rustc_errors::registry;
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_session::config;
use rustc_span::source_map;
use std::path;
use std::process;
use std::str;

fn main() {
    let out = process::Command::new("rustc")
        .arg("--print=sysroot")
        .current_dir(".")
        .output()
        .unwrap();
    let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
    let config = rustc_interface::Config {
        // Command line options
        opts: config::Options {
            maybe_sysroot: Some(path::PathBuf::from(sysroot)),
            ..config::Options::default()
        },
        // cfg! configuration in addition to the default ones
        crate_cfg: FxHashSet::default(), // FxHashSet<(String, Option<String>)>
        input: config::Input::Str {
            name: source_map::FileName::Custom("main.rs".to_string()),
            input: "static HELLO: &str = \"Hello, world!\"; fn main() { println!(\"{}\", HELLO); }"
                .to_string(),
        },
        input_path: None,  // Option<PathBuf>
        output_dir: None,  // Option<PathBuf>
        output_file: None, // Option<PathBuf>
        file_loader: None, // Option<Box<dyn FileLoader + Send + Sync>>
        diagnostic_output: rustc_session::DiagnosticOutput::Default,
        // Set to capture stderr output during compiler execution
        stderr: None,                    // Option<Arc<Mutex<Vec<u8>>>>
        lint_caps: FxHashMap::default(), // FxHashMap<lint::LintId, lint::Level>
        // This is a callback from the driver that is called when [`ParseSess`] is created.
        parse_sess_created: None, //Option<Box<dyn FnOnce(&mut ParseSess) + Send>>
        // This is a callback from the driver that is called when we're registering lints;
        // it is called during plugin registration when we have the LintStore in a non-shared state.
        //
        // Note that if you find a Some here you probably want to call that function in the new
        // function being registered.
        register_lints: None, // Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>
        // This is a callback from the driver that is called just after we have populated
        // the list of queries.
        //
        // The second parameter is local providers and the third parameter is external providers.
        override_queries: None, // Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>
        // Registry of diagnostics codes.
        registry: registry::Registry::new(&rustc_error_codes::DIAGNOSTICS),
        make_codegen_backend: None,
    };
    rustc_interface::run_compiler(config, |compiler| {
        compiler.enter(|queries| {
            // Parse the program and print the syntax tree.
            let parse = queries.parse().unwrap().take();
            println!("{:#?}", parse);
            // Analyze the program and inspect the types of definitions.
            queries.global_ctxt().unwrap().take().enter(|tcx| {
                for item in tcx.hir().items() {
                    match item.kind {
                        rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => {
                            let name = item.ident;
                            let ty = tcx.type_of(tcx.hir().local_def_id(item.hir_id()));
                            println!("{:?}:\t{:?}", name, ty)
                        }
                        _ => (),
                    }
                }
            })
        });
    });
}
<|endoftext|>


<commit_before>extern crate getopts;
use std::io::Write;

pub struct HelpText<'a> {
    pub name : &'a str,
    pub version : &'a str,
    pub syntax : &'a str,
    pub summary : &'a str,
    pub long_help : &'a str,
    pub display_usage : bool
}

pub struct CoreOptions<'a> {
    options : getopts::Options,
    help_text : HelpText<'a>
}

impl<'a> CoreOptions<'a> {
    pub fn new(help_text: HelpText<'a>) -> Self {
        let mut ret = CoreOptions {
            options : getopts::Options::new(),
            help_text : help_text
        };
        ret.options
            .optflag("", "help", "print usage information")
            .optflag("", "version", "print name and version number");
        ret
    }
    pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optflagopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflag(short_name, long_name, desc);
        self
    }
    pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optopt(short_name, long_name, desc, hint);
        self
    }
    pub fn usage(&self, summary : &str) -> String {
        self.options.usage(summary)
    }
    pub fn parse(&mut self, args : Vec<String>) -> getopts::Matches {
        let matches = match self.options.parse(&args[1..]) {
            Ok(m) => { Some(m) },
            Err(f) => {
                pipe_write!(&mut ::std::io::stderr(), "{}: error: ", self.help_text.name);
                pipe_writeln!(&mut ::std::io::stderr(), "{}", f);
                ::std::process::exit(1);
            }
        }.unwrap();
        if matches.opt_present("help") {
            let usage_str = if self.help_text.display_usage {
                    format!("\n {}\n\n Reference\n",
                        self.options.usage(self.help_text.summary)
                    ).replace("Options:", " Options:")
                } else { String::new() };
            print!("
 {0} {1}

 {0} {2}
{3}{4}
", self.help_text.name, self.help_text.version, self.help_text.syntax, usage_str, self.help_text.long_help);
            exit!(0);
        } else if matches.opt_present("version") {
            println!("{} {}", self.help_text.name, self.help_text.version);
            exit!(0);
        }
        matches
    }
}

#[macro_export]
macro_rules! new_coreopts {
    ($syntax: expr, $summary: expr, $long_help: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: true
        })
    );
    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: $display_usage
        })
    );
}
<commit_msg>uucore: add support for optflagmulti and optmulti.<commit_after>extern crate getopts;
use std::io::Write;

pub struct HelpText<'a> {
    pub name : &'a str,
    pub version : &'a str,
    pub syntax : &'a str,
    pub summary : &'a str,
    pub long_help : &'a str,
    pub display_usage : bool
}

pub struct CoreOptions<'a> {
    options : getopts::Options,
    help_text : HelpText<'a>
}

impl<'a> CoreOptions<'a> {
    pub fn new(help_text: HelpText<'a>) -> Self {
        let mut ret = CoreOptions {
            options : getopts::Options::new(),
            help_text : help_text
        };
        ret.options
            .optflag("", "help", "print usage information")
            .optflag("", "version", "print name and version number");
        ret
    }
    pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optflagopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflag(short_name, long_name, desc);
        self
    }
    pub fn optflagmulti(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
        self.options.optflagmulti(short_name, long_name, desc);
        self
    }
    pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optopt(short_name, long_name, desc, hint);
        self
    }
    pub fn optmulti(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
        self.options.optmulti(short_name, long_name, desc, hint);
        self
    }
    pub fn usage(&self, summary : &str) -> String {
        self.options.usage(summary)
    }
    pub fn parse(&mut self, args : Vec<String>) -> getopts::Matches {
        let matches = match self.options.parse(&args[1..]) {
            Ok(m) => { Some(m) },
            Err(f) => {
                pipe_write!(&mut ::std::io::stderr(), "{}: error: ", self.help_text.name);
                pipe_writeln!(&mut ::std::io::stderr(), "{}", f);
                ::std::process::exit(1);
            }
        }.unwrap();
        if matches.opt_present("help") {
            let usage_str = if self.help_text.display_usage {
                    format!("\n {}\n\n Reference\n",
                        self.options.usage(self.help_text.summary)
                    ).replace("Options:", " Options:")
                } else { String::new() };
            print!("
 {0} {1}

 {0} {2}
{3}{4}
", self.help_text.name, self.help_text.version, self.help_text.syntax, usage_str, self.help_text.long_help);
            exit!(0);
        } else if matches.opt_present("version") {
            println!("{} {}", self.help_text.name, self.help_text.version);
            exit!(0);
        }
        matches
    }
}

#[macro_export]
macro_rules! new_coreopts {
    ($syntax: expr, $summary: expr, $long_help: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: true
        })
    );
    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => (
        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
            name: executable!(),
            version: env!("CARGO_PKG_VERSION"),
            syntax: $syntax,
            summary: $summary,
            long_help: $long_help,
            display_usage: $display_usage
        })
    );
}
<|endoftext|>


<commit_before>//! TODO documentation

use std::ptr;

use wlroots_sys::{wlr_output_cursor, wlr_output_cursor_create, wlr_output_cursor_destroy,
                  wlr_output_cursor_move, wlr_output_cursor_set_image,
                  wlr_output_cursor_set_surface};

use {wlroots_dehandle, render,
     output::{self, Output},
     surface::{self, Surface},
     utils::{Handleable, HandleResult}};

#[derive(Debug, Eq, PartialEq)]
pub struct Cursor {
    cursor: *mut wlr_output_cursor,
    output_handle: output::Handle
}

impl Cursor {
    /// Creates a new `output::Cursor` that's bound to the given `Output`.
    ///
    /// When the `Output` is destroyed each call will return an Error.
    ///
    /// # Ergonomics
    ///
    /// To make this easier for you, I would suggest putting the `output::Cursor` in your
    /// `OutputHandler` implementor's state so that when the `Output` is removed you
    /// just don't have to think about it and it will clean itself up by itself.
    pub fn new(output: &mut Output) -> Option<Cursor> {
        unsafe {
            let output_handle = output.weak_reference();
            let cursor = wlr_output_cursor_create(output.as_ptr());
            if cursor.is_null() {
                None
            } else {
                Some(Cursor { cursor,
                              output_handle })
            }
        }
    }

    /// Return a copy of the output handle used by this cursor.
    ///
    /// There are no guarantees that it is valid to use.
    pub fn output(&self) -> output::Handle {
        self.output_handle.clone()
    }

    /// Sets the hardware cursor's image.
    #[wlroots_dehandle]
    pub fn set_image(&mut self, image: &render::Image) -> HandleResult<bool> {
        unsafe {
            let cursor = self.cursor;
            #[dehandle] let _output = self.output_handle?;
            Ok(wlr_output_cursor_set_image(cursor,
                                           image.pixels.as_ptr(),
                                           image.stride,
                                           image.width,
                                           image.height,
                                           image.hotspot_x,
                                           image.hotspot_y))
        }
    }

    /// Sets the hardware cursor's surface.
    #[wlroots_dehandle]
    pub fn set_surface<'a, T>(&mut self, surface: T, hotspot_x: i32, hotspot_y: i32)
                              -> HandleResult<()>
    where T: Into<Option<&'a Surface>>
    {
        unsafe {
            let surface_ptr = surface.into()
                .map(|surface| surface.as_ptr())
                .unwrap_or_else(|| ptr::null_mut());
            #[dehandle] let _output = self.output_handle?;
            Ok(wlr_output_cursor_set_surface(self.cursor,
                                             surface_ptr,
                                             hotspot_x,
                                             hotspot_y))
        }
    }

    /// Moves the hardware cursor to the desired location
    #[wlroots_dehandle]
    pub fn move_to(&mut self, x: f64, y: f64) -> HandleResult<bool> {
        unsafe {
            #[dehandle] let _output = self.output_handle?;
            Ok(wlr_output_cursor_move(self.cursor, x, y))
        }
    }

    /// Get the coordinates of the cursor.
    ///
    /// Returned value is in (x, y) format.
    pub fn coords(&self) -> (f64, f64) {
        unsafe { ((*self.cursor).x, (*self.cursor).y) }
    }

    /// Determines if the hardware cursor is enabled or not.
    pub fn enabled(&self) -> bool {
        unsafe { (*self.cursor).enabled }
    }

    /// Determines if the hardware cursor is visible or not.
    pub fn visible(&self) -> bool {
        unsafe { (*self.cursor).visible }
    }

    /// Gets the width and height of the hardware cursor.
    ///
    /// Returned value is in (width, height) format.
    pub fn size(&self) -> (u32, u32) {
        unsafe { ((*self.cursor).width, (*self.cursor).height) }
    }

    /// Gets the hotspot coordinates of the hardware cursor.
    ///
    /// Returned value is in (x, y) coordinates.
    pub fn hotspots(&self) -> (i32, i32) {
        unsafe { ((*self.cursor).hotspot_x, (*self.cursor).hotspot_y) }
    }

    /// Gets the texture for the cursor, if a software cursor is used without a
    /// surface.
    pub fn texture<'surface>(&'surface self) -> Option<render::Texture<'surface>> {
        unsafe {
            let texture = (*self.cursor).texture;
            if texture.is_null() {
                None
            } else {
                Some(render::Texture::from_ptr(texture))
            }
        }
    }

    /// Gets the surface for the cursor, if using a cursor surface.
    pub fn surface(&self) -> Option<surface::Handle> {
        unsafe {
            let surface = (*self.cursor).surface;
            if surface.is_null() {
                None
            } else {
                Some(surface::Handle::from_ptr(surface))
            }
        }
    }
}

impl Drop for Cursor {
    fn drop(&mut self) {
        unsafe { wlr_output_cursor_destroy(self.cursor) }
    }
}
<commit_msg>Fix output cursor error handling<commit_after>//! TODO documentation

use std::ptr;

use wlroots_sys::{wlr_output_cursor, wlr_output_cursor_create, wlr_output_cursor_destroy,
                  wlr_output_cursor_move, wlr_output_cursor_set_image,
                  wlr_output_cursor_set_surface};

use {render,
     output::{self, Output},
     surface::{self, Surface},
     utils::{Handleable, HandleResult, HandleErr}};

#[derive(Debug, Eq, PartialEq)]
pub struct Cursor {
    cursor: *mut wlr_output_cursor,
    output_handle: output::Handle
}

impl Cursor {
    /// Creates a new `output::Cursor` that's bound to the given `Output`.
    ///
    /// When the `Output` is destroyed each call will return an Error.
    ///
    /// # Ergonomics
    ///
    /// To make this easier for you, I would suggest putting the `output::Cursor` in your
    /// `OutputHandler` implementor's state so that when the `Output` is removed you
    /// just don't have to think about it and it will clean itself up by itself.
    pub fn new(output: &mut Output) -> Option<Cursor> {
        unsafe {
            let output_handle = output.weak_reference();
            let cursor = wlr_output_cursor_create(output.as_ptr());
            if cursor.is_null() {
                None
            } else {
                Some(Cursor { cursor,
                              output_handle })
            }
        }
    }

    /// Return a copy of the output handle used by this cursor.
    ///
    /// There are no guarantees that it is valid to use.
    pub fn output(&self) -> output::Handle {
        self.output_handle.clone()
    }

    /// Sets the hardware cursor's image.
    pub fn set_image(&mut self, image: &render::Image) -> HandleResult<bool> {
        unsafe {
            let cursor = self.cursor;
            if !self.output_handle.is_alive() {
                return Err(HandleErr::AlreadyDropped)
            }
            Ok(wlr_output_cursor_set_image(cursor,
                                           image.pixels.as_ptr(),
                                           image.stride,
                                           image.width,
                                           image.height,
                                           image.hotspot_x,
                                           image.hotspot_y))
        }
    }

    /// Sets the hardware cursor's surface.
    pub fn set_surface<'a, T>(&mut self, surface: T, hotspot_x: i32, hotspot_y: i32)
                              -> HandleResult<()>
    where T: Into<Option<&'a Surface>>
    {
        unsafe {
            let surface_ptr = surface.into()
                .map(|surface| surface.as_ptr())
                .unwrap_or_else(|| ptr::null_mut());
            if !self.output_handle.is_alive() {
                return Err(HandleErr::AlreadyDropped)
            }
            Ok(wlr_output_cursor_set_surface(self.cursor,
                                             surface_ptr,
                                             hotspot_x,
                                             hotspot_y))
        }
    }

    /// Moves the hardware cursor to the desired location
    pub fn move_to(&mut self, x: f64, y: f64) -> HandleResult<bool> {
        unsafe {
            if !self.output_handle.is_alive() {
                return Err(HandleErr::AlreadyDropped)
            }
            Ok(wlr_output_cursor_move(self.cursor, x, y))
        }
    }

    /// Get the coordinates of the cursor.
    ///
    /// Returned value is in (x, y) format.
    pub fn coords(&self) -> (f64, f64) {
        unsafe { ((*self.cursor).x, (*self.cursor).y) }
    }

    /// Determines if the hardware cursor is enabled or not.
    pub fn enabled(&self) -> bool {
        unsafe { (*self.cursor).enabled }
    }

    /// Determines if the hardware cursor is visible or not.
    pub fn visible(&self) -> bool {
        unsafe { (*self.cursor).visible }
    }

    /// Gets the width and height of the hardware cursor.
    ///
    /// Returned value is in (width, height) format.
    pub fn size(&self) -> (u32, u32) {
        unsafe { ((*self.cursor).width, (*self.cursor).height) }
    }

    /// Gets the hotspot coordinates of the hardware cursor.
    ///
    /// Returned value is in (x, y) coordinates.
    pub fn hotspots(&self) -> (i32, i32) {
        unsafe { ((*self.cursor).hotspot_x, (*self.cursor).hotspot_y) }
    }

    /// Gets the texture for the cursor, if a software cursor is used without a
    /// surface.
    pub fn texture<'surface>(&'surface self) -> Option<render::Texture<'surface>> {
        unsafe {
            let texture = (*self.cursor).texture;
            if texture.is_null() {
                None
            } else {
                Some(render::Texture::from_ptr(texture))
            }
        }
    }

    /// Gets the surface for the cursor, if using a cursor surface.
    pub fn surface(&self) -> Option<surface::Handle> {
        unsafe {
            let surface = (*self.cursor).surface;
            if surface.is_null() {
                None
            } else {
                Some(surface::Handle::from_ptr(surface))
            }
        }
    }
}

impl Drop for Cursor {
    fn drop(&mut self) {
        unsafe { wlr_output_cursor_destroy(self.cursor) }
    }
}
<|endoftext|>