<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::fs::create_dir_all;
use std::fs::{File, canonicalize, OpenOptions};
use std::io::{Write, BufRead, BufReader};
use std::path::Path;
use std::collections::HashMap;

use handlebars::Handlebars;
use hcore::package::PackageIdent;

use common::ui::{UI, Status};
use error::Result;

const DEFAULT_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/default_template_plan.sh"
));
const FULL_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/full_template_plan.sh"
));
const DEFAULT_TOML_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_default.toml"
));
const GITIGNORE_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_gitignore"
));

pub fn start(
    ui: &mut UI,
    origin: String,
    with_docs: bool,
    with_callbacks: bool,
    with_all: bool,
    scaffolding_ident: Option<PackageIdent>,
    maybe_name: Option<String>,
) -> Result<()> {
    ui.begin("Constructing a cozy habitat for your app...")?;
    ui.br()?;

    let (root, name) = match maybe_name {
        Some(name) => (name.clone(), name.clone()),
        // The name of the current working directory.
        None => {
            (
                "habitat".into(),
                canonicalize(".")
                    .ok()
                    .and_then(|path| {
                        path.components().last().and_then(|val| {
                            // Type gymnastics!
                            val.as_os_str().to_os_string().into_string().ok()
                        })
                    })
                    .unwrap_or("unnamed".into()),
            )
        }
    };

    // Build out the variables passed.
    let handlebars = Handlebars::new();
    let mut data = HashMap::new();
    data.insert("pkg_name".to_string(), name);
    data.insert("pkg_origin".to_string(), origin);

    let scaffold = match scaffolding_ident {
        Some(ident) => Some(data.insert(
            "scaffolding_ident".to_string(),
            ident.to_string(),
        )),
        None => None,
    };

    if with_callbacks {
        data.insert("with_callbacks".to_string(), "true".to_string());
    }
    if with_docs {
        data.insert("with_docs".to_string(), "true".to_string());
    }
    // Add all environment variables that start with "pkg_" as variables in
    // the template.
    for (key, value) in env::vars() {
        if key.starts_with("pkg_") {
            data.insert(key, value);
        }
    }

    // We want to render the configured variables.
    if with_all || scaffold.is_none() {
        let rendered_plan = handlebars.template_render(FULL_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    } else {
        let rendered_plan = handlebars.template_render(DEFAULT_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    }
    ui.para(
        "`plan.sh` is the foundation of your new habitat. It contains \
        metadata, dependencies, and tasks.",
    )?;
    let rendered_default_toml = handlebars.template_render(DEFAULT_TOML_TEMPLATE, &data)?;
    create_with_template(
        ui,
        &format!("{}/default.toml", root),
        &rendered_default_toml,
    )?;
    ui.para(
        "`default.toml` contains default values for `cfg` prefixed variables.",
    )?;

    let config_path = format!("{}/config/", root);
    match Path::new(&config_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", config_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", config_path),
            )?;
            create_dir_all(&config_path)?;
        }
    };
    ui.para(
        "`/config/` contains configuration files for your app.",
    )?;

    let hooks_path = format!("{}/hooks/", root);
    match Path::new(&hooks_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", hooks_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", hooks_path),
            )?;
            create_dir_all(&hooks_path)?;
        }
    };
    ui.para(
        "`/hooks/` contains automation hooks into your habitat.",
    )?;

    ui.para(
        "For more information on any of the files: \
        https://www.habitat.sh/docs/reference/plan-syntax/",
    )?;

    render_ignorefile(ui, &root)?;

    ui.end("An abode for your code is initialized!")?;
    Ok(())
}

fn render_ignorefile(ui: &mut UI, root: &str) -> Result<()> {
    let parent = format!("{}/..", root);
    let expanded = canonicalize(&parent)?;
    let current_path = Path::new(&expanded);

    if is_git_managed(&current_path) {
        let target = format!("{}/.gitignore", parent);
        let target_path = Path::new(&target);

        if !target_path.exists() {
            create_with_template(ui, &target, GITIGNORE_TEMPLATE)?
        } else {
            let file = OpenOptions::new().read(true).append(true).open(target_path)?;

            let entries: Vec<String> = BufReader::new(&file)
                .lines()
                .map(|l| l.expect("Failed to parse line"))
                .collect();

            let mut appended = 0;

            for line in GITIGNORE_TEMPLATE.lines() {
                let s = line.to_string();

                if !entries.contains(&s) {
                    writeln!(&file, "{}", s)?;
                    appended += 1;
                }
            }

            ui.status(
                Status::Using,
                format!(
                    "existing file: {} ({} lines appended)",
                    &target,
                    appended
                ),
            )?;
        }
    }
    Ok(())
}

fn is_git_managed(path: &Path) -> bool {

    if path.join(".git").is_dir() {
        return true;
    }

    if let Some(parent) = path.parent() {
        return is_git_managed(&parent);
    }

    return false;
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    match path.exists() {
        false => {
            ui.status(Status::Creating, format!("file: {}", location))?;
            // If the directory doesn't exist we need to make it.
            if let Some(directory) = path.parent() {
                create_dir_all(directory)?;
            }
            // Create and then render the template with Handlebars
            File::create(path).and_then(
                |mut file| file.write(template.as_bytes()),
            )?;
        }
        true => {
            // If the user has already configured a file overwriting would be impolite.
            ui.status(
                Status::Using,
                format!("existing file: {}", location),
            )?;
        }
    };
    Ok(())
}
<commit_msg>[hab] Add default `pkg_version` when using `hab plan init`.<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::fs::create_dir_all;
use std::fs::{File, canonicalize, OpenOptions};
use std::io::{Write, BufRead, BufReader};
use std::path::Path;
use std::collections::HashMap;

use handlebars::Handlebars;
use hcore::package::PackageIdent;

use common::ui::{UI, Status};
use error::Result;

const DEFAULT_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/default_template_plan.sh"
));
const FULL_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/full_template_plan.sh"
));
const DEFAULT_TOML_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_default.toml"
));
const GITIGNORE_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_gitignore"
));

const DEFAULT_PKG_VERSION: &'static str = "0.1.0";

pub fn start(
    ui: &mut UI,
    origin: String,
    with_docs: bool,
    with_callbacks: bool,
    with_all: bool,
    scaffolding_ident: Option<PackageIdent>,
    maybe_name: Option<String>,
) -> Result<()> {
    ui.begin("Constructing a cozy habitat for your app...")?;
    ui.br()?;

    let (root, name) = match maybe_name {
        Some(name) => (name.clone(), name.clone()),
        // The name of the current working directory.
        None => {
            (
                "habitat".into(),
                canonicalize(".")
                    .ok()
                    .and_then(|path| {
                        path.components().last().and_then(|val| {
                            // Type gymnastics!
                            val.as_os_str().to_os_string().into_string().ok()
                        })
                    })
                    .unwrap_or("unnamed".into()),
            )
        }
    };

    // Build out the variables passed.
    let handlebars = Handlebars::new();
    let mut data = HashMap::new();
    data.insert("pkg_name".to_string(), name);
    data.insert("pkg_origin".to_string(), origin);
    data.insert("pkg_version".to_string(), DEFAULT_PKG_VERSION.to_string());

    let scaffold = match scaffolding_ident {
        Some(ident) => Some(data.insert(
            "scaffolding_ident".to_string(),
            ident.to_string(),
        )),
        None => None,
    };

    if with_callbacks {
        data.insert("with_callbacks".to_string(), "true".to_string());
    }
    if with_docs {
        data.insert("with_docs".to_string(), "true".to_string());
    }
    // Add all environment variables that start with "pkg_" as variables in
    // the template.
    for (key, value) in env::vars() {
        if key.starts_with("pkg_") {
            data.insert(key, value);
        }
    }

    // We want to render the configured variables.
    if with_all || scaffold.is_none() {
        let rendered_plan = handlebars.template_render(FULL_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    } else {
        let rendered_plan = handlebars.template_render(DEFAULT_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    }
    ui.para(
        "`plan.sh` is the foundation of your new habitat. It contains \
        metadata, dependencies, and tasks.",
    )?;
    let rendered_default_toml = handlebars.template_render(DEFAULT_TOML_TEMPLATE, &data)?;
    create_with_template(
        ui,
        &format!("{}/default.toml", root),
        &rendered_default_toml,
    )?;
    ui.para(
        "`default.toml` contains default values for `cfg` prefixed variables.",
    )?;

    let config_path = format!("{}/config/", root);
    match Path::new(&config_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", config_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", config_path),
            )?;
            create_dir_all(&config_path)?;
        }
    };
    ui.para(
        "`/config/` contains configuration files for your app.",
    )?;

    let hooks_path = format!("{}/hooks/", root);
    match Path::new(&hooks_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", hooks_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", hooks_path),
            )?;
            create_dir_all(&hooks_path)?;
        }
    };
    ui.para(
        "`/hooks/` contains automation hooks into your habitat.",
    )?;

    ui.para(
        "For more information on any of the files: \
        https://www.habitat.sh/docs/reference/plan-syntax/",
    )?;

    render_ignorefile(ui, &root)?;

    ui.end("An abode for your code is initialized!")?;
    Ok(())
}

fn render_ignorefile(ui: &mut UI, root: &str) -> Result<()> {
    let parent = format!("{}/..", root);
    let expanded = canonicalize(&parent)?;
    let current_path = Path::new(&expanded);

    if is_git_managed(&current_path) {
        let target = format!("{}/.gitignore", parent);
        let target_path = Path::new(&target);

        if !target_path.exists() {
            create_with_template(ui, &target, GITIGNORE_TEMPLATE)?
        } else {
            let file = OpenOptions::new().read(true).append(true).open(target_path)?;

            let entries: Vec<String> = BufReader::new(&file)
                .lines()
                .map(|l| l.expect("Failed to parse line"))
                .collect();

            let mut appended = 0;

            for line in GITIGNORE_TEMPLATE.lines() {
                let s = line.to_string();

                if !entries.contains(&s) {
                    writeln!(&file, "{}", s)?;
                    appended += 1;
                }
            }

            ui.status(
                Status::Using,
                format!(
                    "existing file: {} ({} lines appended)",
                    &target,
                    appended
                ),
            )?;
        }
    }
    Ok(())
}

