<commit_before>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(package, "edition", "2021");
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let dep = upsert_table(deps, &ext_lib.crate_name);
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let repo_url = match ext_package.as_str() {
            "cairo-sys-rs" | "gdk-pixbuf-sys" | "gio-sys" | "gobject-sys" | "glib-sys"
            | "graphene-sys" | "pango-sys" | "pangocairo-sys" => {
                "https://github.com/gtk-rs/gtk-rs-core"
            }
            "atk-sys" | "gdk-sys" | "gdkwayland-sys" | "gdkx11-sys" | "gtk-sys" => {
                "https://github.com/gtk-rs/gtk3-rs"
            }
            "gdk4-wayland-sys" | "gdk4-x11-sys" | "gdk4-sys" | "gsk4-sys" | "gtk4-sys" => {
                "https://github.com/gtk-rs/gtk4-rs"
            }
            "gstreamer-sys"
            | "gstreamer-app-sys"
            | "gstreamer-audio-sys"
            | "gstreamer-base-sys"
            | "gstreamer-check-sys"
            | "gstreamer-controller-sys"
            | "gstreamer-editing-services-sys"
            | "gstreamer-gl-sys"
            | "gstreamer-gl/egl-sys"
            | "gstreamer-gl/wayland-sys"
            | "gstreamer-gl/x11-sys"
            | "gstreamer-mpegts-sys"
            | "gstreamer-net-sys"
            | "gstreamer-pbutils-sys"
            | "gstreamer-player-sys"
            | "gstreamer-rtp-sys"
            | "gstreamer-rtsp-sys"
            | "gstreamer-rtsp-server-sys"
            | "gstreamer-sdp-sys"
            | "gstreamer-tag-sys"
            | "gstreamer-video-sys"
            | "gstreamer-webrtc-sys"
            | "gstreamer-allocators-sys" => "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs",
            &_ => "ADD GIT REPOSITORY URL HERE",
        };
        set_string(dep, "package", ext_package);
        set_string(dep, "git", repo_url);
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "6");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert(
            "dox".to_string(),
            Value::Array(
                env.config
                    .dox_feature_dependencies
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect(),
            ),
        );
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        // Allow both the name and version of a system dep to be overridden by hand
        meta.entry("name")
            .or_insert_with(|| Value::String(lib_name.to_owned()));
        meta.entry("version")
            .or_insert_with(|| Value::String(env.config.min_cfg_version.to_string()));

        // Old version API
        unset(meta, "feature-versions");

        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                let version_section = upsert_table(meta, &v.to_feature());
                // Allow system-deps version for this feature level to be overridden by hand
                version_section
                    .entry("version")
                    .or_insert_with(|| Value::String(lib_version.to_string()));
            });
    }

    {
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(Value::Table(lib)) = root.get("lib") {
        if let Some(Value::String(lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(Value::Table(package)) = root.get("package") {
        if let Some(Value::String(package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(table) = parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<commit_msg>Fix names of some gstreamer sys crates<commit_after>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(package, "edition", "2021");
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let dep = upsert_table(deps, &ext_lib.crate_name);
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let repo_url = match ext_package.as_str() {
            "cairo-sys-rs" | "gdk-pixbuf-sys" | "gio-sys" | "gobject-sys" | "glib-sys"
            | "graphene-sys" | "pango-sys" | "pangocairo-sys" => {
                "https://github.com/gtk-rs/gtk-rs-core"
            }
            "atk-sys" | "gdk-sys" | "gdkwayland-sys" | "gdkx11-sys" | "gtk-sys" => {
                "https://github.com/gtk-rs/gtk3-rs"
            }
            "gdk4-wayland-sys" | "gdk4-x11-sys" | "gdk4-sys" | "gsk4-sys" | "gtk4-sys" => {
                "https://github.com/gtk-rs/gtk4-rs"
            }
            "gstreamer-sys"
            | "gstreamer-app-sys"
            | "gstreamer-audio-sys"
            | "gstreamer-base-sys"
            | "gstreamer-check-sys"
            | "gstreamer-controller-sys"
            | "gstreamer-editing-services-sys"
            | "gstreamer-gl-sys"
            | "gstreamer-gl-egl-sys"
            | "gstreamer-gl-wayland-sys"
            | "gstreamer-gl-x11-sys"
            | "gstreamer-mpegts-sys"
            | "gstreamer-net-sys"
            | "gstreamer-pbutils-sys"
            | "gstreamer-player-sys"
            | "gstreamer-rtp-sys"
            | "gstreamer-rtsp-sys"
            | "gstreamer-rtsp-server-sys"
            | "gstreamer-sdp-sys"
            | "gstreamer-tag-sys"
            | "gstreamer-video-sys"
            | "gstreamer-webrtc-sys"
            | "gstreamer-allocators-sys" => "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs",
            &_ => "ADD GIT REPOSITORY URL HERE",
        };
        set_string(dep, "package", ext_package);
        set_string(dep, "git", repo_url);
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "6");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert(
            "dox".to_string(),
            Value::Array(
                env.config
                    .dox_feature_dependencies
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect(),
            ),
        );
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        // Allow both the name and version of a system dep to be overridden by hand
        meta.entry("name")
            .or_insert_with(|| Value::String(lib_name.to_owned()));
        meta.entry("version")
            .or_insert_with(|| Value::String(env.config.min_cfg_version.to_string()));

        // Old version API
        unset(meta, "feature-versions");

        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                let version_section = upsert_table(meta, &v.to_feature());
                // Allow system-deps version for this feature level to be overridden by hand
                version_section
                    .entry("version")
                    .or_insert_with(|| Value::String(lib_version.to_string()));
            });
    }

    {
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(Value::Table(lib)) = root.get("lib") {
        if let Some(Value::String(lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(Value::Table(package)) = root.get("package") {
        if let Some(Value::String(package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(table) = parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<|endoftext|>


<commit_before>//! Metamethods for accesssing the registry values!

use std::ops::Deref;

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::LuaString;

use registry;
use registry::{RegistryField, AccessFlags, LUA_WRITE};
use convert::ToTable;
use convert::json::lua_to_json;

pub fn index(_table: AnyLuaValue, lua_key: AnyLuaValue) -> AnyLuaValue {
    /*if let LuaString(key) = lua_key {
        if let Ok((access, json_arc)) = registry::get_json(&key) {
            if access.contains(registry::LUA_READ) {
                return json_arc.deref().clone().to_table();
            }
        }
    }*/
    AnyLuaValue::LuaNil
}

// Prevent lua from changing the registry?
pub fn new_index(_table: AnyLuaValue, lua_key: AnyLuaValue, val: AnyLuaValue)
                 -> Result<(), &'static str> {
    /*if let LuaString(key) = lua_key {
        let json = try!(lua_to_json(val).map_err(
            |_| "Unable to convert value to JSON!"));
        let mut reg = registry::write_lock();
        let flags: AccessFlags;
        if let Some(reg_val) = reg.get(&key) {
            if let Some((access, _old_arc)) = reg_val.get_data() {
                if !access.contains(LUA_WRITE) {
                    return Err("Unable to modify that key!");
                }
                flags = access;
            }
            else {
                return Err("Cannot modify a command!");
            }
        }
        else {
            return Err("Cannot create a new key! Use config.set instead.");
        }
        let new_val = RegistryValue::new_json(flags, json);
        reg.insert(key, new_val);
        return Err("That value does not yet exist!");
        // Putting an else here would mean allowing Lua code to create new keys
    }*/
    return Err("Invalid key!");
}

/// Method called on Lua code like `print(registry)`
pub fn to_string(_table: AnyLuaValue) -> &'static str {
    "A table used to share data with way-cooler"
}
<commit_msg>Re-implement Lua registry kind of<commit_after>//! Metamethods for accesssing the registry values!

use std::ops::Deref;
use std::sync::Arc;

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::LuaString;

use registry;
use registry::{RegistryField, AccessFlags, LUA_WRITE};
use convert::ToTable;
use convert::json::lua_to_json;

pub fn index(_table: AnyLuaValue, lua_key: AnyLuaValue) -> AnyLuaValue {
    if let LuaString(key) = lua_key {
        if let Ok((access, json_arc)) = registry::get_json(&key) {
            if access.contains(registry::LUA_READ) {
                return json_arc.deref().clone().to_table();
            }
        }
    }
    AnyLuaValue::LuaNil
}

// Prevent lua from changing the registry?
pub fn new_index(_table: AnyLuaValue, lua_key: AnyLuaValue, val: AnyLuaValue)
                 -> Result<(), &'static str> {
    if let LuaString(key) = lua_key {
        let json = try!(lua_to_json(val).map_err(
            |_| "Unable to convert value to JSON!"));
        let mut reg = registry::write_lock();
        let flags: AccessFlags;
        if let Some(reg_field) = reg.get(&key) {
            if let Some((access, _old_arc)) = reg_field.clone().as_object() {
                if !access.contains(LUA_WRITE) {
                    return Err("Unable to modify that key!");
                }
                flags = access;
            }
            else {
                return Err("Cannot modify a command!");
            }
        }
        else {
            return Err("Cannot create a new key! Use config.set instead.");
        }
        let new_val = RegistryField::Object {flags: flags, data: Arc::new(json) };
        reg.insert(key, new_val);
        return Err("That value does not yet exist!");
        // Putting an else here would mean allowing Lua code to create new keys
    }
    return Err("Invalid key!");
}

/// Method called on Lua code like `print(registry)`
pub fn to_string(_table: AnyLuaValue) -> &'static str {
    "A table used to share data with way-cooler"
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str;

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    // Check ability to use #[track_caller]:
    // https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute
    //
    // Perhaps sometime it will be possible to replace by built-in `version` attribute:
    // https://github.com/rust-lang/rust/issues/64796
    if minor >= 46 {
        println!("cargo:rustc-cfg=has_track_caller");
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<commit_msg>Update track_caller cfg link to show what version it's in<commit_after>use std::env;
use std::process::Command;
use std::str;

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    // #[track_caller] stabilized in Rust 1.46:
    // https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller
    if minor >= 46 {
        println!("cargo:rustc-cfg=has_track_caller");
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    pieces.next()?.parse().ok()
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::vec::Vec;

use super::*;
use super::ElementContent::*;
extern crate byteorder;

mod test;

pub fn generate(x: &Element) -> Vec<u8>
{
    let mut r = vec!();
    let id = match x.content {
        Unknown(id_, _) => id_,
        _ => super::database::class_to_id(x.class),
    };
    let mut data : Vec<u8> = match x.content {
        Binary(ref x) => (**x).clone(),
        Unsigned(x) => generate_big_endian_number(x),
        Signed(x) => generate_big_endian_number_s(x),
        Float(x) => {
            use self::byteorder::WriteBytesExt;
            use self::byteorder::BigEndian;
            let mut vv = vec![];
            vv.write_f32::<BigEndian>(x as f32);
            vv
        }
        Text(ref x) => (**x).clone().into_bytes(),
        Master(ref x) => {
            let mut vv = vec![];
            for i in x {
                vv.append( &mut generate(&*i) );
            }
            vv
        }
        MatroskaDate(x) => generate_big_endian_number_s(x),
        Unknown(_, ref x) => (**x).clone(),
    };

    r.append( &mut generate_ebml_number(id,                Mode::Identifier) );
    r.append( &mut generate_ebml_number(data.len() as u64, Mode::Unsigned) );
    r.append( &mut data );
    r
}

enum Mode {
    Unsigned,
    Identifier,
}

fn generate_ebml_number(x : u64, inputmode : Mode) -> Vec<u8>
{

    match inputmode {
        Mode::Identifier => generate_big_endian_number(x),
        Mode::Unsigned => {
            let mut r = vec!();
            if x == 0xFFFFFFFFFFFFFFFF { return vec!(0xFF); }

            let (numbytes, bit) = match x {
                v if v < 0x100             - 0x81             => (1, 0x80),
                v if v < 0x10000           - 0xC001           => (2, 0x40),
                v if v < 0x1000000         - 0xE00001         => (3, 0x20),
                v if v < 0x100000000       - 0xF0000001       => (4, 0x10),
                v if v < 0x10000000000     - 0xF800000001     => (5, 0x08),
                v if v < 0x1000000000000   - 0xFC0000000001   => (6, 0x04),
                v if v < 0x100000000000000 - 0xFE000000000001 => (7, 0x02),
                _                                             => (8, 0x01),
            };

            r.push( bit | ((x >> (numbytes-1)) as u8) );

            for i in 1..numbytes {
                r.push ( ((x >> ((numbytes-i-1)*8)) & 0xFF) as u8 );
            }
            r
        },
    }
}

fn generate_big_endian_number( x : u64) -> Vec<u8>
{
    let mut r = vec!();
    let numbytes = match x {
        v if v < 0x100              => 1,
        v if v < 0x10000            => 2,
        v if v < 0x1000000          => 3,
        v if v < 0x100000000        => 4,
        v if v < 0x10000000000      => 5,
        v if v < 0x1000000000000    => 6,
        v if v < 0x100000000000000  => 7,
        _                           => 8,
    };
    for i in 0..numbytes {
        r.push ( ((x >> ((numbytes-i-1)*8)) & 0xFF) as u8 );
    }
    r
}

fn generate_big_endian_number_s( x : i64) -> Vec<u8>
{
    let mut r = vec!();

    let numbytes = match x {
        v if -0x80             <= v && v < 0x80              => 1,
        v if -0x8000           <= v && v < 0x8000            => 2,
        v if -0x800000         <= v && v < 0x800000          => 3,
        v if -0x80000000       <= v && v < 0x80000000        => 4,
        v if -0x8000000000     <= v && v < 0x8000000000      => 5,
        v if -0x800000000000   <= v && v < 0x800000000000    => 6,
        v if -0x80000000000000 <= v && v < 0x80000000000000  => 7,
        _                                                    => 8,
    };
    for i in 0..numbytes {
        r.push ( ((x >> ((numbytes-i-1)*8)) & 0xFF) as u8 );
    }
    r
}
<commit_msg>Fix generate_ebml_number<commit_after>use std::rc::Rc;
use std::vec::Vec;

use super::*;
use super::ElementContent::*;
extern crate byteorder;

mod test;

pub fn generate(x: &Element) -> Vec<u8>
{
    let mut r = vec!();
    let id = match x.content {
        Unknown(id_, _) => id_,
        _ => super::database::class_to_id(x.class),
    };
    let mut data : Vec<u8> = match x.content {
        Binary(ref x) => (**x).clone(),
        Unsigned(x) => generate_big_endian_number(x),
        Signed(x) => generate_big_endian_number_s(x),
        Float(x) => {
            use self::byteorder::WriteBytesExt;
            use self::byteorder::BigEndian;
            let mut vv = vec![];
            vv.write_f32::<BigEndian>(x as f32);
            vv
        }
        Text(ref x) => (**x).clone().into_bytes(),
        Master(ref x) => {
            let mut vv = vec![];
            for i in x {
                vv.append( &mut generate(&*i) );
            }
            vv
        }
        MatroskaDate(x) => generate_big_endian_number_s(x),
        Unknown(_, ref x) => (**x).clone(),
    };

    r.append( &mut generate_ebml_number(id,                Mode::Identifier) );
    r.append( &mut generate_ebml_number(data.len() as u64, Mode::Unsigned) );
    r.append( &mut data );
    r
}

enum Mode {
    Unsigned,
    Identifier,
}

fn generate_ebml_number(x : u64, inputmode : Mode) -> Vec<u8>
{
    match inputmode {
        Mode::Identifier => generate_big_endian_number(x),
        Mode::Unsigned => {
            let mut r = vec!();
            if x == 0xFFFFFFFFFFFFFFFF { return vec!(0xFF); }

            let (numbytes, bit) = match x {
                v if v < 0x100             - 0x81             => (1, 0x80),
                v if v < 0x10000           - 0xC001           => (2, 0x40),
                v if v < 0x1000000         - 0xE00001         => (3, 0x20),
                v if v < 0x100000000       - 0xF0000001       => (4, 0x10),
                v if v < 0x10000000000     - 0xF800000001     => (5, 0x08),
                v if v < 0x1000000000000   - 0xFC0000000001   => (6, 0x04),
                v if v < 0x100000000000000 - 0xFE000000000001 => (7, 0x02),
                _                                             => (8, 0x01),
            };

            r.push( bit | ((x >> (numbytes-1)*8) as u8) );

            for i in 1..numbytes {
                r.push ( ((x >> ((numbytes-i-1)*8)) & 0xFF) as u8 );
            }
            r
        },
    }
}

fn generate_big_endian_number( x : u64) -> Vec<u8>
{
    let mut r = vec!();
    let numbytes = match x {
        v if v < 0x100              => 1,
        v if v < 0x10000            => 2,
        v if v < 0x1000000          => 3,
        v if v < 0x100000000        => 4,
        v if v < 0x10000000000      => 5,
        v if v < 0x1000000000000    => 6,
        v if v < 0x100000000000000  => 7,
        _                           => 8,
    };
    for i in 0..numbytes {
        r.push ( ((x >> ((numbytes-i-1)*8)) & 0xFF) as u8 );
    }
    r
}

fn generate_big_endian_number_s( x : i64) -> Vec<u8>
{
    let mut r = vec!();

    let numbytes = match x {
        v if -0x80             <= v && v < 0x80              => 1,
        v if -0x8000           <= v && v < 0x8000            => 2,
        v if -0x800000         <= v && v < 0x800000          => 3,
        v if -0x80000000       <= v && v < 0x80000000        => 4,
        v if -0x8000000000     <= v && v < 0x8000000000      => 5,
        v if -0x800000000000   <= v && v < 0x800000000000    => 6,
        v if -0x80000000000000 <= v && v < 0x80000000000000  => 7,
        _                                                    => 8,
    };
    for i in 0..numbytes {
        r.push ( ((x >> ((numbytes-i-1)*8)) & 0xFF) as u8 );
    }
    r
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Myers bit-parallel approximate pattern matching algorithm.
//! Finds all matches up to a given edit distance. The pattern has to fit into a bitvector,
//! and is here limited to 64 symbols.
//! Complexity: O(n)

use std::iter;

pub struct Myers {
    peq: [u64; 256],
    bound: u64,
    m: u8,
}

impl Myers {
    pub fn new(pattern: &[u8]) -> Self {
        assert!(pattern.len() <= 64 && pattern.len() > 0);

        let mut peq = [0; 256];
        for (i, &a) in pattern.iter().enumerate() {
            peq[a as usize] |= 1 << i;
        }

        Myers {
            peq: peq,
            bound: 1 << (pattern.len() -1),
            m: pattern.len() as u8,
        }
    }

    fn step(&self, state: &mut State, a: u8) {
        let eq = self.peq[a as usize];
        let xv = eq | state.mv;
        let xh = (((eq & state.pv) + state.pv) ^ state.pv) | eq;

        let mut ph = state.mv | !( xh | state.pv);
        let mut mh = state.pv & xh;

        if ph & self.bound > 0 {
            state.dist += 1;
        }
        else if mh & self.bound > 0 {
            state.dist -= 1;
        }

        ph <<= 1;
        mh <<= 1;
        state.pv = mh | !(xv | ph);
        state.mv = ph & xv;
    }

    pub fn distance(&self, text: &[u8]) -> u8 {
        let mut state = State::new(self.m);
        for &a in text {
            self.step(&mut state, a);
        }
        state.dist
    }

    // Find all occurences of pattern in the given text.
    pub fn find_all_end<'a, I: Iterator<Item=&'a u8>>(&'a self, text: I, max_dist: u8) -> Matches<I> {
        Matches { myers: self, state: State::new(self.m), text: text.enumerate(), max_dist: max_dist }
    }
}

struct State {
    pv: u64,
    mv: u64,
    dist: u8,
}

impl State {
    pub fn new(m: u8) -> Self {
        State { pv: (1 << m) - 1, mv: 0, dist: m }
    }
}

pub struct Matches<'a, I: Iterator<Item=&'a u8>> {
    myers: &'a Myers,
    state: State,
    text: iter::Enumerate<I>,
    max_dist: u8,
}

impl<'a, I: Iterator<Item=&'a u8>> Iterator for Matches<'a, I> {
    type Item = (usize, u8);

    fn next(&mut self) -> Option<(usize, u8)> {
        for (i, &a) in self.text.by_ref() {
            self.myers.step(&mut self.state, a);
            if self.state.dist <= self.max_dist {
                return Some((i, self.state.dist));
            }
        }
        None
    }
}

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

    #[test]
    fn test_find_all_end() {
        let text = b"ACCGTGGATGAGCGCCATAG";
        let pattern = b"TGAGCGT";
        let myers = Myers::new(pattern);
        let occ = myers.find_all_end(text.iter(), 1).collect_vec();
        assert_eq!(occ, [(13, 1), (14, 1)]);
    }
}
<commit_msg>Implement wildcard support for Myers bitparallel algorithm.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Myers bit-parallel approximate pattern matching algorithm.
//! Finds all matches up to a given edit distance. The pattern has to fit into a bitvector,
//! and is here limited to 64 symbols.
//! Complexity: O(n)

use std::iter;
use std::u64;

pub struct Myers {
    peq: [u64; 256],
    bound: u64,
    m: u8,
}

impl Myers {
    pub fn new(pattern: &[u8]) -> Self {
        assert!(pattern.len() <= 64 && pattern.len() > 0);

        let mut peq = [0; 256];
        for (i, &a) in pattern.iter().enumerate() {
            peq[a as usize] |= 1 << i;
        }

        Myers {
            peq: peq,
            bound: 1 << (pattern.len() -1),
            m: pattern.len() as u8,
        }
    }

    pub fn with_wildcard(pattern: &[u8], wildcard: u8) -> Self {
        let mut myers = Self::new(pattern);
        // wildcard matches all symbols of the pattern.
        myers.peq[wildcard as usize] = u64::MAX;

        myers
    }

    fn step(&self, state: &mut State, a: u8) {
        let eq = self.peq[a as usize];
        let xv = eq | state.mv;
        let xh = (((eq & state.pv) + state.pv) ^ state.pv) | eq;

        let mut ph = state.mv | !( xh | state.pv);
        let mut mh = state.pv & xh;

        if ph & self.bound > 0 {
            state.dist += 1;
        }
        else if mh & self.bound > 0 {
            state.dist -= 1;
        }

        ph <<= 1;
        mh <<= 1;
        state.pv = mh | !(xv | ph);
        state.mv = ph & xv;
    }

    pub fn distance(&self, text: &[u8]) -> u8 {
        let mut state = State::new(self.m);
        for &a in text {
            self.step(&mut state, a);
        }
        state.dist
    }

    // Find all occurences of pattern in the given text.
    pub fn find_all_end<'a, I: Iterator<Item=&'a u8>>(&'a self, text: I, max_dist: u8) -> Matches<I> {
        Matches { myers: self, state: State::new(self.m), text: text.enumerate(), max_dist: max_dist }
    }
}

struct State {
    pv: u64,
    mv: u64,
    dist: u8,
}

impl State {
    pub fn new(m: u8) -> Self {
        State { pv: (1 << m) - 1, mv: 0, dist: m }
    }
}

pub struct Matches<'a, I: Iterator<Item=&'a u8>> {
    myers: &'a Myers,
    state: State,
    text: iter::Enumerate<I>,
    max_dist: u8,
}

impl<'a, I: Iterator<Item=&'a u8>> Iterator for Matches<'a, I> {
    type Item = (usize, u8);

    fn next(&mut self) -> Option<(usize, u8)> {
        for (i, &a) in self.text.by_ref() {
            self.myers.step(&mut self.state, a);
            if self.state.dist <= self.max_dist {
                return Some((i, self.state.dist));
            }
        }
        None
    }
}

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

    #[test]
    fn test_find_all_end() {
        let text = b"ACCGTGGATGAGCGCCATAG";
        let pattern = b"TGAGCGT";
        let myers = Myers::new(pattern);
        let occ = myers.find_all_end(text.iter(), 1).collect_vec();
        assert_eq!(occ, [(13, 1), (14, 1)]);
    }

    #[test]
    fn test_distance() {
        let text = b"TGAGCNT";
        let pattern = b"TGAGCGT";

        let myers = Myers::new(pattern);
        assert_eq!(myers.distance(text), 1);

        let myers_wildcard = Myers::with_wildcard(pattern, b'N');
        assert_eq!(myers_wildcard.distance(text), 0);
    }
}
<|endoftext|>


<commit_before>#![crate_id="CSVProvider#0.1-pre"]
#![crate_type="dylib"]

// why doesn't "lib" work?
/*
CSVSample.rs:38:4: 38:21 error: macro undefined: 'ProvideCSV_labels'
CSVSample.rs:38    ProvideCSV_labels!("MyCSV", "./sample1.txt", "Verse");
                   ^~~~~~~~~~~~~~~~~
error: aborting due to previous error
 */

// rustc 0.11.0-pre (732e057 2014-06-06 01:21:54 -0700)
// host: x86_64-apple-darwin

#![feature(globs, macro_registrar, macro_rules, quote, managed_boxes)]

extern crate syntax;

use syntax::ast::{Name,
                  TokenTree,
                  Expr,
                  ExprLit,
                  ExprVec,
                  LitStr,
                  DUMMY_NODE_ID,
                  MutImmutable};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        DummyResult,
                        MacExpr,
                        NormalTT,
                        BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("ProvideCSV_labels"),
             NormalTT(box BasicMacroExpander {
                 expander: provide_csv_given_labels,
                 span: None,
             },
             None));
}

#[deriving(Clone)]
struct Entry {
    str: InternedString,
    expr: @Expr
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(
         cx.parse_sess(),
         cx.cfg(),
         tts.iter()
            .map(|x| (*x).clone())
            .collect()
    );

    let mut entries: Vec<Entry> = Vec::new();

    let mut error = false;
    while parser.token != EOF {
        let entry = parser.parse_expr();

        let entry_str = match entry.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(entry.span, "expected string literal");
                        error = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(entry.span, "expected string literal");
                error = true;
                InternedString::new("")
            }
        };

        entries.push(Entry { str: entry_str, expr: entry });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if error {
        return None;
    }

    Some(entries)
}

// FIXME: right now we only look at one column (CSV, haha)

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   //println!("provide_labels: args: {}", entries);

   let name   = entries.shift().expect("should be given a type name");
   let path   = entries.shift().expect("should be given a CSV file path");
   let labels = entries.shift().expect("should be given column labels");

   println!("provide_csv_given_labels: name:   {}", name.str);
   println!("provide_csv_given_labels: path:   {}", path.str);
   println!("provide_csv_given_labels: labels: {}", labels.str);

   return DummyResult::expr(sp);
}

<commit_msg>PENDING<commit_after>#![crate_id="CSVProvider#0.1-pre"]
#![crate_type="dylib"]

// why doesn't "lib" work?
/*
CSVSample.rs:38:4: 38:21 error: macro undefined: 'ProvideCSV_labels'
CSVSample.rs:38    ProvideCSV_labels!("MyCSV", "./sample1.txt", "Verse");
                   ^~~~~~~~~~~~~~~~~
error: aborting due to previous error
 */

// rustc 0.11.0-pre (732e057 2014-06-06 01:21:54 -0700)
// host: x86_64-apple-darwin

#![feature(globs, macro_registrar, macro_rules, quote, managed_boxes)]

extern crate syntax;

use syntax::ast::{Name,
                  TokenTree,
                  Expr,
                  ExprLit,
                  ExprVec,
                  LitStr,
                  DUMMY_NODE_ID,
                  MutImmutable};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        DummyResult,
                        MacExpr,
                        NormalTT,
                        BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("ProvideCSV_labels"),
             NormalTT(box BasicMacroExpander {
                 expander: provide_csv_given_labels,
                 span: None,
             },
             None));
}