fn is_git_managed(path: &Path) -> bool {

    if path.join(".git").is_dir() {
        return true;
    }

    if let Some(parent) = path.parent() {
        return is_git_managed(&parent);
    }

    return false;
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    match path.exists() {
        false => {
            ui.status(Status::Creating, format!("file: {}", location))?;
            // If the directory doesn't exist we need to make it.
            if let Some(directory) = path.parent() {
                create_dir_all(directory)?;
            }
            // Create and then render the template with Handlebars
            File::create(path).and_then(
                |mut file| file.write(template.as_bytes()),
            )?;
        }
        true => {
            // If the user has already configured a file overwriting would be impolite.
            ui.status(
                Status::Using,
                format!("existing file: {}", location),
            )?;
        }
    };
    Ok(())
}
<|endoftext|>


<commit_before>/*!

Implements the copy-on-write DOM-sharing model.  This model allows for
a single writer and any number of readers, but the writer must be able
to control and manage the lifetimes of the reader(s).  For simplicity
I will describe the implementation as though there were a single
reader.

The basic idea is that every object in the COW pool has both a reader
view and a writer view.  The writer always sees the writer view, which
contains the most up-to-date values.  The reader uses the reader view,
which contains the values as of the point where the reader was forked.
When the writer joins the reader, the reader view will be synchronized
with the writer view.

Internally, the way this works is using a copy-on-write scheme.  Each
COW node maintains two pointers (`read_ptr` and `write_ptr`).
Assuming that readers are active, when a writer wants to modify a
node, it first copies the reader's data into a new pointer.  Any
writes that occur after that point (but before the reader is joined)
will operate on this same copy.  When the reader is joined, any nodes
which the writer modified will free the stale reader data and update
the reader pointer to be the same as the writer pointer.

# Using the COW APIs as a writer

You must first create a `scope` object.  The scope object manages the
memory and the COW operations.  COW'd objects of some sendable type
`T` are not referenced directly but rather through a `handle<T>`.  To
create a new COW object, you use `scope.handle(t)` where `t` is some
initial value of type `T`.  To write to an COW object, use
`scope.write()` and to read from it use `scope.read()`. Be sure not to
use the various `ReaderMethods`.

Handles can be freely sent between tasks but the COW scope cannot.  It must stay with the writer
task.  You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep
the COW scope abreast of when the reader is active.  Failure to do so will lead to race conditions
or worse.

# Using the COW APIs as a reader

Import the `ReaderMethods` impl.  When you receive a handle, you can
invoke `h.read { |v| ... }` and so forth.  There is also a piece of
auxiliary data that can be optionally associated with each handle.

Note: if the type `T` contains mutable fields, then there is nothing
to stop the reader from mutating those fields in the `read()` method.
Do not do this.  It will lead to race conditions.

FIXME: We can enforce that this is not done by ensuring that the type
`T` contains no mutable fields.

# Auxiliary data

Readers can associate a piece of auxiliary data of type `A` along with
main nodes.  This is convenient but dangerous: it is the reader's job
to ensure that this data remains live independent of the COW nodes
themselves.

*/

use core::libc::types::os::arch::c95::size_t;
use ptr::Ptr;
use vec::push;

type ScopeData<T:Send,A> = {
    mut layout_active: bool,
    mut free_list: ~[Handle<T,A>],
    mut first_dirty: Handle<T,A>
};

struct ScopeResource<T:Send,A> {
    d : ScopeData<T,A>,

    drop unsafe {
        error!("dropp!");
        for self.d.free_list.each |h| { free_handle(*h); }
    }
}

fn ScopeResource<T:Send,A>(d : ScopeData<T,A>) -> ScopeResource<T,A> {
    ScopeResource { d: d }
}

pub type Scope<T:Send,A> = @ScopeResource<T,A>;

type HandleData<T:Send,A> = {mut read_ptr: *T,
                             mut write_ptr: *mut T,
                             mut read_aux: *A,
                             mut next_dirty: Handle<T,A>};
pub enum Handle<T:Send,A> {
    _Handle(*HandleData<T,A>)
}

// Private methods
impl<T:Send,A> Handle<T,A> {
    fn read_ptr() -> *T unsafe            { (**self).read_ptr   }
    fn write_ptr() -> *mut T unsafe       { (**self).write_ptr  }
    fn read_aux() -> *A unsafe            { (**self).read_aux   }
    fn next_dirty() -> Handle<T,A> unsafe { (**self).next_dirty }

    fn set_read_ptr(t: *T) unsafe             { (**self).read_ptr = t;   }
    fn set_write_ptr(t: *mut T) unsafe        { (**self).write_ptr = t;  }
    fn set_read_aux(t: *A) unsafe             { (**self).read_aux = t;   }
    fn set_next_dirty(h: Handle<T,A>) unsafe { (**self).next_dirty = h; }

    pure fn is_null() -> bool { (*self).is_null() }
    fn is_not_null() -> bool { (*self).is_not_null() }
}

impl<T:Send,A> Handle<T,A> {
    /// Access the reader's view of the handle's data
    fn read<U>(f: fn(&T) -> U) -> U unsafe {
        f(&*self.read_ptr())
    }

    /// True if auxiliary data is associated with this handle
    fn has_aux() -> bool unsafe {
        self.read_aux().is_not_null()
    }

    /** Set the auxiliary data associated with this handle.

    **Warning:** the reader is responsible for keeping this data live!
    */
    fn set_aux(p: @A) unsafe {
        (**self).read_aux = ptr::to_unsafe_ptr(&*p);
    }

    /// Access the auxiliary data associated with this handle
    fn aux<U>(f: fn(&A) -> U) -> U unsafe {
        assert self.has_aux();
        f(&*self.read_aux())
    }
}

// Private methods
impl<T: Copy Send,A> Scope<T,A> {
    fn clone(v: *T) -> *T unsafe {
        let n: *mut T =
            cast::reinterpret_cast(&libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));

        // n.b.: this assignment will run the drop glue for <T,A>. *Hopefully* the fact that
        // everything is initialized to NULL by calloc will make this ok.  We may have to make the
        // take glue be tolerant of this.
        *n = unsafe{*v};

        return cast::reinterpret_cast(&n);
    }
}

unsafe fn free<T:Send>(t: *T) {
    let _x <- *cast::reinterpret_cast::<*T,*mut T>(&t);
    libc::free(cast::reinterpret_cast(&t));
}

unsafe fn free_handle<T:Send,A>(h: Handle<T,A>) {
    free(h.read_ptr());
    if h.write_ptr() != cast::reinterpret_cast(&h.read_ptr()) {
        free(cast::reinterpret_cast::<*mut T,*T>(&h.write_ptr()));
    }
}

fn null_handle<T:Send,A>() -> Handle<T,A> {
    _Handle(ptr::null())
}

pub fn Scope<T:Send,A>() -> Scope<T,A> {
    @ScopeResource({mut layout_active: false,
                    mut free_list: ~[],
                    mut first_dirty: null_handle()})
}

// Writer methods
impl<T:Copy Send,A> Scope<T,A> {
    fn is_reader_forked() -> bool {
        self.d.layout_active
    }

    fn reader_forked() {
        assert !self.d.layout_active;
        assert self.d.first_dirty.is_null();
        self.d.layout_active = true;
    }

    fn reader_joined() unsafe {
        assert self.d.layout_active;

        if self.d.first_dirty.is_not_null() {
            let mut handle = self.d.first_dirty;
            while (*handle).is_not_null() {
                free(handle.read_ptr());

                handle.set_read_ptr(cast::reinterpret_cast(&handle.write_ptr()));
                let next_handle = handle.next_dirty();
                handle.set_next_dirty(null_handle());
                handle = next_handle;
            }
            self.d.first_dirty = null_handle();
        }

        assert self.d.first_dirty.is_null();
        self.d.layout_active = false;
    }

    fn read<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        // Use the write_ptr, which may be more up to date than the read_ptr or may not
        f(&*h.write_ptr())
    }

    fn write<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        let const_read_ptr = ptr::const_offset(h.read_ptr(), 0);
        let const_write_ptr = ptr::const_offset(h.write_ptr(), 0);
        if self.d.layout_active && const_read_ptr == const_write_ptr {
            #debug["marking handle %? as dirty", h];
            h.set_write_ptr(cast::reinterpret_cast(&self.clone(h.read_ptr())));
            h.set_next_dirty(self.d.first_dirty);
            self.d.first_dirty = *h;
        }
        f(&*h.write_ptr())
    }

    // FIXME: This could avoid a deep copy by taking ownership of `v`
    #[allow(non_implicitly_copyable_typarams)]
    fn handle(v: &T) -> Handle<T,A> unsafe {
        debug!("vv: %?", *v);
        let d: *HandleData<T,A> =
            cast::reinterpret_cast(
                &libc::malloc(sys::size_of::<HandleData<T,A>>() as size_t));
        (*d).read_ptr = self.clone(ptr::to_unsafe_ptr(v));
        (*d).write_ptr = cast::reinterpret_cast(&(*d).read_ptr);
        (*d).read_aux = ptr::null();
        (*d).next_dirty = null_handle();
        let h = _Handle(d);
        push(&mut self.d.free_list, h);
        do self.read(&h) |v| {
            debug!("vv: %?", *v);
        }
        return h;
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod test {
    type animal = {name: ~str, species: species};
    enum species {
        chicken(~chicken),
        bull(~bull)
    }
    type chicken = {mut eggs_per_day:uint};
    type bull = {mut horns:uint};

    type processed = {flag: bool};

    type animal_scope = Scope<animal, processed>;

    #[test]
    fn handles_get_freed() {
        let s: animal_scope = Scope();
        s.handle(&{name:~"henrietta", species:chicken(~{mut eggs_per_day:22u})});
        s.handle(&{name:~"ferdinand", species:bull(~{mut horns:3u})});
    }

    fn mutate(a: &animal) {
        match a.species {
          chicken(c) => c.eggs_per_day += 1u,
          bull(c) => c.horns += 1u
        }
    }

    fn read_characteristic(a: &animal) -> uint {
        match a.species {
          chicken(c) => c.eggs_per_day,
          bull(c) => c.horns
        }
    }

    #[test]
    fn interspersed_execution() {
        let s: animal_scope = Scope();
        let henrietta =
            s.handle(&{name:~"henrietta",
                      species:chicken(~{mut eggs_per_day:0u})});
        let ferdinand =
            s.handle(&{name:~"ferdinand",
                      species:bull(~{mut horns:0u})});

        let iter1 = 3u;
        let iter2 = 22u;
        let read_port = comm::Port();
        let read_chan = comm::Chan(&read_port);

        // fire up a reader task
        for uint::range(0u, iter1) |i| {
            s.reader_forked();
            let wait_chan = task::spawn_listener(|wait_port| {
                for uint::range(0u, iter2) |_i| {
                    comm::send(read_chan, henrietta.read(read_characteristic));
                    comm::send(read_chan, ferdinand.read(read_characteristic));
                    comm::recv(wait_port);
                }
            });

            let hrc = henrietta.read(read_characteristic);
            assert hrc == (i * iter2);

            let frc = ferdinand.read(read_characteristic);
            assert frc == i * iter2;

            for uint::range(0u, iter2) |_i| {
                assert hrc == comm::recv(read_port);
                s.write(&henrietta, mutate);
                assert frc == comm::recv(read_port);
                s.write(&ferdinand, mutate);
                comm::send(wait_chan, ());
            }
            s.reader_joined();
        }

        assert henrietta.read(read_characteristic) == iter1 * iter2;
        assert ferdinand.read(read_characteristic) == iter1 * iter2;
    }
}
<commit_msg>Remove debug logging<commit_after>/*!

Implements the copy-on-write DOM-sharing model.  This model allows for
a single writer and any number of readers, but the writer must be able
to control and manage the lifetimes of the reader(s).  For simplicity
I will describe the implementation as though there were a single
reader.

The basic idea is that every object in the COW pool has both a reader
view and a writer view.  The writer always sees the writer view, which
contains the most up-to-date values.  The reader uses the reader view,
which contains the values as of the point where the reader was forked.
When the writer joins the reader, the reader view will be synchronized
with the writer view.

Internally, the way this works is using a copy-on-write scheme.  Each
COW node maintains two pointers (`read_ptr` and `write_ptr`).
Assuming that readers are active, when a writer wants to modify a
node, it first copies the reader's data into a new pointer.  Any
writes that occur after that point (but before the reader is joined)
will operate on this same copy.  When the reader is joined, any nodes
which the writer modified will free the stale reader data and update
the reader pointer to be the same as the writer pointer.

# Using the COW APIs as a writer

You must first create a `scope` object.  The scope object manages the
memory and the COW operations.  COW'd objects of some sendable type
`T` are not referenced directly but rather through a `handle<T>`.  To
create a new COW object, you use `scope.handle(t)` where `t` is some
initial value of type `T`.  To write to an COW object, use
`scope.write()` and to read from it use `scope.read()`. Be sure not to
use the various `ReaderMethods`.

Handles can be freely sent between tasks but the COW scope cannot.  It must stay with the writer
task.  You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep
the COW scope abreast of when the reader is active.  Failure to do so will lead to race conditions
or worse.

# Using the COW APIs as a reader

Import the `ReaderMethods` impl.  When you receive a handle, you can
invoke `h.read { |v| ... }` and so forth.  There is also a piece of
auxiliary data that can be optionally associated with each handle.

Note: if the type `T` contains mutable fields, then there is nothing
to stop the reader from mutating those fields in the `read()` method.
Do not do this.  It will lead to race conditions.

FIXME: We can enforce that this is not done by ensuring that the type
`T` contains no mutable fields.

# Auxiliary data

Readers can associate a piece of auxiliary data of type `A` along with
main nodes.  This is convenient but dangerous: it is the reader's job
to ensure that this data remains live independent of the COW nodes
themselves.

*/

use core::libc::types::os::arch::c95::size_t;
use ptr::Ptr;
use vec::push;

type ScopeData<T:Send,A> = {
    mut layout_active: bool,
    mut free_list: ~[Handle<T,A>],
    mut first_dirty: Handle<T,A>
};

struct ScopeResource<T:Send,A> {
    d : ScopeData<T,A>,

    drop unsafe {
        for self.d.free_list.each |h| { free_handle(*h); }
    }
}

fn ScopeResource<T:Send,A>(d : ScopeData<T,A>) -> ScopeResource<T,A> {
    ScopeResource { d: d }
}

pub type Scope<T:Send,A> = @ScopeResource<T,A>;

type HandleData<T:Send,A> = {mut read_ptr: *T,
                             mut write_ptr: *mut T,
                             mut read_aux: *A,
                             mut next_dirty: Handle<T,A>};
pub enum Handle<T:Send,A> {
    _Handle(*HandleData<T,A>)
}

// Private methods
impl<T:Send,A> Handle<T,A> {
    fn read_ptr() -> *T unsafe            { (**self).read_ptr   }
    fn write_ptr() -> *mut T unsafe       { (**self).write_ptr  }
    fn read_aux() -> *A unsafe            { (**self).read_aux   }
    fn next_dirty() -> Handle<T,A> unsafe { (**self).next_dirty }

    fn set_read_ptr(t: *T) unsafe             { (**self).read_ptr = t;   }
    fn set_write_ptr(t: *mut T) unsafe        { (**self).write_ptr = t;  }
    fn set_read_aux(t: *A) unsafe             { (**self).read_aux = t;   }
    fn set_next_dirty(h: Handle<T,A>) unsafe { (**self).next_dirty = h; }

    pure fn is_null() -> bool { (*self).is_null() }
    fn is_not_null() -> bool { (*self).is_not_null() }
}

impl<T:Send,A> Handle<T,A> {
    /// Access the reader's view of the handle's data
    fn read<U>(f: fn(&T) -> U) -> U unsafe {
        f(&*self.read_ptr())
    }

    /// True if auxiliary data is associated with this handle
    fn has_aux() -> bool unsafe {
        self.read_aux().is_not_null()
    }

    /** Set the auxiliary data associated with this handle.

    **Warning:** the reader is responsible for keeping this data live!
    */
    fn set_aux(p: @A) unsafe {
        (**self).read_aux = ptr::to_unsafe_ptr(&*p);
    }

    /// Access the auxiliary data associated with this handle
    fn aux<U>(f: fn(&A) -> U) -> U unsafe {
        assert self.has_aux();
        f(&*self.read_aux())
    }
}

// Private methods
impl<T: Copy Send,A> Scope<T,A> {
    fn clone(v: *T) -> *T unsafe {
        let n: *mut T =
            cast::reinterpret_cast(&libc::calloc(sys::size_of::<T>() as size_t, 1u as size_t));

        // n.b.: this assignment will run the drop glue for <T,A>. *Hopefully* the fact that
        // everything is initialized to NULL by calloc will make this ok.  We may have to make the
        // take glue be tolerant of this.
        *n = unsafe{*v};

        return cast::reinterpret_cast(&n);
    }
}

unsafe fn free<T:Send>(t: *T) {
    let _x <- *cast::reinterpret_cast::<*T,*mut T>(&t);
    libc::free(cast::reinterpret_cast(&t));
}

unsafe fn free_handle<T:Send,A>(h: Handle<T,A>) {
    free(h.read_ptr());
    if h.write_ptr() != cast::reinterpret_cast(&h.read_ptr()) {
        free(cast::reinterpret_cast::<*mut T,*T>(&h.write_ptr()));
    }
}

fn null_handle<T:Send,A>() -> Handle<T,A> {
    _Handle(ptr::null())
}

pub fn Scope<T:Send,A>() -> Scope<T,A> {
    @ScopeResource({mut layout_active: false,
                    mut free_list: ~[],
                    mut first_dirty: null_handle()})
}

// Writer methods
impl<T:Copy Send,A> Scope<T,A> {
    fn is_reader_forked() -> bool {
        self.d.layout_active
    }

    fn reader_forked() {
        assert !self.d.layout_active;
        assert self.d.first_dirty.is_null();
        self.d.layout_active = true;
    }

    fn reader_joined() unsafe {
        assert self.d.layout_active;

        if self.d.first_dirty.is_not_null() {
            let mut handle = self.d.first_dirty;
            while (*handle).is_not_null() {
                free(handle.read_ptr());

                handle.set_read_ptr(cast::reinterpret_cast(&handle.write_ptr()));
                let next_handle = handle.next_dirty();
                handle.set_next_dirty(null_handle());
                handle = next_handle;
            }
            self.d.first_dirty = null_handle();
        }

        assert self.d.first_dirty.is_null();
        self.d.layout_active = false;
    }

    fn read<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        // Use the write_ptr, which may be more up to date than the read_ptr or may not
        f(&*h.write_ptr())
    }

    fn write<U>(h: &Handle<T,A>, f: fn(&T) -> U) -> U unsafe {
        let const_read_ptr = ptr::const_offset(h.read_ptr(), 0);
        let const_write_ptr = ptr::const_offset(h.write_ptr(), 0);
        if self.d.layout_active && const_read_ptr == const_write_ptr {
            #debug["marking handle %? as dirty", h];
            h.set_write_ptr(cast::reinterpret_cast(&self.clone(h.read_ptr())));
            h.set_next_dirty(self.d.first_dirty);
            self.d.first_dirty = *h;
        }
        f(&*h.write_ptr())
    }

    // FIXME: This could avoid a deep copy by taking ownership of `v`
    #[allow(non_implicitly_copyable_typarams)]
    fn handle(v: &T) -> Handle<T,A> unsafe {
        debug!("vv: %?", *v);
        let d: *HandleData<T,A> =
            cast::reinterpret_cast(
                &libc::malloc(sys::size_of::<HandleData<T,A>>() as size_t));
        (*d).read_ptr = self.clone(ptr::to_unsafe_ptr(v));
        (*d).write_ptr = cast::reinterpret_cast(&(*d).read_ptr);
        (*d).read_aux = ptr::null();
        (*d).next_dirty = null_handle();
        let h = _Handle(d);
        push(&mut self.d.free_list, h);
        do self.read(&h) |v| {
            debug!("vv: %?", *v);
        }
        return h;
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod test {
    type animal = {name: ~str, species: species};
    enum species {
        chicken(~chicken),
        bull(~bull)
    }
    type chicken = {mut eggs_per_day:uint};
    type bull = {mut horns:uint};

    type processed = {flag: bool};

    type animal_scope = Scope<animal, processed>;

    #[test]
    fn handles_get_freed() {
        let s: animal_scope = Scope();
        s.handle(&{name:~"henrietta", species:chicken(~{mut eggs_per_day:22u})});
        s.handle(&{name:~"ferdinand", species:bull(~{mut horns:3u})});
    }

    fn mutate(a: &animal) {
        match a.species {
          chicken(c) => c.eggs_per_day += 1u,
          bull(c) => c.horns += 1u
        }
    }

    fn read_characteristic(a: &animal) -> uint {
        match a.species {
          chicken(c) => c.eggs_per_day,
          bull(c) => c.horns
        }
    }

    #[test]
    fn interspersed_execution() {
        let s: animal_scope = Scope();
        let henrietta =
            s.handle(&{name:~"henrietta",
                      species:chicken(~{mut eggs_per_day:0u})});
        let ferdinand =
            s.handle(&{name:~"ferdinand",
                      species:bull(~{mut horns:0u})});

        let iter1 = 3u;
        let iter2 = 22u;
        let read_port = comm::Port();
        let read_chan = comm::Chan(&read_port);

        // fire up a reader task
        for uint::range(0u, iter1) |i| {
            s.reader_forked();
            let wait_chan = task::spawn_listener(|wait_port| {
                for uint::range(0u, iter2) |_i| {
                    comm::send(read_chan, henrietta.read(read_characteristic));
                    comm::send(read_chan, ferdinand.read(read_characteristic));
                    comm::recv(wait_port);
                }
            });

            let hrc = henrietta.read(read_characteristic);
            assert hrc == (i * iter2);

            let frc = ferdinand.read(read_characteristic);
            assert frc == i * iter2;

            for uint::range(0u, iter2) |_i| {
                assert hrc == comm::recv(read_port);
                s.write(&henrietta, mutate);
                assert frc == comm::recv(read_port);
                s.write(&ferdinand, mutate);
                comm::send(wait_chan, ());
            }
            s.reader_joined();
        }

        assert henrietta.read(read_characteristic) == iter1 * iter2;
        assert ferdinand.read(read_characteristic) == iter1 * iter2;
    }
}
<|endoftext|>


<commit_before><commit_msg>Deref in match header as suggested by clippy<commit_after><|endoftext|>


<commit_before>//! Utility module to generate a GraphiQL interface

/// Generate the HTML source to show a GraphiQL interface
pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
    let stylesheet_source = r#"

    "#;
    let fetcher_source = r#"

    "#;

    format!(
        r#"
<!DOCTYPE html>

    <title>GraphQL</title>
    {stylesheet_source}
    <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/graphiql/0.10.2/graphiql.css">

    {fetcher_source}

"#,
        graphql_url = graphql_endpoint_url,
        stylesheet_source = stylesheet_source,
        fetcher_source = fetcher_source
    )
}
<commit_msg>Use latest graphiql (v0.17.2) (#477)<commit_after>//! Utility module to generate a GraphiQL interface

/// Generate the HTML source to show a GraphiQL interface
pub fn graphiql_source(graphql_endpoint_url: &str) -> String {
    let stylesheet_source = r#"

    "#;
    let fetcher_source = r#"

    "#;

    format!(
        r#"
<!DOCTYPE html>

    <title>GraphQL</title>
    {stylesheet_source}
    <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/graphiql@0.17.2/graphiql.min.css">

    {fetcher_source}

"#,
        graphql_url = graphql_endpoint_url,
        stylesheet_source = stylesheet_source,
        fetcher_source = fetcher_source
    )
}
<|endoftext|>


<commit_before>//! A thin wrapper around `ThreadPool` to make sure that we join all things
//! properly.
use crossbeam_channel::Sender;

pub(crate) struct TaskPool<T> {
    sender: Sender<T>,
    inner: threadpool::ThreadPool,
}

impl<T> TaskPool<T> {
    pub(crate) fn new(sender: Sender<T>) -> TaskPool<T> {
        TaskPool { sender, inner: threadpool::ThreadPool::default() }
    }

    pub(crate) fn spawn<F>(&mut self, task: F)
    where
        F: FnOnce() -> T + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || sender.send(task()).unwrap()
        })
    }

    pub(crate) fn spawn_with_sender<F>(&mut self, task: F)
    where
        F: FnOnce(Sender<T>) + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || task(sender)
        })
    }

    pub(crate) fn len(&self) -> usize {
        self.inner.queued_count()
    }
}