#[deriving(Clone)]
struct Entry {
    str: InternedString,
    expr: @Expr
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(
         cx.parse_sess(),
         cx.cfg(),
         tts.iter()
            .map(|x| (*x).clone())
            .collect()
    );

    let mut entries: Vec<Entry> = Vec::new();

    let mut error = false;
    while parser.token != EOF {
        let entry = parser.parse_expr();

        let entry_str = match entry.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(entry.span, "expected string literal");
                        error = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(entry.span, "expected string literal");
                error = true;
                InternedString::new("")
            }
        };

        entries.push(Entry { str: entry_str, expr: entry });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if error {
        return None;
    }

    Some(entries)
}

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   let name   = entries.shift().expect("should be given a type name");
   let path   = entries.shift().expect("should be given a CSV file path");
   let labels = entries.shift().expect("should be given column labels");

   println!("provide_csv_given_labels: name:   {}", name.str);
   println!("provide_csv_given_labels: path:   {}", path.str);
   println!("provide_csv_given_labels: labels: {}", labels.str);

   // PENDING
   // read the CSV and try to get the type of data in it
   // create a type with
   //  * this name,
   //  * these labeled columns,
   //  * discovered type of data
   //  * a constructor which reads the whole file

   return DummyResult::expr(sp);
}

<|endoftext|>


<commit_before>#![crate_name="CSVProvider"]
#![crate_type="dylib"]

// why doesn't "lib" work?

// rustc 0.11.0-pre (b47f2226a25654c5b781d27a91f2fa5274b3a347 2014-06-28 14:31:37 +0000)

#![feature(globs, macro_rules, quote, managed_boxes, plugin_registrar)]

#![allow(unused_imports)]
//#![allow(unused_variable)]
#![allow(uppercase_variables)]
#![allow(unnecessary_parens)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{
   Name,
   TokenTree,
   Expr,
   ExprLit,
   ExprVec,
   LitStr,
   Ident,
   DUMMY_NODE_ID,
   MutImmutable
};
use syntax::codemap::Span;
use syntax::ext::base::{
   SyntaxExtension,
   BasicMacroExpander,
   ExtCtxt,
   MacResult,
   MacPat,
   MacItem,
   DummyResult,
   MacExpr,
   NormalTT
};
use std::gc::Gc;
use syntax::ext::quote::{
   //expand_parse_call
};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;
use syntax::ast;
use syntax::ast::Name;

use syntax::util::small_vector::SmallVector;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;

#[plugin_registrar]
pub fn macro_registrar(reg: &mut Registry) {
   reg.register_macro("ProvideCSV_labels", provide_csv_given_labels);
}