impl<T> Drop for TaskPool<T> {
    fn drop(&mut self) {
        self.inner.join()
    }
}
<commit_msg>Increase worker thread stack and name them<commit_after>//! A thin wrapper around `ThreadPool` to make sure that we join all things
//! properly.
use crossbeam_channel::Sender;

pub(crate) struct TaskPool<T> {
    sender: Sender<T>,
    inner: threadpool::ThreadPool,
}

impl<T> TaskPool<T> {
    pub(crate) fn new(sender: Sender<T>) -> TaskPool<T> {
        const STACK_SIZE: usize = 8 * 1024 * 1024;

        let inner = threadpool::Builder::new()
            .thread_name("Worker".into())
            .thread_stack_size(STACK_SIZE)
            .build();
        TaskPool { sender, inner }
    }

    pub(crate) fn spawn<F>(&mut self, task: F)
    where
        F: FnOnce() -> T + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || sender.send(task()).unwrap()
        })
    }

    pub(crate) fn spawn_with_sender<F>(&mut self, task: F)
    where
        F: FnOnce(Sender<T>) + Send + 'static,
        T: Send + 'static,
    {
        self.inner.execute({
            let sender = self.sender.clone();
            move || task(sender)
        })
    }

    pub(crate) fn len(&self) -> usize {
        self.inner.queued_count()
    }
}

impl<T> Drop for TaskPool<T> {
    fn drop(&mut self) {
        self.inner.join()
    }
}
<|endoftext|>


<commit_before>use super::crt_objects::CrtObjectsFallback;
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
use std::collections::BTreeMap;

pub fn options() -> TargetOptions {
    let mut lld_args = Vec::new();
    let mut clang_args = Vec::new();
    let mut arg = |arg: &str| {
        lld_args.push(arg.to_string());
        clang_args.push(format!("-Wl,{}", arg));
    };

    // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
    // using threads causing weird hangs and bugs. Disable it entirely as
    // this isn't yet the bottleneck of compilation at all anyway.
    //
    // FIXME: we should file an upstream issue with LLD about this
    arg("--no-threads");

    // By default LLD only gives us one page of stack (64k) which is a
    // little small. Default to a larger stack closer to other PC platforms
    // (1MB) and users can always inject their own link-args to override this.
    arg("-z");
    arg("stack-size=1048576");

    // By default LLD's memory layout is:
    //
    // 1. First, a blank page
    // 2. Next, all static data
    // 3. Finally, the main stack (which grows down)
    //
    // This has the unfortunate consequence that on stack overflows you
    // corrupt static data and can cause some exceedingly weird bugs. To
    // help detect this a little sooner we instead request that the stack is
    // placed before static data.
    //
    // This means that we'll generate slightly larger binaries as references
    // to static data will take more bytes in the ULEB128 encoding, but
    // stack overflow will be guaranteed to trap as it underflows instead of
    // corrupting static data.
    arg("--stack-first");

    // FIXME we probably shouldn't pass this but instead pass an explicit list
    // of symbols we'll allow to be undefined. We don't currently have a
    // mechanism of knowing, however, which symbols are intended to be imported
    // from the environment and which are intended to be imported from other
    // objects linked elsewhere. This is a coarse approximation but is sure to
    // hide some bugs and frustrate someone at some point, so we should ideally
    // work towards a world where we can explicitly list symbols that are
    // supposed to be imported and have all other symbols generate errors if
    // they remain undefined.
    arg("--allow-undefined");

    // Rust code should never have warnings, and warnings are often
    // indicative of bugs, let's prevent them.
    arg("--fatal-warnings");

    // LLD only implements C++-like demangling, which doesn't match our own
    // mangling scheme. Tell LLD to not demangle anything and leave it up to
    // us to demangle these symbols later. Currently rustc does not perform
    // further demangling, but tools like twiggy and wasm-bindgen are intended
    // to do so.
    arg("--no-demangle");

    // The symbol visibility story is a bit in flux right now with LLD.
    // It's... not entirely clear to me what's going on, but this looks to
    // make everything work when `export_symbols` isn't otherwise called for
    // things like executables.
    //
    // This is really only here to get things working. If it can be removed and
    // basic tests still work, then sounds like it should be removed!
    arg("--export-dynamic");

    let mut pre_link_args = BTreeMap::new();
    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
    pre_link_args.insert(LinkerFlavor::Gcc, clang_args);

    TargetOptions {
        // we allow dynamic linking, but only cdylibs. Basically we allow a
        // final library artifact that exports some symbols (a wasm module) but
        // we don't allow intermediate `dylib` crate types
        dynamic_linking: true,
        only_cdylib: true,

        // This means we'll just embed a `#[start]` function in the wasm module
        executables: true,

        // relatively self-explanatory!
        exe_suffix: ".wasm".to_string(),
        dll_prefix: String::new(),
        dll_suffix: ".wasm".to_string(),
        linker_is_gnu: false,

        max_atomic_width: Some(64),

        // Unwinding doesn't work right now, so the whole target unconditionally
        // defaults to panic=abort. Note that this is guaranteed to change in
        // the future once unwinding is implemented. Don't rely on this as we're
        // basically guaranteed to change it once WebAssembly supports
        // exceptions.
        panic_strategy: PanicStrategy::Abort,

        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
        // threaded model which will legalize atomics to normal operations.
        singlethread: true,

        // no dynamic linking, no need for default visibility!
        default_hidden_visibility: true,

        // Symbol visibility takes care of this for the WebAssembly.
        // Additionally the only known linker, LLD, doesn't support the script
        // arguments just yet
        limit_rdylib_exports: false,

        // we use the LLD shipped with the Rust toolchain by default
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Wasm,

        // No need for indirection here, simd types can always be passed by
        // value as the whole module either has simd or not, which is different
        // from x86 (for example) where programs can have functions that don't
        // enable simd features.
        simd_types_indirect: false,

        pre_link_args,

        crt_objects_fallback: Some(CrtObjectsFallback::Wasm),

        // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
        // PIC code is implemented this has quite a drastric effect if it stays
        // at the default, `pic`. In an effort to keep wasm binaries as minimal
        // as possible we're defaulting to `static` for now, but the hope is
        // that eventually we can ship a `pic`-compatible standard library which
        // works with `static` as well (or works with some method of generating
        // non-relative calls and such later on).
        relocation_model: RelocModel::Static,

        // When the atomics feature is activated then these two keys matter,
        // otherwise they're basically ignored by the standard library. In this
        // mode, however, the `#[thread_local]` attribute works (i.e.
        // `has_elf_tls`) and we need to get it to work by specifying
        // `local-exec` as that's all that's implemented in LLVM today for wasm.
        has_elf_tls: true,
        tls_model: TlsModel::LocalExec,

        // gdb scripts don't work on wasm blobs
        emit_debug_gdb_scripts: false,

        ..Default::default()
    }
}
<commit_msg>Remove the `--no-threads` workaround for wasm targets.<commit_after>use super::crt_objects::CrtObjectsFallback;
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
use std::collections::BTreeMap;