#[deriving(Clone)]
struct Entry {
   str: InternedString,
   expr: Gc<Expr>
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
   let mut parser = parse::new_parser_from_tts(
       cx.parse_sess(),
       cx.cfg(),
       tts.iter()
          .map(|x| (*x).clone())
          .collect()
   );

   let mut entries: Vec<Entry> = Vec::new();

   let mut error = false;
   while parser.token != EOF {
      let entry = parser.parse_expr();

      let entry_str = match entry.node {
         ExprLit(lit) => {
            match lit.node {
               LitStr(ref s, _) => s.clone(),
               _ => {
                  cx.span_err(entry.span, "expected string literal (1)");
                  error = true;
                  InternedString::new("")
               }
            }
         }
         _ => {
                cx.span_err(entry.span, "expected string literal (2)");
                error = true;
                InternedString::new("")
         }
      };

      entries.push(Entry { str: entry_str, expr: entry });

      if !parser.eat(&COMMA) && parser.token != EOF {
         cx.span_err(parser.span, "expected `,`");
         return None;
      }
    }

   if error {
      return None;
   }

   Some(entries)
}

pub struct MacItems {
   items: Vec<Gc<ast::Item>>
}
impl MacItems {
   pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
      box MacItems { items: items } as Box<MacResult>
   }
}
impl MacResult for MacItems {
   fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
      Some(SmallVector::many(self.items.clone()))
   }
}

fn parse_csv_row<'a>(raw: &'a str, expected_columns: Option<uint>) -> str::StrSplits<'a> {
   let mut it = raw.split_str(",");

   // take a pulse
   let _whatever = it.map(|xx| {
      println!("iterating over row elements: {}", xx.to_string());
      return xx;
   });

   match expected_columns {
      Some(count) => {
         if (count == it.count()) {
            println!("parse_csv_row: matching length expected");
         } else {
            println!("parse_csv_row: wrong length!");
         }
      },
      None => (),
   }

   return it;
}

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   let icx : &ExtCtxt = cx;  // an immutable borrow

   let raw_name   : Entry = entries.remove(0).expect("should be given a type name");
   let raw_path   : Entry = entries.remove(0).expect("should be given a CSV file path");
   let raw_labels : Entry = entries.remove(0).expect("should be given column labels");

   let name   : InternedString = raw_name.str;
   let path   : InternedString = raw_path.str;
   let labels : InternedString = raw_labels.str;

   println!("provide_csv_given_labels: name:   {}", name);
   println!("provide_csv_given_labels: path:   {}", path);
   println!("provide_csv_given_labels: labels: {}", labels);

   // PENDING
   // read the CSV and try to get the type of data in it
   // create a type with
   //  * this name,
   //  * these labeled columns,
   //  * discovered type of data
   //  * a constructor which reads the whole file

   fn interned_to_ident(xx: InternedString) -> Ident {
      let yy: String = format!("{}", xx);
      let zz: &str = yy.as_slice();
      return token::str_to_ident(zz);
   }

   fn interned_to_ident_with_suffix(xx: InternedString, suff: &str) -> Ident {
      let yy: String = format!("{}{}", xx, suff);
      let zz: &str = yy.as_slice();
      return token::str_to_ident(zz);
   }

   let MyCsv    = interned_to_ident(name.clone());
   let MyCsvRow = interned_to_ident_with_suffix(name, "Row");
   let col0     = interned_to_ident(labels.clone());

   println!("Parsing given labels...");

   let labels1 = format!("{}", labels);
   let labels_iter = parse_csv_row(labels1.as_slice(), None);

   println!("Defining items in the CSV provider...");

   // TODO: iterate through call columns
   let col = quote_item!(icx,
      pub $col0: String
   ).expect("column parsing");

   let item0 = quote_item!(icx,
      pub struct $MyCsvRow {
         $col,
      }
   );

   let item1: Option<Gc<syntax::ast::Item>> = quote_item!(icx,
      pub struct $MyCsv {
         pub data: Vec<$MyCsvRow>,
      }
   );

   let item2: Option<Gc<syntax::ast::Item>> = quote_item!(icx,
      impl $MyCsv {
         pub fn new() -> $MyCsv {
            println!("HMMMMMM.");
            return $MyCsv {
               data: (vec![
                  $MyCsvRow { $col0: "zero".to_string() },
                  $MyCsvRow { $col0:  "one".to_string() },
                  $MyCsvRow { $col0:  "two".to_string() },
               ]),
            };
         }
      }
   );

   let items = vec![item0.expect("Should be able to make struct MyCsvRow"),
                    item1.expect("Should be able to make struct MyCsv."),
                    item2.expect("Should be able to implement MyCsv.")];

   println!("OK");

   return MacItems::new(items);
}

<commit_msg>hmm, between 0.11 and 0.12, lifetime inference got better :D<commit_after>#![crate_name="CSVProvider"]
#![crate_type="dylib"]

// why doesn't "lib" work?

// rustc 0.11.0-pre (b47f2226a25654c5b781d27a91f2fa5274b3a347 2014-06-28 14:31:37 +0000)

#![feature(globs, macro_rules, quote, managed_boxes, plugin_registrar)]

#![allow(unused_imports)]
//#![allow(unused_variable)]
#![allow(uppercase_variables)]
#![allow(unnecessary_parens)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{
   Name,
   TokenTree,
   Expr,
   ExprLit,
   ExprVec,
   LitStr,
   Ident,
   DUMMY_NODE_ID,
   MutImmutable
};
use syntax::codemap::Span;
use syntax::ext::base::{
   SyntaxExtension,
   BasicMacroExpander,
   ExtCtxt,
   MacResult,
   MacPat,
   MacItem,
   DummyResult,
   MacExpr,
   NormalTT
};
use std::gc::Gc;
use syntax::ext::quote::{
   //expand_parse_call
};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;
use syntax::ast;
use syntax::ast::Name;

use syntax::util::small_vector::SmallVector;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;

#[plugin_registrar]
pub fn macro_registrar(reg: &mut Registry) {
   reg.register_macro("ProvideCSV_labels", provide_csv_given_labels);
}

#[deriving(Clone)]
struct Entry {
   str: InternedString,
   expr: Gc<Expr>
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
   let mut parser = parse::new_parser_from_tts(
       cx.parse_sess(),
       cx.cfg(),
       tts.iter()
          .map(|x| (*x).clone())
          .collect()
   );

   let mut entries: Vec<Entry> = Vec::new();

   let mut error = false;
   while parser.token != EOF {
      let entry = parser.parse_expr();

      let entry_str = match entry.node {
         ExprLit(lit) => {
            match lit.node {
               LitStr(ref s, _) => s.clone(),
               _ => {
                  cx.span_err(entry.span, "expected string literal (1)");
                  error = true;
                  InternedString::new("")
               }
            }
         }
         _ => {
                cx.span_err(entry.span, "expected string literal (2)");
                error = true;
                InternedString::new("")
         }
      };

      entries.push(Entry { str: entry_str, expr: entry });

      if !parser.eat(&COMMA) && parser.token != EOF {
         cx.span_err(parser.span, "expected `,`");
         return None;
      }
    }

   if error {
      return None;
   }

   Some(entries)
}

pub struct MacItems {
   items: Vec<Gc<ast::Item>>
}
impl MacItems {
   pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
      box MacItems { items: items } as Box<MacResult>
   }
}
impl MacResult for MacItems {
   fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
      Some(SmallVector::many(self.items.clone()))
   }
}

fn parse_csv_row(raw: &str, expected_columns: Option<uint>) -> str::StrSplits {
   let mut it = raw.split_str(",");

   // take a pulse
   let _whatever = it.map(|xx| {
      println!("iterating over row elements: {}", xx.to_string());
      return xx;
   });

   match expected_columns {
      Some(count) => {
         if (count == it.count()) {
            println!("parse_csv_row: matching length expected");
         } else {
            println!("parse_csv_row: wrong length!");
         }
      },
      None => (),
   }

   return it;
}

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   let icx : &ExtCtxt = cx;  // an immutable borrow

   let raw_name   : Entry = entries.remove(0).expect("should be given a type name");
   let raw_path   : Entry = entries.remove(0).expect("should be given a CSV file path");
   let raw_labels : Entry = entries.remove(0).expect("should be given column labels");

   let name   : InternedString = raw_name.str;
   let path   : InternedString = raw_path.str;
   let labels : InternedString = raw_labels.str;

   println!("provide_csv_given_labels: name:   {}", name);
   println!("provide_csv_given_labels: path:   {}", path);
   println!("provide_csv_given_labels: labels: {}", labels);

   // PENDING
   // read the CSV and try to get the type of data in it
   // create a type with
   //  * this name,
   //  * these labeled columns,
   //  * discovered type of data
   //  * a constructor which reads the whole file

   fn interned_to_ident(xx: InternedString) -> Ident {
      let yy: String = format!("{}", xx);
      let zz: &str = yy.as_slice();
      return token::str_to_ident(zz);
   }

   fn interned_to_ident_with_suffix(xx: InternedString, suff: &str) -> Ident {
      let yy: String = format!("{}{}", xx, suff);
      let zz: &str = yy.as_slice();
      return token::str_to_ident(zz);
   }

   let MyCsv    = interned_to_ident(name.clone());
   let MyCsvRow = interned_to_ident_with_suffix(name, "Row");
   let col0     = interned_to_ident(labels.clone());

   println!("Parsing given labels...");

   let labels1 = format!("{}", labels);
   let labels_iter = parse_csv_row(labels1.as_slice(), None);

   println!("Defining items in the CSV provider...");

   // TODO: iterate through call columns
   let col = quote_item!(icx,
      pub $col0: String
   ).expect("column parsing");

   let item0 = quote_item!(icx,
      pub struct $MyCsvRow {
         $col,
      }
   );

   let item1: Option<Gc<syntax::ast::Item>> = quote_item!(icx,
      pub struct $MyCsv {
         pub data: Vec<$MyCsvRow>,
      }
   );

   let item2: Option<Gc<syntax::ast::Item>> = quote_item!(icx,
      impl $MyCsv {
         pub fn new() -> $MyCsv {
            println!("HMMMMMM.");
            return $MyCsv {
               data: (vec![
                  $MyCsvRow { $col0: "zero".to_string() },
                  $MyCsvRow { $col0:  "one".to_string() },
                  $MyCsvRow { $col0:  "two".to_string() },
               ]),
            };
         }
      }
   );

   let items = vec![item0.expect("Should be able to make struct MyCsvRow"),
                    item1.expect("Should be able to make struct MyCsv."),
                    item2.expect("Should be able to implement MyCsv.")];

   println!("OK");

   return MacItems::new(items);
}