pub fn options() -> TargetOptions {
    let mut lld_args = Vec::new();
    let mut clang_args = Vec::new();
    let mut arg = |arg: &str| {
        lld_args.push(arg.to_string());
        clang_args.push(format!("-Wl,{}", arg));
    };

    // By default LLD only gives us one page of stack (64k) which is a
    // little small. Default to a larger stack closer to other PC platforms
    // (1MB) and users can always inject their own link-args to override this.
    arg("-z");
    arg("stack-size=1048576");

    // By default LLD's memory layout is:
    //
    // 1. First, a blank page
    // 2. Next, all static data
    // 3. Finally, the main stack (which grows down)
    //
    // This has the unfortunate consequence that on stack overflows you
    // corrupt static data and can cause some exceedingly weird bugs. To
    // help detect this a little sooner we instead request that the stack is
    // placed before static data.
    //
    // This means that we'll generate slightly larger binaries as references
    // to static data will take more bytes in the ULEB128 encoding, but
    // stack overflow will be guaranteed to trap as it underflows instead of
    // corrupting static data.
    arg("--stack-first");

    // FIXME we probably shouldn't pass this but instead pass an explicit list
    // of symbols we'll allow to be undefined. We don't currently have a
    // mechanism of knowing, however, which symbols are intended to be imported
    // from the environment and which are intended to be imported from other
    // objects linked elsewhere. This is a coarse approximation but is sure to
    // hide some bugs and frustrate someone at some point, so we should ideally
    // work towards a world where we can explicitly list symbols that are
    // supposed to be imported and have all other symbols generate errors if
    // they remain undefined.
    arg("--allow-undefined");

    // Rust code should never have warnings, and warnings are often
    // indicative of bugs, let's prevent them.
    arg("--fatal-warnings");

    // LLD only implements C++-like demangling, which doesn't match our own
    // mangling scheme. Tell LLD to not demangle anything and leave it up to
    // us to demangle these symbols later. Currently rustc does not perform
    // further demangling, but tools like twiggy and wasm-bindgen are intended
    // to do so.
    arg("--no-demangle");

    // The symbol visibility story is a bit in flux right now with LLD.
    // It's... not entirely clear to me what's going on, but this looks to
    // make everything work when `export_symbols` isn't otherwise called for
    // things like executables.
    //
    // This is really only here to get things working. If it can be removed and
    // basic tests still work, then sounds like it should be removed!
    arg("--export-dynamic");

    let mut pre_link_args = BTreeMap::new();
    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
    pre_link_args.insert(LinkerFlavor::Gcc, clang_args);

    TargetOptions {
        // we allow dynamic linking, but only cdylibs. Basically we allow a
        // final library artifact that exports some symbols (a wasm module) but
        // we don't allow intermediate `dylib` crate types
        dynamic_linking: true,
        only_cdylib: true,

        // This means we'll just embed a `#[start]` function in the wasm module
        executables: true,

        // relatively self-explanatory!
        exe_suffix: ".wasm".to_string(),
        dll_prefix: String::new(),
        dll_suffix: ".wasm".to_string(),
        linker_is_gnu: false,

        max_atomic_width: Some(64),

        // Unwinding doesn't work right now, so the whole target unconditionally
        // defaults to panic=abort. Note that this is guaranteed to change in
        // the future once unwinding is implemented. Don't rely on this as we're
        // basically guaranteed to change it once WebAssembly supports
        // exceptions.
        panic_strategy: PanicStrategy::Abort,

        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
        // threaded model which will legalize atomics to normal operations.
        singlethread: true,

        // no dynamic linking, no need for default visibility!
        default_hidden_visibility: true,

        // Symbol visibility takes care of this for the WebAssembly.
        // Additionally the only known linker, LLD, doesn't support the script
        // arguments just yet
        limit_rdylib_exports: false,

        // we use the LLD shipped with the Rust toolchain by default
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Wasm,

        // No need for indirection here, simd types can always be passed by
        // value as the whole module either has simd or not, which is different
        // from x86 (for example) where programs can have functions that don't
        // enable simd features.
        simd_types_indirect: false,

        pre_link_args,

        crt_objects_fallback: Some(CrtObjectsFallback::Wasm),

        // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
        // PIC code is implemented this has quite a drastric effect if it stays
        // at the default, `pic`. In an effort to keep wasm binaries as minimal
        // as possible we're defaulting to `static` for now, but the hope is
        // that eventually we can ship a `pic`-compatible standard library which
        // works with `static` as well (or works with some method of generating
        // non-relative calls and such later on).
        relocation_model: RelocModel::Static,

        // When the atomics feature is activated then these two keys matter,
        // otherwise they're basically ignored by the standard library. In this
        // mode, however, the `#[thread_local]` attribute works (i.e.
        // `has_elf_tls`) and we need to get it to work by specifying
        // `local-exec` as that's all that's implemented in LLVM today for wasm.
        has_elf_tls: true,
        tls_model: TlsModel::LocalExec,

        // gdb scripts don't work on wasm blobs
        emit_debug_gdb_scripts: false,

        ..Default::default()
    }
}
<|endoftext|>


<commit_before>#[cfg(not(test))]
fn main() {
	let text: String = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$\nare$delineated$by$a$single$'dollar'$character,$write$a$program\nthat$aligns$each$column$of$fields$by$ensuring$that$words$in$each$\ncolumn$are$separated$by$at$least$one$space.\nFurther,$allow$for$each$word$in$a$column$to$be$either$left$\njustified,$right$justified,$or$center$justified$within$its$column.\n".to_string();
	let (chunks, max_lengths) = align_columns(&text);
	print_aligned_columns(&chunks, &max_lengths);
}

fn align_columns(text: &String) -> (Vec<Vec<String>>, Vec<uint>) {
	let mut lines: Vec<String> = text.as_slice().split('\n').map(|s| s.to_string()).collect();
	let mut max_lengths: Vec<uint> = Vec::new();
	let mut chunks: Vec<Vec<String>> = Vec::new();

	for i in range(0u, lines.len()) {
		let input = lines.get_mut(i);
		let split_input: Vec<String> = input.as_slice().split('$').map(|s| s.to_string()).collect();
		chunks.push(split_input.clone());
		let v: Vec<uint> = split_input.iter().map(|chunk| chunk.len() ).collect();

		for i in range(0u, v.len()) {
			if i < max_lengths.len() {
				*max_lengths.get_mut(i) = std::cmp::max(max_lengths[i], v[i]);
			} else {
				max_lengths.push(v[i]);
			}
		}
	}

	(chunks, max_lengths)
}

fn print_aligned_columns(chunks: &Vec<Vec<String>>, max_lengths: &Vec<uint>) {
	// left aligned
	for i in range(0u, chunks.len()) {
		for j in range(0u, chunks[i].len()) {
			print!("{0:<1$}", chunks[i][j], 1 + max_lengths[j]);
		}
		println!("");
	}
	println!("");
	// right aligned
	for i in range(0u, chunks.len()) {
		for j in range(0u, chunks[i].len()) {
			print!("{0:>1$}", chunks[i][j], 1 + max_lengths[j]);
		}
		println!("");
	}
	println!("");
	// center aligned
	for i in range(0u, chunks.len()) {
		for j in range(0u, chunks[i].len()) {
			let ref string: String = chunks[i][j];
			let spaces: uint = 1 + max_lengths[j] - string.len();
			for k in range(0u, spaces>>1) {
				print!(" ");
			}
			print!("{}", string);
			for k in range(0u, spaces - (spaces>>1)) {
				print!(" ");
			}
		}
		println!("");
	}
}

#[test]
fn test_result() {
	let text: String = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$\nare$delineated$by$a$single$'dollar'$character,$write$a$program\nthat$aligns$each$column$of$fields$by$ensuring$that$words$in$each$\ncolumn$are$separated$by$at$least$one$space.\nFurther,$allow$for$each$word$in$a$column$to$be$either$left$\njustified,$right$justified,$or$center$justified$within$its$column.\n".to_string();
	let (chunks, max_lengths) = align_columns(&text);
	for chunkset in chunks.iter() {
		// the number of words in a chunkset is <= the number of values in max_lengths
		assert!(chunkset.len() <= max_lengths.len());
		for j in range(0u, chunkset.len()) {
			// a word in a chunkset cannot be longer than max_lengths
			assert!(chunkset[j].len() <= max_lengths[j]);
		}
	}
	print_aligned_columns(&chunks, &max_lengths);
}<commit_msg>use &str instead of String<commit_after>#[cfg(not(test))]
fn main() {
	let text: &str = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$\nare$delineated$by$a$single$'dollar'$character,$write$a$program\nthat$aligns$each$column$of$fields$by$ensuring$that$words$in$each$\ncolumn$are$separated$by$at$least$one$space.\nFurther,$allow$for$each$word$in$a$column$to$be$either$left$\njustified,$right$justified,$or$center$justified$within$its$column.\n";
	let (chunks, max_lengths) = align_columns(text);
	print_aligned_columns(&chunks, &max_lengths);
}

fn align_columns(text: &str) -> (Vec<Vec<String>>, Vec<uint>) {
	let mut lines: Vec<String> = text.split('\n').map(|s| s.to_string()).collect();
	let mut max_lengths: Vec<uint> = Vec::new();
	let mut chunks: Vec<Vec<String>> = Vec::new();

	for i in range(0u, lines.len()) {
		let input = lines.get_mut(i);
		let split_input: Vec<String> = input.as_slice().split('$').map(|s| s.to_string()).collect();
		chunks.push(split_input.clone());
		let v: Vec<uint> = split_input.iter().map(|chunk| chunk.len() ).collect();

		for i in range(0u, v.len()) {
			if i < max_lengths.len() {
				*max_lengths.get_mut(i) = std::cmp::max(max_lengths[i], v[i]);
			} else {
				max_lengths.push(v[i]);
			}
		}
	}

	(chunks, max_lengths)
}

fn print_aligned_columns(chunks: &Vec<Vec<String>>, max_lengths: &Vec<uint>) {
	// left aligned
	for i in range(0u, chunks.len()) {
		for j in range(0u, chunks[i].len()) {
			print!("{0:<1$}", chunks[i][j], 1 + max_lengths[j]);
		}
		println!("");
	}
	println!("");
	// right aligned
	for i in range(0u, chunks.len()) {
		for j in range(0u, chunks[i].len()) {
			print!("{0:>1$}", chunks[i][j], 1 + max_lengths[j]);
		}
		println!("");
	}
	println!("");
	// center aligned
	for i in range(0u, chunks.len()) {
		for j in range(0u, chunks[i].len()) {
			let ref string: String = chunks[i][j];
			let spaces: uint = 1 + max_lengths[j] - string.len();
			for k in range(0u, spaces>>1) {
				print!(" ");
			}
			print!("{}", string);
			for k in range(0u, spaces - (spaces>>1)) {
				print!(" ");
			}
		}
		println!("");
	}
}

#[test]
fn test_result() {
	let text: &str = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$\nare$delineated$by$a$single$'dollar'$character,$write$a$program\nthat$aligns$each$column$of$fields$by$ensuring$that$words$in$each$\ncolumn$are$separated$by$at$least$one$space.\nFurther,$allow$for$each$word$in$a$column$to$be$either$left$\njustified,$right$justified,$or$center$justified$within$its$column.\n";
	let (chunks, max_lengths) = align_columns(text);
	for chunkset in chunks.iter() {
		// the number of words in a chunkset is <= the number of values in max_lengths
		assert!(chunkset.len() <= max_lengths.len());
		for j in range(0u, chunkset.len()) {
			// a word in a chunkset cannot be longer than max_lengths
			assert!(chunkset[j].len() <= max_lengths[j]);
		}
	}
	print_aligned_columns(&chunks, &max_lengths);
}
<|endoftext|>


<commit_before>//! This module contains the ffi bindings for libao
extern crate libc;

use std::ptr;
use std::f32::consts::{PI};
use libc::{c_int, c_char};

// bitflags! {
//     flags AoByteFormat: c_int {
//         const AO_FMT_LITTLE = 1,
//         const AO_FMT_BIG = 2,
//         const AO_FMT_NATIVE = 4,
//     }
// }

const AO_FMT_LITTLE: c_int = 1;
const AO_FMT_BIG: c_int = 2;
const AO_FMT_NATIVE: c_int = 4;

// Opaque structures for c inter-operation.

/// Opaque structure for libao's ao_device.
#[derive(Debug)]
pub enum AoDevice {}

/// Structure for libao's ao_sample_format.
#[repr(C)]
pub struct AoFormat {
    pub bits: c_int,
    pub rate: c_int,
    pub channels: c_int,
    pub byte_format: c_int,
    pub matrix: *mut c_char,
}

impl Default for AoFormat {
    fn default() -> Self {
        AoFormat {
            bits: 16,
            rate: 44100,
            channels: 2,
            byte_format: AO_FMT_LITTLE,
            matrix: ptr::null_mut(),
        }
    }
}

/// Structure for libao's ao_option.
#[repr(C)]
pub struct AoOption {
    key: *mut c_char,
    value: *mut c_char,
    next: *mut AoOption,
}

#[link(name="ao")]
extern {
    static mut errno: c_int;

    pub fn ao_initialize();
    pub fn ao_driver_id(short_name: *const c_char) -> c_int;
    pub fn ao_default_driver_id() -> c_int;
    pub fn ao_open_live(driver_id: c_int, format: *const AoFormat, options: *const AoOption) -> *mut AoDevice;
    pub fn ao_play(ao_device: *const AoDevice, output_samples: *const c_char, num_bytes: u32) -> c_int;
    pub fn ao_close(ao_device: *const AoDevice) -> c_int;
    pub fn ao_shutdown();
}

// fn main() {
//     let driver = unsafe {
//         ao_initialize();
//         ao_default_driver_id()
//     };

//     let freq = 440.0;
//     let mut format = AoFormat::default();

//     let device = unsafe { ao_open_live(driver, &mut format, ptr::null_mut()) };

//     // Creates buffer.
//     let buff_size = (format.bits / 8 * format.channels * format.rate) as u32;
//     let mut buffer: Vec<i8> = Vec::with_capacity(buff_size as usize);
//     unsafe { buffer.set_len(buff_size as usize); }
//     for (i, chunk) in buffer.chunks_mut(4).enumerate() {
//         let sample = (0.75 * 32768.0 * (2.0 * PI * freq * (i as f32) / (format.rate as f32)).sin()) as i16;
//         chunk[0] = (sample & 0xff) as i8;
//         chunk[2] = (sample & 0xff) as i8;
//         chunk[1] = ((sample >> 8) & 0xff) as i8;
//         chunk[3] = ((sample >> 8) & 0xff) as i8;
//         println!("{:?}", chunk);
//     }

//     let mut ret = -10;
//     unsafe {
//         ret = ao_play(device, buffer.as_mut_ptr(), buff_size);
//         ao_close(device);
//         ao_shutdown();
//     }

//     println!("Device: {:?}", device);
//     println!("Ret: {:?}", buff_size);
// }
<commit_msg>Moved example to its own file<commit_after>//! This module contains the ffi bindings for libao
use libc::{c_int, c_char};

const AO_FMT_LITTLE: c_int = 1;
const AO_FMT_BIG: c_int = 2;
const AO_FMT_NATIVE: c_int = 4;

// Opaque structures for c inter-operation.

/// Opaque structure for libao's ao_device.
#[derive(Debug)]
pub enum AoDevice {}

/// Structure for libao's ao_sample_format.
#[repr(C)]
pub struct AoFormat {
    pub bits: c_int,
    pub rate: c_int,
    pub channels: c_int,
    pub byte_format: c_int,
    pub matrix: *mut c_char,
}

/// Structure for libao's ao_option.
#[repr(C)]
pub struct AoOption {
    key: *mut c_char,
    value: *mut c_char,
    next: *mut AoOption,
}

#[link(name="ao")]
extern {
    static mut errno: c_int;

    pub fn ao_initialize();
    pub fn ao_driver_id(short_name: *const c_char) -> c_int;
    pub fn ao_default_driver_id() -> c_int;
    pub fn ao_open_live(driver_id: c_int, format: *const AoFormat, options: *const AoOption) -> *mut AoDevice;
    pub fn ao_play(ao_device: *const AoDevice, output_samples: *const c_char, num_bytes: u32) -> c_int;
    pub fn ao_close(ao_device: *const AoDevice) -> c_int;
    pub fn ao_shutdown();
}
<|endoftext|>


<commit_before>use std::string::String;
use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::punctuation::Punctuations;
use syntax::ast::expr::Expr;

pub struct ErrorMsg {
    pub line: usize,
    pub column: usize,
    pub message: String,
}

#[allow(dead_code)]
enum OldExpr {
    Integer(IntegerAST),
    UInteger(UIntegerAST),
    Float(FloatAST),
}

impl OldExpr {
    #[allow(unused_variables)]
    fn gen_code(&self) -> () {
        match *self {
            OldExpr::Integer(ref node) => (),
            OldExpr::UInteger(ref node) => (),
            OldExpr::Float(ref node) => (),
        }
    }
}

#[allow(dead_code)]
struct IntegerAST {
    val: i64,
}

#[allow(dead_code)]
struct UIntegerAST {
    val: u64,
}

#[allow(dead_code)]
struct FloatAST {
    val: f64,
}

#[allow(dead_code)]
pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indentation: u64,
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        Parser {
            lexer: tokenizer,
            indentation: 0,
        }
    }

    // Get the next token from the lexer
    fn next_token(&mut self) -> Token {
        self.lexer.get_tok()
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&self, msg: &str) -> ErrorMsg {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        ErrorMsg {
            line: start_line,
            column: start_column,
            message: msg.to_string(),
        }
    }

    fn expect_error(&self, reason: &str, expect: &str, got: &str) -> ErrorMsg {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got))
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&self, depth: u64) -> Result<Option<OldExpr>, ErrorMsg> {
        if self.indentation == depth {
            return Ok(None);
        }
        Err(self.write_error("Incorrect indentation level"))
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    fn parse_declaration(&mut self) -> Result<Option<OldExpr>, ErrorMsg> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();
                match token1 {
                    // Punctuation(punc) => {
                    //     match punc {
                    //         punctuation::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Punctuation here"))
                    //     }
                    // }
                    Punctuation(Punctuations::Equals) => {
                        self.parse_expression()
                    },
                    _ => Err(self.write_error("Invalid sequence"))
                }
            },
            Error(msg) => Err(self.write_error(&msg)),
            _ => Err(self.expect_error("", "a variable name", "something else"))
        }
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Result<Option<OldExpr>, ErrorMsg> {
        match keyword {
            Keywords::Def => {
                self.parse_declaration()
            },
            _ => Err(self.write_error(&format!("Unsupported keyword {:?}.", keyword)))
        }
    }

    fn parse_expression(&self) -> Result<Option<OldExpr>, ErrorMsg> {
        Ok(None)
    }

    // Parse numbers into their correct representation
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Result<Option<OldExpr>, ErrorMsg> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        Ok(Some(OldExpr::Integer(IntegerAST { val: value })))
    }

    // Parse the file
    #[allow(unused_variables)]
    pub fn parse(&mut self) {
        self.start();

        loop {
            // Parse the token into the next node of the AST
            let result: Result<Option<OldExpr>, ErrorMsg>;
            let token = self.next_token();

            // Debug:
            println!("{:?}", token);

            result = match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
                    self.parse_expression()
                },
                Indent(depth) => {
                    panic!("Unimplemented top level token 'Indent'");
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    self.handle_keywords(keyword)
                },
                Punctuation(punc) => {
                    panic!("Unimplemented top level token 'Punctuation'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                    Ok(None)
                },
                Error(err) => {
                    Err(self.write_error(&err))
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => {
                    Ok(None)
                }
            };

            // `result` can either raise an error or not return an AST,
            // deal with its potential values
            match result {
                Ok(value) => {
                    match value {
                        Some(node) => {
                            node.gen_code();
                        },
                        None => {
                        }
                    }
                },
                Err(e) => {
                    panic!("Error on line: {} col: {}, {}", e.line, e.column, e.message);
                }
            };
        }
    }
}
<commit_msg>Made indents do nothing.<commit_after>use std::string::String;
use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::punctuation::Punctuations;
use syntax::ast::expr::Expr;