<|endoftext|>


<commit_before>use std::fmt; // Import the `fmt` module.

// Define a structure named `List` containing a `Vec`.
struct List(Vec<i32>);

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Dereference `self` and create a reference to `vec`
        // via destructuring.
        let List(ref vec) = *self;

        try!(write!(f, "["));

        // Iterate over `vec` in `v` while enumerating the iteration
        // count in `count`.
        for (count, v) in vec.iter().enumerate() {
            // For every element except the first, add a comma
            // before calling `write!`. Use `try!` to return on errors.
            if count != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{}", v));
        }

        // Close the opened bracket and return a fmt::Result value
        write!(f, "]")
    }
}

fn main() {
    let v = List(vec![1, 2, 3]);
    println!("{}", v);
}
<commit_msg>examples/hello/print/print_display/testcase_list/testcase_list.rs<commit_after>use std::fmt; // 导入 `fmt` 模块。

// 定义一个包含不同包含 `Vec` 的结构体 `List`。
struct List(Vec<i32>);

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // 对 `self` 解引用，并通过解构创建一个指向 `vec` 的引用。
        let List(ref vec) = *self;

        try!(write!(f, "["));

        // 对 `vec` 进行迭代，`v` 为每次迭代的值，`count` 为计数。
        for (count, v) in vec.iter().enumerate() {
            // 在调用 `write!` 前对每个元素（第一个元素除外）加上逗号。
            // 使用 `try!` ，在出错的情况返回。
            if count != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{}", v));
        }

        // 加上配对中括号，并返回一个 fmt::Result 值
        write!(f, "]")
    }
}

fn main() {
    let v = List(vec![1, 2, 3]);
    println!("{}", v);
}
<|endoftext|>


<commit_before><commit_msg>rand_distr: make Pareto generic over Float<commit_after><|endoftext|>


<commit_before>use crate::masm::CondCode;
use dora_asm::arm64::Cond;

#[cfg(target_os = "macos")]
pub fn flush_icache(start: *const u8, len: usize) {
    extern "C" {
        fn sys_icache_invalidate(data: *const u8, len: usize);
    }

    unsafe {
        sys_icache_invalidate(start, len);
    }
}

#[cfg(not(target_os = "macos"))]
pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            llvm_asm!("dc civac, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += dcacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish" ::: "memory" : "volatile");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            llvm_asm!("ic ivau, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += icacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish
              isb" ::: "memory" : "volatile");
    }
}

#[cfg(not(target_os = "macos"))]
pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        llvm_asm!("mrs $0, ctr_el0": "=r"(value)::: "volatile");
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn has_round() -> bool {
    true
}

pub fn has_popcnt() -> bool {
    true
}

pub fn has_lzcnt() -> bool {
    true
}

pub fn has_tzcnt() -> bool {
    true
}

impl From<CondCode> for Cond {
    fn from(c: CondCode) -> Cond {
        match c {
            CondCode::Zero => Cond::EQ,
            CondCode::NonZero => Cond::NE,
            CondCode::Equal => Cond::EQ,
            CondCode::NotEqual => Cond::NE,
            CondCode::Greater => Cond::GT,
            CondCode::GreaterEq => Cond::GE,
            CondCode::Less => Cond::LT,
            CondCode::LessEq => Cond::LE,
            CondCode::UnsignedGreater => Cond::HI,
            CondCode::UnsignedGreaterEq => Cond::HS,
            CondCode::UnsignedLess => Cond::LO,
            CondCode::UnsignedLessEq => Cond::LS,
        }
    }
}

use crate::cpu::{FReg, Reg};
use crate::ty::SourceType;
use dora_asm::arm64 as asm;
use dora_asm::arm64::Register;

pub static REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static CCALL_REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static CCALL_FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static SCRATCH: [Reg; 5] = [R9, R12, R13, R14, R15];

pub const REG_RESULT: Reg = R0;
pub const REG_TMP1: Reg = R10;
pub const REG_TMP2: Reg = R11;
pub const REG_FP: Reg = R29;
pub const REG_LR: Reg = R30;
pub const REG_THREAD: Reg = R28;

pub const REG_SP: Reg = Reg(32);
pub const REG_ZERO: Reg = Reg(33);

pub const FREG_RESULT: FReg = F0;

// shall not overlap with param registers
pub const FREG_TMP1: FReg = F16;

pub const STACK_FRAME_ALIGNMENT: usize = 16;

pub const R0: Reg = Reg(0);
pub const R1: Reg = Reg(1);
pub const R2: Reg = Reg(2);
pub const R3: Reg = Reg(3);
pub const R4: Reg = Reg(4);
pub const R5: Reg = Reg(5);
pub const R6: Reg = Reg(6);
pub const R7: Reg = Reg(7);
pub const R8: Reg = Reg(8);
pub const R9: Reg = Reg(9);
pub const R10: Reg = Reg(10);
pub const R11: Reg = Reg(11);
pub const R12: Reg = Reg(12);
pub const R13: Reg = Reg(13);
pub const R14: Reg = Reg(14);
pub const R15: Reg = Reg(15);
pub const R16: Reg = Reg(16);
pub const R17: Reg = Reg(17);
pub const R18: Reg = Reg(18);
pub const R19: Reg = Reg(19);
pub const R20: Reg = Reg(20);
pub const R21: Reg = Reg(21);
pub const R22: Reg = Reg(22);
pub const R23: Reg = Reg(23);
pub const R24: Reg = Reg(24);
pub const R25: Reg = Reg(25);
pub const R26: Reg = Reg(26);
pub const R27: Reg = Reg(27);
pub const R28: Reg = Reg(28);
pub const R29: Reg = Reg(29);
pub const R30: Reg = Reg(30);

pub const F0: FReg = FReg(0);
pub const F1: FReg = FReg(1);
pub const F2: FReg = FReg(2);
pub const F3: FReg = FReg(3);
pub const F4: FReg = FReg(4);
pub const F5: FReg = FReg(5);
pub const F6: FReg = FReg(6);
pub const F7: FReg = FReg(7);
pub const F8: FReg = FReg(8);
pub const F9: FReg = FReg(9);
pub const F10: FReg = FReg(10);
pub const F11: FReg = FReg(11);
pub const F12: FReg = FReg(12);
pub const F13: FReg = FReg(13);
pub const F14: FReg = FReg(14);
pub const F15: FReg = FReg(15);
pub const F16: FReg = FReg(16);
pub const F17: FReg = FReg(17);
pub const F18: FReg = FReg(18);
pub const F19: FReg = FReg(19);
pub const F20: FReg = FReg(20);
pub const F21: FReg = FReg(21);
pub const F22: FReg = FReg(22);
pub const F23: FReg = FReg(23);
pub const F24: FReg = FReg(24);
pub const F25: FReg = FReg(25);
pub const F26: FReg = FReg(26);
pub const F27: FReg = FReg(27);
pub const F28: FReg = FReg(28);
pub const F29: FReg = FReg(29);
pub const F30: FReg = FReg(30);
pub const F31: FReg = FReg(31);

impl Reg {
    pub fn asm(self) -> u32 {
        match self {
            REG_SP => 31,
            REG_ZERO => 31,
            _ => self.0 as u32,
        }
    }

    pub fn is_gpr(self) -> bool {
        self.0 <= 30
    }

    pub fn is_gpr_or_zero(self) -> bool {
        self.is_gpr() || self == REG_ZERO
    }

    pub fn is_gpr_or_sp(self) -> bool {
        self.is_gpr() || self == REG_SP
    }
}

impl From<Reg> for Register {
    fn from(reg: Reg) -> Register {
        if reg.0 < 31 {
            Register::new(reg.0)
        } else if reg == REG_ZERO {
            asm::REG_ZERO
        } else {
            assert_eq!(reg, REG_SP);
            asm::REG_SP
        }
    }
}

impl FReg {
    pub fn asm(self) -> u32 {
        assert!(self.0 < 32);
        self.0 as u32
    }
}

pub static PARAM_OFFSET: i32 = 16;

pub fn next_param_offset(param_offset: i32, _: SourceType) -> i32 {
    param_offset + 8
}
<commit_msg>arm64: add method to detect lse atomics<commit_after>use crate::masm::CondCode;
use dora_asm::arm64::Cond;

#[cfg(target_os = "macos")]
pub fn flush_icache(start: *const u8, len: usize) {
    extern "C" {
        fn sys_icache_invalidate(data: *const u8, len: usize);
    }

    unsafe {
        sys_icache_invalidate(start, len);
    }
}

#[cfg(not(target_os = "macos"))]
pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            llvm_asm!("dc civac, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += dcacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish" ::: "memory" : "volatile");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            llvm_asm!("ic ivau, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += icacheline_size;
    }

    unsafe {
        llvm_asm!("dsb ish
              isb" ::: "memory" : "volatile");
    }
}

#[cfg(target_os = "macos")]
pub fn supports_lse_atomic() -> bool {
    use std::ffi::CString;

    unsafe {
        let mut oldbuffer: usize = 0;
        let mut oldlenp: libc::size_t = 4;
        let name = CString::new("hw.optional.armv8_1_atomics").unwrap();
        let result = libc::sysctlbyname(
            name.as_ptr(),
            &mut oldbuffer as *mut usize as *mut libc::c_void,
            &mut oldlenp,
            std::ptr::null_mut(),
            0,
        );
        assert_eq!(result, 0);
        oldbuffer != 0
    }
}

#[cfg(not(target_os = "macos"))]
pub fn supports_lse_atomic() -> bool {
    false
}

#[cfg(not(target_os = "macos"))]
pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        llvm_asm!("mrs $0, ctr_el0": "=r"(value)::: "volatile");
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn has_round() -> bool {
    true
}

pub fn has_popcnt() -> bool {
    true
}

pub fn has_lzcnt() -> bool {
    true
}

pub fn has_tzcnt() -> bool {
    true
}

impl From<CondCode> for Cond {
    fn from(c: CondCode) -> Cond {
        match c {
            CondCode::Zero => Cond::EQ,
            CondCode::NonZero => Cond::NE,
            CondCode::Equal => Cond::EQ,
            CondCode::NotEqual => Cond::NE,
            CondCode::Greater => Cond::GT,
            CondCode::GreaterEq => Cond::GE,
            CondCode::Less => Cond::LT,
            CondCode::LessEq => Cond::LE,
            CondCode::UnsignedGreater => Cond::HI,
            CondCode::UnsignedGreaterEq => Cond::HS,
            CondCode::UnsignedLess => Cond::LO,
            CondCode::UnsignedLessEq => Cond::LS,
        }
    }
}

use crate::cpu::{FReg, Reg};
use crate::ty::SourceType;
use dora_asm::arm64 as asm;
use dora_asm::arm64::Register;

pub static REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static CCALL_REG_PARAMS: [Reg; 8] = [R0, R1, R2, R3, R4, R5, R6, R7];
pub static CCALL_FREG_PARAMS: [FReg; 8] = [F0, F1, F2, F3, F4, F5, F6, F7];

pub static SCRATCH: [Reg; 5] = [R9, R12, R13, R14, R15];

pub const REG_RESULT: Reg = R0;
pub const REG_TMP1: Reg = R10;
pub const REG_TMP2: Reg = R11;
pub const REG_FP: Reg = R29;
pub const REG_LR: Reg = R30;
pub const REG_THREAD: Reg = R28;

pub const REG_SP: Reg = Reg(32);
pub const REG_ZERO: Reg = Reg(33);

pub const FREG_RESULT: FReg = F0;

// shall not overlap with param registers
pub const FREG_TMP1: FReg = F16;

pub const STACK_FRAME_ALIGNMENT: usize = 16;

pub const R0: Reg = Reg(0);
pub const R1: Reg = Reg(1);
pub const R2: Reg = Reg(2);
pub const R3: Reg = Reg(3);
pub const R4: Reg = Reg(4);
pub const R5: Reg = Reg(5);
pub const R6: Reg = Reg(6);
pub const R7: Reg = Reg(7);
pub const R8: Reg = Reg(8);
pub const R9: Reg = Reg(9);
pub const R10: Reg = Reg(10);
pub const R11: Reg = Reg(11);
pub const R12: Reg = Reg(12);
pub const R13: Reg = Reg(13);
pub const R14: Reg = Reg(14);
pub const R15: Reg = Reg(15);
pub const R16: Reg = Reg(16);
pub const R17: Reg = Reg(17);
pub const R18: Reg = Reg(18);
pub const R19: Reg = Reg(19);
pub const R20: Reg = Reg(20);
pub const R21: Reg = Reg(21);
pub const R22: Reg = Reg(22);
pub const R23: Reg = Reg(23);
pub const R24: Reg = Reg(24);
pub const R25: Reg = Reg(25);
pub const R26: Reg = Reg(26);
pub const R27: Reg = Reg(27);
pub const R28: Reg = Reg(28);
pub const R29: Reg = Reg(29);
pub const R30: Reg = Reg(30);

pub const F0: FReg = FReg(0);
pub const F1: FReg = FReg(1);
pub const F2: FReg = FReg(2);
pub const F3: FReg = FReg(3);
pub const F4: FReg = FReg(4);
pub const F5: FReg = FReg(5);
pub const F6: FReg = FReg(6);
pub const F7: FReg = FReg(7);
pub const F8: FReg = FReg(8);
pub const F9: FReg = FReg(9);
pub const F10: FReg = FReg(10);
pub const F11: FReg = FReg(11);
pub const F12: FReg = FReg(12);
pub const F13: FReg = FReg(13);
pub const F14: FReg = FReg(14);
pub const F15: FReg = FReg(15);
pub const F16: FReg = FReg(16);
pub const F17: FReg = FReg(17);
pub const F18: FReg = FReg(18);
pub const F19: FReg = FReg(19);
pub const F20: FReg = FReg(20);
pub const F21: FReg = FReg(21);
pub const F22: FReg = FReg(22);
pub const F23: FReg = FReg(23);
pub const F24: FReg = FReg(24);
pub const F25: FReg = FReg(25);
pub const F26: FReg = FReg(26);
pub const F27: FReg = FReg(27);
pub const F28: FReg = FReg(28);
pub const F29: FReg = FReg(29);
pub const F30: FReg = FReg(30);
pub const F31: FReg = FReg(31);

impl Reg {
    pub fn asm(self) -> u32 {
        match self {
            REG_SP => 31,
            REG_ZERO => 31,
            _ => self.0 as u32,
        }
    }

    pub fn is_gpr(self) -> bool {
        self.0 <= 30
    }

    pub fn is_gpr_or_zero(self) -> bool {
        self.is_gpr() || self == REG_ZERO
    }

    pub fn is_gpr_or_sp(self) -> bool {
        self.is_gpr() || self == REG_SP
    }
}

impl From<Reg> for Register {
    fn from(reg: Reg) -> Register {
        if reg.0 < 31 {
            Register::new(reg.0)
        } else if reg == REG_ZERO {
            asm::REG_ZERO
        } else {
            assert_eq!(reg, REG_SP);
            asm::REG_SP
        }
    }
}

impl FReg {
    pub fn asm(self) -> u32 {
        assert!(self.0 < 32);
        self.0 as u32
    }
}

pub static PARAM_OFFSET: i32 = 16;

pub fn next_param_offset(param_offset: i32, _: SourceType) -> i32 {
    param_offset + 8
}
<|endoftext|>


<commit_before>// Kevin Cantu
// replace djb with murmur

use std;

fn djb(&&ss: str) -> uint {
   // default str::hash
   // https://github.com/graydon/rust/blob/master/src/libcore/str.rs at ll. 43-50
   let uu: uint = 5381u;
   for cc: u8 in ss { uu *= 33u; uu += cc as uint; }
   ret uu;
}

// translate to hex
fn murmur_str(&&ss: str) -> str {
   let mm = murmur(ss);
   ret #fmt("%016x%016x", mm[0], mm[1]);
}