pub struct ErrorMsg {
    pub line: usize,
    pub column: usize,
    pub message: String,
}

#[allow(dead_code)]
enum OldExpr {
    Integer(IntegerAST),
    UInteger(UIntegerAST),
    Float(FloatAST),
}

impl OldExpr {
    #[allow(unused_variables)]
    fn gen_code(&self) -> () {
        match *self {
            OldExpr::Integer(ref node) => (),
            OldExpr::UInteger(ref node) => (),
            OldExpr::Float(ref node) => (),
        }
    }
}

#[allow(dead_code)]
struct IntegerAST {
    val: i64,
}

#[allow(dead_code)]
struct UIntegerAST {
    val: u64,
}

#[allow(dead_code)]
struct FloatAST {
    val: f64,
}

#[allow(dead_code)]
pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indentation: u64,
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        Parser {
            lexer: tokenizer,
            indentation: 0,
        }
    }

    // Get the next token from the lexer
    fn next_token(&mut self) -> Token {
        self.lexer.get_tok()
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&self, msg: &str) -> ErrorMsg {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        ErrorMsg {
            line: start_line,
            column: start_column,
            message: msg.to_string(),
        }
    }

    fn expect_error(&self, reason: &str, expect: &str, got: &str) -> ErrorMsg {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got))
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&self, depth: u64) -> Result<Option<OldExpr>, ErrorMsg> {
        if self.indentation == depth {
            return Ok(None);
        }
        Err(self.write_error("Incorrect indentation level"))
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    fn parse_declaration(&mut self) -> Result<Option<OldExpr>, ErrorMsg> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();
                match token1 {
                    // Punctuation(punc) => {
                    //     match punc {
                    //         punctuation::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Punctuation here"))
                    //     }
                    // }
                    Punctuation(Punctuations::Equals) => {
                        self.parse_expression()
                    },
                    _ => Err(self.write_error("Invalid sequence"))
                }
            },
            Error(msg) => Err(self.write_error(&msg)),
            _ => Err(self.expect_error("", "a variable name", "something else"))
        }
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Result<Option<OldExpr>, ErrorMsg> {
        match keyword {
            Keywords::Def => {
                self.parse_declaration()
            },
            _ => Err(self.write_error(&format!("Unsupported keyword {:?}.", keyword)))
        }
    }

    fn parse_expression(&self) -> Result<Option<OldExpr>, ErrorMsg> {
        Ok(None)
    }

    // Parse numbers into their correct representation
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Result<Option<OldExpr>, ErrorMsg> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        Ok(Some(OldExpr::Integer(IntegerAST { val: value })))
    }

    // Parse the file
    #[allow(unused_variables)]
    pub fn parse(&mut self) {
        self.start();

        loop {
            // Parse the token into the next node of the AST
            let result: Result<Option<OldExpr>, ErrorMsg>;
            let token = self.next_token();

            // Debug:
            println!("{:?}", token);

            result = match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
                    self.parse_expression()
                },
                Indent(depth) => {
                    // ToDo: Keep track of indentation level when preceeding a statement
                    Ok(None)
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    self.handle_keywords(keyword)
                },
                Punctuation(punc) => {
                    panic!("Unimplemented top level token 'Punctuation'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                    Ok(None)
                },
                Error(err) => {
                    Err(self.write_error(&err))
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => {
                    Ok(None)
                }
            };

            // `result` can either raise an error or not return an AST,
            // deal with its potential values
            match result {
                Ok(value) => {
                    match value {
                        Some(node) => {
                            node.gen_code();
                        },
                        None => {
                        }
                    }
                },
                Err(e) => {
                    panic!("Error on line: {} col: {}, {}", e.line, e.column, e.message);
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>//! Methods for converting shapes into triangles.

use std::f64::consts::{
    PI,
    PI_2,
    FRAC_PI_2,
};
use {
    Color,
    Image,
    Line,
    Matrix2d,
    Rectangle,
};
use interpolation::{lerp};
use vecmath::{
    multiply,
    orient,
    translate,
};

#[inline(always)]
fn tx(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[0] * x + m[1] * y + m[2]) as f32
}

#[inline(always)]
fn ty(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[3] * x + m[4] * y + m[5]) as f32
}

/// Streams tweened polygons using linear interpolation.
#[inline(always)]
pub fn with_lerp_polygons_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygons: &[&[f64]],
    tween_factor: f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let poly_len = polygons.len() as f64;
    // Map to interval between 0 and 1.
    let tw = tween_factor % 1.0;
    // Map negative values to positive.
    let tw = if tw < 0.0 { tw + 1.0 } else { tw };
    // Map to frame.
    let tw = tw * poly_len;
    // Get the current frame.
    let frame = tw as uint;
    // Get the next frame.
    let next_frame = (frame + 1) % polygons.len();
    let p0 = polygons[frame];
    let p1 = polygons[next_frame];
    // Get factor between frames.
    let tw = tw - frame as f64;
    let n = polygons[0].len();
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 2;
        let (x0, y0) = (p0[j], p0[j+1]);
        let (x1, y1) = (p1[j], p1[j+1]);
        Some([lerp(&x0, &x1, &tw), lerp(&y0, &y1, &tw)])
    }, color, f);
}

/// Streams an ellipse specified by a resolution.
#[inline(always)]
pub fn with_ellipse_tri_list_xy_f32_rgba_f32(
    resolution: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (cw, ch) = (0.5 * w, 0.5 * h);
    let (cx, cy) = (x + cw, y + ch);
    let n = resolution;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let angle = i as f64 / n as f64 * PI_2;
        i += 1;
        Some([cx + angle.cos() * cw, cy + angle.sin() * ch])
    }, color, f);
}

/// Streams a round border line.
#[inline(always)]
pub fn with_round_border_line_tri_list_xy_f32_rgba_f32(
    resolution_cap: uint,
    m: &Matrix2d,
    line: &Line,
    round_border_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let radius = *round_border_radius;
    let (x1, y1, x2, y2) = (line[0], line[1], line[2], line[3]);
    let (dx, dy) = (x2 - x1, y2 - y1);
    let w = (dx * dx + dy * dy).sqrt();
    let m = multiply(m, &translate(x1, y1));
    let m = multiply(&m, &orient(dx, dy));
    let n = resolution_cap * 2;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(&m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        // Detect the half circle from index.
        // There is one half circle at each end of the line.
        // Together they form a full circle if the length of the line is zero.
        match j {
            j if j >= resolution_cap => {
                // Compute the angle to match start and end point of half circle.
                // This requires an angle offset since the other end of line is the first half circle.
                let angle = (j - resolution_cap) as f64 / (resolution_cap - 1) as f64 * PI + PI;
                // Rotate 90 degrees since the line is horizontal.
                let angle = angle + FRAC_PI_2;
                Some([w + angle.cos() * radius, angle.sin() * radius])
            },
            j => {
                // Compute the angle to match start and end point of half circle.
                let angle = j as f64 / (resolution_cap - 1) as f64 * PI;
                // Rotate 90 degrees since the line is horizontal.
                let angle = angle + FRAC_PI_2;
                Some([angle.cos() * radius, angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a round rectangle.
#[inline(always)]
pub fn with_round_rectangle_tri_list_xy_f32_rgba_f32(
    resolution_corner: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    round_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = *round_radius;
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a polygon into tri list with color per vertex.
/// Uses buffers that fit inside L1 cache.
pub fn stream_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: || -> Option<[f64, ..2]>,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let mut vertices: [f32, ..740] = [0.0, ..740];
    let mut colors: [f32, ..1480] = [0.0, ..1480];
    // Get the first point which will be used a lot.
    let fp = match polygon() { None => return, Some(val) => val };
    let (fx, fy) = (tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1]));
    let gp = match polygon() { None => return, Some(val) => val };
    let (gx, gy) = (tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1]));
    let mut gx = gx;
    let mut gy = gy;
    let mut i = 0;
    'read_vertices: loop {
        let ind_out = i * 2 * 3;
        vertices[ind_out + 0] = fx;
        vertices[ind_out + 1] = fy;
        let ind_out = i * 4 * 3;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];

        // Copy vertex.
        let ind_out = i * 2 * 3 + 2;
        let p =
            match polygon() {
                None => break 'read_vertices,
                Some(val) => val,
            };
        let x = tx(m, p[0], p[1]);
        let y = ty(m, p[0], p[1]);

        vertices[ind_out + 0] = gx;
        vertices[ind_out + 1] = gy;
        vertices[ind_out + 2] = x;
        vertices[ind_out + 3] = y;
        gx = x;
        gy = y;
        let ind_out = i * 4 * 3 + 4;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];
        colors[ind_out + 4] = color[0];
        colors[ind_out + 5] = color[1];
        colors[ind_out + 6] = color[2];
        colors[ind_out + 7] = color[3];

        i += 1;
        // Buffer is full.
        if i * 2 * 3 + 2 == vertices.len() {
            // Send chunk and start over.
            f(vertices.slice(0, i * 2 * 3),
                colors.slice(0, i * 4 * 3));
            i = 0;
        }
    }

    if i > 0 {
        f(vertices.slice(0, i * 2 * 3),
            colors.slice(0, i * 4 * 3));
    }
}

/// Splits polygon into convex segments with one color per vertex.
/// Create a buffer that fits into L1 cache with 1KB overhead.
pub fn with_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: &[f64],
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let n = polygon.len();
    let mut i = 0;
    stream_polygon_tri_list_xy_f32_rgba_f32(
        m, || {
            if i >= n { return None; }

            let j = i;
            i += 2;
            Some([polygon[j], polygon[j+1]])
        }, color, f);
}

/// Creates triangle list vertices from rectangle.
pub fn rect_tri_list_xy_f32(m: &Matrix2d, rect: &Rectangle) -> [f32, ..12] {
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (x2, y2) = (x + w, y + h);
    [tx(m,x,y), ty(m,x,y), tx(m,x2,y), ty(m,x2,y), tx(m,x,y2), ty(m,x,y2),
     tx(m,x2,y), ty(m,x2,y), tx(m,x2,y2), ty(m,x2,y2), tx(m,x,y2), ty(m,x,y2)]
}

/// Creates triangle list colors from rectangle.
pub fn rect_tri_list_rgba_f32(color: &Color) -> [f32, ..48] {
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    [r, g, b, a, // 0
     r, g, b, a, // 1
     r, g, b, a, // 2
     r, g, b, a, // 3
     r, g, b, a, // 4
     r, g, b, a, // 5
     r, g, b, a, // 6
     r, g, b, a, // 7
     r, g, b, a, // 8
     r, g, b, a, // 9
     r, g, b, a, // 10
     r, g, b, a]
}

/// Creates triangle list texture coords from image.
pub fn rect_tri_list_uv_f32(image: &Image) -> [f32, ..12] {
    let x1 = image.source_rect[0] as f32 / image.texture_width as f32;
    let y1 = image.source_rect[1] as f32 / image.texture_height as f32;
    let x2 = (image.source_rect[0] + image.source_rect[2]) as f32 / image.texture_width as f32;
    let y2 = (image.source_rect[1] + image.source_rect[3]) as f32 / image.texture_height as f32;
    [x1, y1, x2, y1, x1, y2,
     x2, y1, x2, y2, x1, y2]
}
<commit_msg>Fix defect in round rectangle fill<commit_after>//! Methods for converting shapes into triangles.

use std::f64::consts::{
    PI,
    PI_2,
    FRAC_PI_2,
};
use {
    Color,
    Image,
    Line,
    Matrix2d,
    Rectangle,
};
use interpolation::{lerp};
use vecmath::{
    multiply,
    orient,
    translate,
};

#[inline(always)]
fn tx(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[0] * x + m[1] * y + m[2]) as f32
}

#[inline(always)]
fn ty(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[3] * x + m[4] * y + m[5]) as f32
}

/// Streams tweened polygons using linear interpolation.
#[inline(always)]
pub fn with_lerp_polygons_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygons: &[&[f64]],
    tween_factor: f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let poly_len = polygons.len() as f64;
    // Map to interval between 0 and 1.
    let tw = tween_factor % 1.0;
    // Map negative values to positive.
    let tw = if tw < 0.0 { tw + 1.0 } else { tw };
    // Map to frame.
    let tw = tw * poly_len;
    // Get the current frame.
    let frame = tw as uint;
    // Get the next frame.
    let next_frame = (frame + 1) % polygons.len();
    let p0 = polygons[frame];
    let p1 = polygons[next_frame];
    // Get factor between frames.
    let tw = tw - frame as f64;
    let n = polygons[0].len();
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 2;
        let (x0, y0) = (p0[j], p0[j+1]);
        let (x1, y1) = (p1[j], p1[j+1]);
        Some([lerp(&x0, &x1, &tw), lerp(&y0, &y1, &tw)])
    }, color, f);
}

/// Streams an ellipse specified by a resolution.
#[inline(always)]
pub fn with_ellipse_tri_list_xy_f32_rgba_f32(
    resolution: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (cw, ch) = (0.5 * w, 0.5 * h);
    let (cx, cy) = (x + cw, y + ch);
    let n = resolution;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let angle = i as f64 / n as f64 * PI_2;
        i += 1;
        Some([cx + angle.cos() * cw, cy + angle.sin() * ch])
    }, color, f);
}

/// Streams a round border line.
#[inline(always)]
pub fn with_round_border_line_tri_list_xy_f32_rgba_f32(
    resolution_cap: uint,
    m: &Matrix2d,
    line: &Line,
    round_border_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let radius = *round_border_radius;
    let (x1, y1, x2, y2) = (line[0], line[1], line[2], line[3]);
    let (dx, dy) = (x2 - x1, y2 - y1);
    let w = (dx * dx + dy * dy).sqrt();
    let m = multiply(m, &translate(x1, y1));
    let m = multiply(&m, &orient(dx, dy));
    let n = resolution_cap * 2;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(&m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        // Detect the half circle from index.
        // There is one half circle at each end of the line.
        // Together they form a full circle if the length of the line is zero.
        match j {
            j if j >= resolution_cap => {
                // Compute the angle to match start and end point of half circle.
                // This requires an angle offset since the other end of line is the first half circle.
                let angle = (j - resolution_cap) as f64 / (resolution_cap - 1) as f64 * PI + PI;
                // Rotate 90 degrees since the line is horizontal.
                let angle = angle + FRAC_PI_2;
                Some([w + angle.cos() * radius, angle.sin() * radius])
            },
            j => {
                // Compute the angle to match start and end point of half circle.
                let angle = j as f64 / (resolution_cap - 1) as f64 * PI;
                // Rotate 90 degrees since the line is horizontal.
                let angle = angle + FRAC_PI_2;
                Some([angle.cos() * radius, angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a round rectangle.
#[inline(always)]
pub fn with_round_rectangle_tri_list_xy_f32_rgba_f32(
    resolution_corner: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    round_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = *round_radius;
    let n = resolution_corner * 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        // Detect quarter circle from index.
        // There is one quarter circle at each corner.
        // Together they form a full circle if each side of rectangle is 2 times the radius.
        match j {
            j if j >= resolution_corner * 3 => {
                // Compute the angle to match start and end point of quarter circle.
                // This requires an angle offset since this is the last quarter.
                let angle = (j - resolution_corner * 3) as f64 / (resolution_corner - 1) as f64 * FRAC_PI_2
                    + 3.0 * FRAC_PI_2;
                // Set center of the circle to the last corner.
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                // Compute the angle to match start and end point of quarter circle.
                // This requires an angle offset since this is the second last quarter.
                let angle = (j - resolution_corner * 2) as f64 / (resolution_corner - 1) as f64 * FRAC_PI_2
                    + PI;
                // Set center of the circle to the second last corner.
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                // Compute the angle to match start and end point of quarter circle.
                // This requires an angle offset since this is the second quarter.
                let angle = (j - resolution_corner) as f64 / (resolution_corner - 1) as f64 * FRAC_PI_2
                    + FRAC_PI_2;
                // Set center of the circle to the second corner.
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                // Compute the angle to match start and end point of quarter circle.
                let angle = j as f64 / (resolution_corner - 1) as f64 * FRAC_PI_2;
                // Set center of the circle to the first corner.
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a polygon into tri list with color per vertex.
/// Uses buffers that fit inside L1 cache.
pub fn stream_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: || -> Option<[f64, ..2]>,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let mut vertices: [f32, ..740] = [0.0, ..740];
    let mut colors: [f32, ..1480] = [0.0, ..1480];
    // Get the first point which will be used a lot.
    let fp = match polygon() { None => return, Some(val) => val };
    let (fx, fy) = (tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1]));
    let gp = match polygon() { None => return, Some(val) => val };
    let (gx, gy) = (tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1]));
    let mut gx = gx;
    let mut gy = gy;
    let mut i = 0;
    'read_vertices: loop {
        let ind_out = i * 2 * 3;
        vertices[ind_out + 0] = fx;
        vertices[ind_out + 1] = fy;
        let ind_out = i * 4 * 3;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];

        // Copy vertex.
        let ind_out = i * 2 * 3 + 2;
        let p =
            match polygon() {
                None => break 'read_vertices,
                Some(val) => val,
            };
        let x = tx(m, p[0], p[1]);
        let y = ty(m, p[0], p[1]);

        vertices[ind_out + 0] = gx;
        vertices[ind_out + 1] = gy;
        vertices[ind_out + 2] = x;
        vertices[ind_out + 3] = y;
        gx = x;
        gy = y;
        let ind_out = i * 4 * 3 + 4;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];
        colors[ind_out + 4] = color[0];
        colors[ind_out + 5] = color[1];
        colors[ind_out + 6] = color[2];
        colors[ind_out + 7] = color[3];

        i += 1;
        // Buffer is full.
        if i * 2 * 3 + 2 == vertices.len() {
            // Send chunk and start over.
            f(vertices.slice(0, i * 2 * 3),
                colors.slice(0, i * 4 * 3));
            i = 0;
        }
    }

    if i > 0 {
        f(vertices.slice(0, i * 2 * 3),
            colors.slice(0, i * 4 * 3));
    }
}

/// Splits polygon into convex segments with one color per vertex.
/// Create a buffer that fits into L1 cache with 1KB overhead.
pub fn with_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: &[f64],
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let n = polygon.len();
    let mut i = 0;
    stream_polygon_tri_list_xy_f32_rgba_f32(
        m, || {
            if i >= n { return None; }

            let j = i;
            i += 2;
            Some([polygon[j], polygon[j+1]])
        }, color, f);
}

/// Creates triangle list vertices from rectangle.
pub fn rect_tri_list_xy_f32(m: &Matrix2d, rect: &Rectangle) -> [f32, ..12] {
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (x2, y2) = (x + w, y + h);
    [tx(m,x,y), ty(m,x,y), tx(m,x2,y), ty(m,x2,y), tx(m,x,y2), ty(m,x,y2),
     tx(m,x2,y), ty(m,x2,y), tx(m,x2,y2), ty(m,x2,y2), tx(m,x,y2), ty(m,x,y2)]
}

/// Creates triangle list colors from rectangle.
pub fn rect_tri_list_rgba_f32(color: &Color) -> [f32, ..48] {
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    [r, g, b, a, // 0
     r, g, b, a, // 1
     r, g, b, a, // 2
     r, g, b, a, // 3
     r, g, b, a, // 4
     r, g, b, a, // 5
     r, g, b, a, // 6
     r, g, b, a, // 7
     r, g, b, a, // 8
     r, g, b, a, // 9
     r, g, b, a, // 10
     r, g, b, a]
}

/// Creates triangle list texture coords from image.
pub fn rect_tri_list_uv_f32(image: &Image) -> [f32, ..12] {
    let x1 = image.source_rect[0] as f32 / image.texture_width as f32;
    let y1 = image.source_rect[1] as f32 / image.texture_height as f32;
    let x2 = (image.source_rect[0] + image.source_rect[2]) as f32 / image.texture_width as f32;
    let y2 = (image.source_rect[1] + image.source_rect[3]) as f32 / image.texture_height as f32;
    [x1, y1, x2, y1, x1, y2,
     x2, y1, x2, y2, x1, y2]
}
<|endoftext|>