// murmur3 x64 128-bit
fn murmur(&&key_: str) -> [u64] {

   let key = str::bytes (key_);
   let data = key;
   let len = vec::len(key);
   let nblocks = len / 16u;

   // TODO: random seeds
   let seed = 0u64;
   let hh = [seed,seed];

   let cc = [ 0x_87c37b91114253d5_u64,
              0x_4cf5ad432745937f_u64 ];

   // rotation left
   fn rotl64 (x: u64, r: u64) -> u64 {
      ret (x << r) | (x >> (64u-r));
   }

   // conversion from 8 to 64 bits
   pure fn isEight (bytes: [u8]) -> bool {
      ret vec::len(bytes) == 8u;
   }

   fn convert_eight_u8_to_one_u64 (bb: [u8]) -> u64 {
      check isEight(bb);
      ret vec::foldl(0u64, bb, {|w, b| (w << 8u) + (b as u64)});
   }

   #[test]
   fn test_conversion_u8to64 () {
      //let XXXX = convert_u8to64 ([1u8,2u8]);
      let aa = [255u8,0u8,8u8,0u8, 20u8,0u8,0u8,1u8];
      std::io::println(#fmt("converted: %016x", convert_eight_u8_to_one_u64 (aa)));
   }

   fn convert_u8to64 (bb: [u8]) -> [u64] {
      fn lesser <copy TT> (aa: TT, bb: TT) -> TT {
         if aa < bb { aa } else { bb }
      }

      // windowing
      fn windowed <copy TT> (nn: uint, xs: [TT]) -> [[TT]] {
         let ws: [[TT]] = [];
         vec::iteri (xs, {|ii, x|
            let len: uint = vec::len(xs);
            if ii+(nn) < len {
               let w: [TT] = vec::slice ( xs, ii, ii+nn );
               vec::push (ws, w);
            }
         });
         ret ws;
      }

      // split into vector^2
      fn splitEvery <copy TT> (nn: uint, xs: [TT]) -> [[TT]] {
         let ys: [[TT]] = [];
         vec::iteri (xs, {|ii, x|
            let len = vec::len(xs);
            if ii % nn == 0u && ii < len {
               let y = vec::slice (xs, ii, lesser(nn+ii, len));
               vec::push (ys, y);
            }
         });
         ret ys;
      }

      let bbs = splitEvery(8u, bb);
      ret vec::map ( bbs, {|xs|
         convert_eight_u8_to_one_u64(xs)
      });
   }

   // fmix
   fn fmix (k_: u64) -> u64 {
      let kk = k_;

      kk ^= kk >> 33u;
      kk *= 0x_ff51afd7ed558ccd_u64;
      kk ^= kk >> 33u;
      kk *= 0x_c4ceb9fe1a85ec53_u64;
      kk ^= kk >> 33u;

      ret kk;
   }

   let blocks = convert_u8to64 ([0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8]);

   // TODO: truncate to u64 for djb replacement
   ret [1u64, 1u64];
}

<commit_msg>note on original<commit_after>// Kevin Cantu
// replace djb with murmur

use std;

fn djb(&&ss: str) -> uint {
   // default str::hash
   // https://github.com/graydon/rust/blob/master/src/libcore/str.rs at ll. 43-50
   let uu: uint = 5381u;
   for cc: u8 in ss { uu *= 33u; uu += cc as uint; }
   ret uu;
}

// translate to hex
fn murmur_str(&&ss: str) -> str {
   let mm = murmur(ss);
   ret #fmt("%016x%016x", mm[0], mm[1]);
}

// murmur3 x64 128-bit
fn murmur(&&key_: str) -> [u64] {

   let key = str::bytes (key_);
   let data = key;
   let len = vec::len(key);
   let nblocks = len / 16u;

   // TODO: random seeds
   let seed = 0u64;
   let hh = [seed,seed];

   let cc = [ 0x_87c37b91114253d5_u64,
              0x_4cf5ad432745937f_u64 ];

   // rotation left
   fn rotl64 (x: u64, r: u64) -> u64 {
      ret (x << r) | (x >> (64u-r));
   }

   // conversion from 8 to 64 bits
   pure fn isEight (bytes: [u8]) -> bool {
      ret vec::len(bytes) == 8u;
   }

   fn convert_eight_u8_to_one_u64 (bb: [u8]) -> u64 {
      check isEight(bb);
      ret vec::foldl(0u64, bb, {|w, b| (w << 8u) + (b as u64)});
   }

   #[test]
   #[should_fail]
   fn test1_conversion_u8to64 () {
      let XXXX = convert_u8to64 ([1u8,2u8]);
   }

   #[test]
   fn test2_conversion_u8to64 () {
      let aa = [255u8,0u8,8u8,0u8, 20u8,0u8,0u8,1u8];
      std::io::println(#fmt("converted: %016x", convert_eight_u8_to_one_u64 (aa)));
   }

   fn convert_u8to64 (bb: [u8]) -> [u64] {
      fn lesser <copy TT> (aa: TT, bb: TT) -> TT {
         if aa < bb { aa } else { bb }
      }

      // windowing
      fn windowed <copy TT> (nn: uint, xs: [TT]) -> [[TT]] {
         let ws: [[TT]] = [];
         vec::iteri (xs, {|ii, x|
            let len: uint = vec::len(xs);
            if ii+(nn) < len {
               let w: [TT] = vec::slice ( xs, ii, ii+nn );
               vec::push (ws, w);
            }
         });
         ret ws;
      }

      // split into vector^2
      fn splitEvery <copy TT> (nn: uint, xs: [TT]) -> [[TT]] {
         let ys: [[TT]] = [];
         vec::iteri (xs, {|ii, x|
            let len = vec::len(xs);
            if ii % nn == 0u && ii < len {
               let y = vec::slice (xs, ii, lesser(nn+ii, len));
               vec::push (ys, y);
            }
         });
         ret ys;
      }

      // PENDING A
      let bbs = splitEvery(8u, bb);
      ret vec::map ( bbs, {|xs|
         convert_eight_u8_to_one_u64(xs)
      });
   }

   // fmix
   fn fmix (k_: u64) -> u64 {
      let kk = k_;

      kk ^= kk >> 33u;
      kk *= 0x_ff51afd7ed558ccd_u64;
      kk ^= kk >> 33u;
      kk *= 0x_c4ceb9fe1a85ec53_u64;
      kk ^= kk >> 33u;

      ret kk;
   }

   // PENDING B
   // what the original does is process the full size blocks as if they're u64
   // then takes the leftovers and twiddle those bytes
   // so i need to change things
   let blocks = convert_u8to64 ([0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8, 0u8,0u8,0u8,0u8]);

   // TODO: truncate to u64 for djb replacement
   ret [1u64, 1u64];
}

<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::io::*;
use std::ops::*;
use std::*;

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused)]
fn rl() -> String {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) => {
        (0..$n).map(|_| read!([$t])).collect::<Vec<_>>()
    };
    ($($t:ty),+ ; $n:expr) => {
        (0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>()
    };
    ([$t:ty]) => {{
        rl()
            .split_whitespace()
            .map(|word| word.parse().unwrap())
            .collect::<Vec<$t>>()
    }};
    ($t:ty) => {
        rl().parse::<$t>().unwrap()
    };
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace().into_iter();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

trait IteratorExt: Iterator + Sized {
    fn vec(self) -> Vec<Self::Item> {
        self.collect()
    }
}

impl<T: Iterator> IteratorExt for T {}

#[allow(unused)]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            let entries = &[
                $((
                    &stringify!($arg).to_string() as &fmt::Debug,
                    &($arg) as &fmt::Debug,
                )),*
            ];
            eprintln!("{:?}", DebugMap(entries));
        }
    };
}

#[allow(unused)]
struct DebugMap<'a>(&'a [(&'a fmt::Debug, &'a fmt::Debug)]);

impl<'a> std::fmt::Debug for DebugMap<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut m = fmt.debug_map();
        for &(key, value) in self.0.iter() {
            m.entry(key, value);
        }
        m.finish()
    }
}

// -----------------------------------------------
// Polyfill
// -----------------------------------------------

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}

#[allow(unused)]
macro_rules! eprintln {
    ($($arg:expr),*) => { _eprintln(format_args!($($arg),*)) }
}

fn _eprintln(args: fmt::Arguments) {
    let err = std::io::stderr();
    let mut err = err.lock();
    err.write_fmt(args).unwrap();
    err.write(b"\n").unwrap();
}

// -----------------------------------------------
// Solution
// -----------------------------------------------

pub fn main() {
    return;
}

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

    #[test]
    fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<commit_msg>Remove redundant into_iter<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::io::*;
use std::ops::*;
use std::*;

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused)]
fn rl() -> String {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) => {
        (0..$n).map(|_| read!([$t])).collect::<Vec<_>>()
    };
    ($($t:ty),+ ; $n:expr) => {
        (0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>()
    };
    ([$t:ty]) => {{
        rl()
            .split_whitespace()
            .map(|word| word.parse().unwrap())
            .collect::<Vec<$t>>()
    }};
    ($t:ty) => {
        rl().parse::<$t>().unwrap()
    };
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

trait IteratorExt: Iterator + Sized {
    fn vec(self) -> Vec<Self::Item> {
        self.collect()
    }
}

impl<T: Iterator> IteratorExt for T {}

#[allow(unused)]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            let entries = &[
                $((
                    &stringify!($arg).to_string() as &fmt::Debug,
                    &($arg) as &fmt::Debug,
                )),*
            ];
            eprintln!("{:?}", DebugMap(entries));
        }
    };
}

#[allow(unused)]
struct DebugMap<'a>(&'a [(&'a fmt::Debug, &'a fmt::Debug)]);

impl<'a> std::fmt::Debug for DebugMap<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut m = fmt.debug_map();
        for &(key, value) in self.0.iter() {
            m.entry(key, value);
        }
        m.finish()
    }
}

// -----------------------------------------------
// Polyfill
// -----------------------------------------------

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}

#[allow(unused)]
macro_rules! eprintln {
    ($($arg:expr),*) => { _eprintln(format_args!($($arg),*)) }
}

fn _eprintln(args: fmt::Arguments) {
    let err = std::io::stderr();
    let mut err = err.lock();
    err.write_fmt(args).unwrap();
    err.write(b"\n").unwrap();
}

// -----------------------------------------------
// Solution
// -----------------------------------------------

pub fn main() {
    return;
}

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

    #[test]
    fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<|endoftext|>


<commit_before>use hir::Semantics;
use ide_db::RootDatabase;
use syntax::{
    algo::{find_node_at_offset, SyntaxRewriter},
    ast, AstNode, NodeOrToken, SyntaxKind,
    SyntaxKind::*,
    SyntaxNode, WalkEvent, T,
};

use crate::FilePosition;

pub struct ExpandedMacro {
    pub name: String,
    pub expansion: String,
}

// Feature: Expand Macro Recursively
//
// Shows the full macro expansion of the macro at current cursor.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Expand macro recursively**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
    let sema = Semantics::new(db);
    let file = sema.parse(position.file_id);
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
    let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;

    let expanded = expand_macro_recur(&sema, &mac)?;

    // FIXME:
    // macro expansion may lose all white space information
    // But we hope someday we can use ra_fmt for that
    let expansion = insert_whitespaces(expanded);
    Some(ExpandedMacro { name: name_ref.text().to_string(), expansion })
}

fn expand_macro_recur(
    sema: &Semantics<RootDatabase>,
    macro_call: &ast::MacroCall,
) -> Option<SyntaxNode> {
    let mut expanded = sema.expand(macro_call)?;

    let children = expanded.descendants().filter_map(ast::MacroCall::cast);
    let mut rewriter = SyntaxRewriter::default();

    for child in children.into_iter() {
        if let Some(new_node) = expand_macro_recur(sema, &child) {
            // Replace the whole node if it is root
            // `replace_descendants` will not replace the parent node
            // but `SyntaxNode::descendants include itself
            if expanded == *child.syntax() {
                expanded = new_node;
            } else {
                rewriter.replace(child.syntax(), &new_node)
            }
        }
    }

    let res = rewriter.rewrite(&expanded);
    Some(res)
}

// FIXME: It would also be cool to share logic here and in the mbe tests,
// which are pretty unreadable at the moment.
fn insert_whitespaces(syn: SyntaxNode) -> String {
    let mut res = String::new();
    let mut token_iter = syn
        .preorder_with_tokens()
        .filter_map(|event| {
            if let WalkEvent::Enter(NodeOrToken::Token(token)) = event {
                Some(token)
            } else {
                None
            }
        })
        .peekable();

    let mut indent = 0;
    let mut last: Option<SyntaxKind> = None;

    while let Some(token) = token_iter.next() {
        let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
            token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
        };
        let is_last =
            |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };

        res += &match token.kind() {
            k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ",
            L_CURLY if is_next(|it| it != R_CURLY, true) => {
                indent += 1;
                let leading_space = if is_last(is_text, false) { " " } else { "" };
                format!("{}{{\n{}", leading_space, "  ".repeat(indent))
            }
            R_CURLY if is_last(|it| it != L_CURLY, true) => {
                indent = indent.saturating_sub(1);
                format!("\n{}}}", "  ".repeat(indent))
            }
            R_CURLY => format!("}}\n{}", "  ".repeat(indent)),
            LIFETIME_IDENT if is_next(|it| it == IDENT, true) => {
                format!("{} ", token.text().to_string())
            }
            T![;] => format!(";\n{}", "  ".repeat(indent)),
            T![->] => " -> ".to_string(),
            T![=] => " = ".to_string(),
            T![=>] => " => ".to_string(),
            _ => token.text().to_string(),
        };

        last = Some(token.kind());
    }

    return res;

    fn is_text(k: SyntaxKind) -> bool {
        k.is_keyword() || k.is_literal() || k == IDENT
    }
}

#[cfg(test)]
mod tests {
    use expect_test::{expect, Expect};

    use crate::fixture;

    fn check(ra_fixture: &str, expect: Expect) {
        let (analysis, pos) = fixture::position(ra_fixture);
        let expansion = analysis.expand_macro(pos).unwrap().unwrap();
        let actual = format!("{}\n{}", expansion.name, expansion.expansion);
        expect.assert_eq(&actual);
    }

    #[test]
    fn macro_expand_recursive_expansion() {
        check(
            r#"
macro_rules! bar {
    () => { fn  b() {} }
}
macro_rules! foo {
    () => { bar!(); }
}
macro_rules! baz {
    () => { foo!(); }
}
f$0oo!();
"#,
            expect![[r#"
                foo
                fn b(){}
            "#]],
        );
    }

    #[test]
    fn macro_expand_multiple_lines() {
        check(
            r#"
macro_rules! foo {
    () => {
        fn some_thing() -> u32 {
            let a = 0;
            a + 10
        }
    }
}
f$0oo!();
        "#,
            expect![[r#"
            foo
            fn some_thing() -> u32 {
              let a = 0;
              a+10
            }"#]],
        );
    }

    #[test]
    fn macro_expand_match_ast() {
        check(
            r#"
macro_rules! match_ast {
    (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
    (match ($node:expr) {
        $( ast::$ast:ident($it:ident) => $res:block, )*
        _ => $catch_all:expr $(,)?
    }) => {{
        $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
        { $catch_all }
    }};
}

fn main() {
    mat$0ch_ast! {
        match container {
            ast::TraitDef(it) => {},
            ast::ImplDef(it) => {},
            _ => { continue },
        }
    }
}
"#,
            expect![[r#"
       match_ast
       {
         if let Some(it) = ast::TraitDef::cast(container.clone()){}
         else if let Some(it) = ast::ImplDef::cast(container.clone()){}
         else {
           {
             continue
           }
         }
       }"#]],
        );
    }

    #[test]
    fn macro_expand_match_ast_inside_let_statement() {
        check(
            r#"
macro_rules! match_ast {
    (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
    (match ($node:expr) {}) => {{}};
}

fn main() {
    let p = f(|it| {
        let res = mat$0ch_ast! { match c {}};
        Some(res)
    })?;
}
"#,
            expect![[r#"
                match_ast
                {}
            "#]],
        );
    }

    #[test]
    fn macro_expand_inner_macro_fail_to_expand() {
        check(
            r#"
macro_rules! bar {
    (BAD) => {};
}
macro_rules! foo {
    () => {bar!()};
}

fn main() {
    let res = fo$0o!();
}
"#,
            expect![[r#"
                foo
            "#]],
        );
    }

    #[test]
    fn macro_expand_with_dollar_crate() {
        check(
            r#"
#[macro_export]
macro_rules! bar {
    () => {0};
}
macro_rules! foo {
    () => {$crate::bar!()};
}

fn main() {
    let res = fo$0o!();
}
"#,
            expect![[r#"
                foo
                0 "#]],
        );
    }
}
<commit_msg>Reduce allocations in Expand macro<commit_after>use std::iter;

use hir::Semantics;
use ide_db::RootDatabase;
use syntax::{
    algo::{find_node_at_offset, SyntaxRewriter},
    ast, AstNode, NodeOrToken, SyntaxKind,
    SyntaxKind::*,
    SyntaxNode, WalkEvent, T,
};

use crate::FilePosition;

pub struct ExpandedMacro {
    pub name: String,
    pub expansion: String,
}

// Feature: Expand Macro Recursively
//
// Shows the full macro expansion of the macro at current cursor.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Expand macro recursively**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
    let sema = Semantics::new(db);
    let file = sema.parse(position.file_id);
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
    let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;

    let expanded = expand_macro_recur(&sema, &mac)?;

    // FIXME:
    // macro expansion may lose all white space information
    // But we hope someday we can use ra_fmt for that
    let expansion = insert_whitespaces(expanded);
    Some(ExpandedMacro { name: name_ref.text().to_string(), expansion })
}

fn expand_macro_recur(
    sema: &Semantics<RootDatabase>,
    macro_call: &ast::MacroCall,
) -> Option<SyntaxNode> {
    let mut expanded = sema.expand(macro_call)?;

    let children = expanded.descendants().filter_map(ast::MacroCall::cast);
    let mut rewriter = SyntaxRewriter::default();

    for child in children.into_iter() {
        if let Some(new_node) = expand_macro_recur(sema, &child) {
            // Replace the whole node if it is root
            // `replace_descendants` will not replace the parent node
            // but `SyntaxNode::descendants include itself
            if expanded == *child.syntax() {
                expanded = new_node;
            } else {
                rewriter.replace(child.syntax(), &new_node)
            }
        }
    }

    let res = rewriter.rewrite(&expanded);
    Some(res)
}

// FIXME: It would also be cool to share logic here and in the mbe tests,
// which are pretty unreadable at the moment.
fn insert_whitespaces(syn: SyntaxNode) -> String {
    let mut res = String::new();
    let mut token_iter = syn
        .preorder_with_tokens()
        .filter_map(|event| {
            if let WalkEvent::Enter(NodeOrToken::Token(token)) = event {
                Some(token)
            } else {
                None
            }
        })
        .peekable();

    let mut indent = 0;
    let mut last: Option<SyntaxKind> = None;

    while let Some(token) = token_iter.next() {
        let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
            token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
        };
        let is_last =
            |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };

        match token.kind() {
            k if is_text(k) && is_next(|it| !it.is_punct(), true) => {
                res.push_str(token.text());
                res.push(' ');
            }
            L_CURLY if is_next(|it| it != R_CURLY, true) => {
                indent += 1;
                if is_last(is_text, false) {
                    res.push(' ');
                }
                res.push_str("{\n");
                res.extend(iter::repeat(" ").take(2 * indent));
            }
            R_CURLY if is_last(|it| it != L_CURLY, true) => {
                indent = indent.saturating_sub(1);
                res.push('\n');
                res.extend(iter::repeat(" ").take(2 * indent));
                res.push_str("}");
            }
            R_CURLY => {
                res.push_str("}\n");
                res.extend(iter::repeat(" ").take(2 * indent));
            }
            LIFETIME_IDENT if is_next(|it| it == IDENT, true) => {
                res.push_str(token.text());
                res.push(' ');
            }
            T![;] => {
                res.push_str(";\n");
                res.extend(iter::repeat(" ").take(2 * indent));
            }
            T![->] => res.push_str(" -> "),
            T![=] => res.push_str(" = "),
            T![=>] => res.push_str(" => "),
            _ => res.push_str(token.text()),
        }

        last = Some(token.kind());
    }

    return res;

    fn is_text(k: SyntaxKind) -> bool {
        k.is_keyword() || k.is_literal() || k == IDENT
    }
}

#[cfg(test)]
mod tests {
    use expect_test::{expect, Expect};

    use crate::fixture;

    fn check(ra_fixture: &str, expect: Expect) {
        let (analysis, pos) = fixture::position(ra_fixture);
        let expansion = analysis.expand_macro(pos).unwrap().unwrap();
        let actual = format!("{}\n{}", expansion.name, expansion.expansion);
        expect.assert_eq(&actual);
    }

    #[test]
    fn macro_expand_recursive_expansion() {
        check(
            r#"
macro_rules! bar {
    () => { fn  b() {} }
}
macro_rules! foo {
    () => { bar!(); }
}
macro_rules! baz {
    () => { foo!(); }
}
f$0oo!();
"#,
            expect![[r#"
                foo
                fn b(){}
            "#]],
        );
    }

    #[test]
    fn macro_expand_multiple_lines() {
        check(
            r#"
macro_rules! foo {
    () => {
        fn some_thing() -> u32 {
            let a = 0;
            a + 10
        }
    }
}
f$0oo!();
        "#,
            expect![[r#"
            foo
            fn some_thing() -> u32 {
              let a = 0;
              a+10
            }"#]],
        );
    }

    #[test]
    fn macro_expand_match_ast() {
        check(
            r#"
macro_rules! match_ast {
    (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
    (match ($node:expr) {
        $( ast::$ast:ident($it:ident) => $res:block, )*
        _ => $catch_all:expr $(,)?
    }) => {{
        $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
        { $catch_all }
    }};
}

fn main() {
    mat$0ch_ast! {
        match container {
            ast::TraitDef(it) => {},
            ast::ImplDef(it) => {},
            _ => { continue },
        }
    }
}
"#,
            expect![[r#"
       match_ast
       {
         if let Some(it) = ast::TraitDef::cast(container.clone()){}
         else if let Some(it) = ast::ImplDef::cast(container.clone()){}
         else {
           {
             continue
           }
         }
       }"#]],
        );
    }

    #[test]
    fn macro_expand_match_ast_inside_let_statement() {
        check(
            r#"
macro_rules! match_ast {
    (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
    (match ($node:expr) {}) => {{}};
}

fn main() {
    let p = f(|it| {
        let res = mat$0ch_ast! { match c {}};
        Some(res)
    })?;
}
"#,
            expect![[r#"
                match_ast
                {}
            "#]],
        );
    }

    #[test]
    fn macro_expand_inner_macro_fail_to_expand() {
        check(
            r#"
macro_rules! bar {
    (BAD) => {};
}
macro_rules! foo {
    () => {bar!()};
}

fn main() {
    let res = fo$0o!();
}
"#,
            expect![[r#"
                foo
            "#]],
        );
    }

    #[test]
    fn macro_expand_with_dollar_crate() {
        check(
            r#"
#[macro_export]
macro_rules! bar {
    () => {0};
}
macro_rules! foo {
    () => {$crate::bar!()};
}

fn main() {
    let res = fo$0o!();
}
"#,
            expect![[r#"
                foo
                0 "#]],
        );
    }
}
<|endoftext|>