<commit_before>use std::marker;
use std::slice;
use std::ptr;
use libc::{c_int, c_uint, c_void, size_t};

use {raw, panic, Repository, Error, Oid, Revwalk, Buf};
use util::Binding;

/// Stages that are reported by the PackBuilder progress callback.
pub enum PackBuilderStage {
    /// Adding objects to the pack
    AddingObjects,
    /// Deltafication of the pack
    Deltafication,
}

pub type ProgressCb<'a> = FnMut(PackBuilderStage, u32, u32) -> bool + 'a;
pub type ForEachCb<'a> = FnMut(&[u8]) -> bool + 'a;

/// A builder for creating a packfile
pub struct PackBuilder<'repo> {
    raw: *mut raw::git_packbuilder,
    _marker: marker::PhantomData<&'repo Repository>,
}

impl<'repo> PackBuilder<'repo> {
    /// Insert a single object. For an optimal pack it's mandatory to insert
    /// objects in recency order, commits followed by trees and blobs.
    pub fn insert_object(&mut self,
                         id: Oid,
                         name: Option<&str>)
                         -> Result<(), Error> {
        let name = try!(::opt_cstr(name));
        unsafe {
            try_call!(raw::git_packbuilder_insert(self.raw, &*id.raw(), name));
        }
        Ok(())
    }

    /// Insert a root tree object. This will add the tree as well as all
    /// referenced trees and blobs.
    pub fn insert_tree(&mut self, id: Oid) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_packbuilder_insert_tree(self.raw, &*id.raw()));
        }
        Ok(())
    }

    /// Insert a commit object. This will add a commit as well as the completed
    /// referenced tree.
    pub fn insert_commit(&mut self, id: Oid) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_packbuilder_insert_commit(self.raw, &*id.raw()));
        }
        Ok(())
    }

    /// Insert objects as given by the walk. Those commits and all objects they
    /// reference will be inserted into the packbuilder.
    pub fn insert_walk(&mut self, walk: &mut Revwalk) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_packbuilder_insert_walk(self.raw, walk.raw()));
        }
        Ok(())
    }

    /// Recursively insert an object and its referenced objects. Insert the
    /// object as well as any object it references.
    pub fn insert_recursive(&mut self,
                            id: Oid,
                            name: Option<&str>)
                            -> Result<(), Error> {
        let name = try!(::opt_cstr(name));
        unsafe {
            try_call!(raw::git_packbuilder_insert_recur(self.raw,
                                                        &*id.raw(),
                                                        name));
        }
        Ok(())
    }

    /// Write the contents of the packfile to an in-memory buffer. The contents
    /// of the buffer will become a valid packfile, even though there will be
    /// no attached index.
    ///
    /// `progress` will be called with progress information during pack
    /// building. Be aware that this is called inline with pack building
    /// operations, so performance may be affected.
    pub fn write_buf(&mut self,
                     buf: &mut Buf,
                     progress: Option<&mut ProgressCb>)
                     -> Result<(), Error> {
        let has_progress = progress.is_some();
        if let Some(mut progress) = progress {
            let ptr = &mut progress as *mut _;
            let progress_c = Some(progress_c as raw::git_packbuilder_progress);
            unsafe {
                try_call!(raw::git_packbuilder_set_callbacks(self.raw,
                                                             progress_c,
                                                             ptr as *mut _));
            }
        }
        unsafe {
            try_call!(raw::git_packbuilder_write_buf(buf.raw(), self.raw));
        }
        if has_progress {
            unsafe {
                try_call!(raw::git_packbuilder_set_callbacks(self.raw,
                                                             None,
                                                             ptr::null_mut()));
            }
        }
        Ok(())
    }

    /// Create the new pack and pass each object to the callback.
    ///
    /// `progress` will be called with progress information during pack
    /// building. Be aware that this is called inline with pack building
    /// operations, so performance may be affected.
    pub fn foreach(&mut self,
                   mut cb: &mut ForEachCb,
                   progress: Option<&mut ProgressCb>)
                   -> Result<(), Error> {
        let has_progress = progress.is_some();
        if let Some(mut progress) = progress {
            let ptr = &mut progress as *mut _;
            let progress_c = Some(progress_c as raw::git_packbuilder_progress);
            unsafe {
                try_call!(raw::git_packbuilder_set_callbacks(self.raw,
                                                             progress_c,
                                                             ptr as *mut _));
            }
        }
        let ptr = &mut cb as *mut _;
        unsafe {
            try_call!(raw::git_packbuilder_foreach(self.raw,
                                                   foreach_c,
                                                   ptr as *mut _));
        }
        if has_progress {
            unsafe {
                try_call!(raw::git_packbuilder_set_callbacks(self.raw,
                                                             None,
                                                             ptr::null_mut()));
            }
        }
        Ok(())
    }

    /// Get the total number of objects the packbuilder will write out.
    pub fn object_count(&self) -> usize {
        unsafe { raw::git_packbuilder_object_count(self.raw) as usize }
    }

    /// Get the number of objects the packbuilder has already written out.
    pub fn written(&self) -> usize {
        unsafe { raw::git_packbuilder_written(self.raw) as usize }
    }

    /// Get the packfile's hash. A packfile's name is derived from the sorted
    /// hashing of all object names. This is only correct after the packfile
    /// has been written.
    pub fn hash(&self) -> Option<Oid> {
        if self.object_count() == 0 {
            unsafe {
                Some(Binding::from_raw(raw::git_packbuilder_hash(self.raw)))
            }
        } else {
            None
        }
    }
}

impl<'repo> Binding for PackBuilder<'repo> {
    type Raw = *mut raw::git_packbuilder;
    unsafe fn from_raw(ptr: *mut raw::git_packbuilder) -> PackBuilder<'repo> {
        PackBuilder {
            raw: ptr,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_packbuilder {
        self.raw
    }
}

impl<'repo> Drop for PackBuilder<'repo> {
    fn drop(&mut self) {
        unsafe { raw::git_packbuilder_free(self.raw) }
    }
}

impl Binding for PackBuilderStage {
    type Raw = raw::git_packbuilder_stage_t;
    unsafe fn from_raw(raw: raw::git_packbuilder_stage_t) -> PackBuilderStage {
        match raw {
            raw::GIT_PACKBUILDER_ADDING_OBJECTS => PackBuilderStage::AddingObjects,
            raw::GIT_PACKBUILDER_DELTAFICATION => PackBuilderStage::Deltafication,
            _ => panic!("Unknown git diff binary kind"),
        }
    }
    fn raw(&self) -> raw::git_packbuilder_stage_t {
        match *self {
            PackBuilderStage::AddingObjects => raw::GIT_PACKBUILDER_ADDING_OBJECTS,
            PackBuilderStage::Deltafication => raw::GIT_PACKBUILDER_DELTAFICATION,
        }
    }
}

extern "C" fn foreach_c(buf: *const c_void,
                        size: size_t,
                        data: *mut c_void)
                        -> c_int {
    unsafe {
        let buf = slice::from_raw_parts(buf as *const u8, size as usize);

        let r = panic::wrap(|| {
            let data = data as *mut &mut ForEachCb;
            (*data)(buf)
        });
        if r == Some(true) {
            0
        } else {
            -1
        }
    }
}

extern "C" fn progress_c(stage: raw::git_packbuilder_stage_t,
                         current: c_uint,
                         total: c_uint,
                         data: *mut c_void)
                         -> c_int {
    unsafe {
        let stage = Binding::from_raw(stage);

        let r = panic::wrap(|| {
            let data = data as *mut &mut ProgressCb;
            (*data)(stage, current, total)
        });
        if r == Some(true) {
            0
        } else {
            -1
        }
    }
}

#[cfg(test)]
mod tests {
    use std::fs::File;
    use std::path::Path;
    use {Buf, Repository, Oid};

    fn commit(repo: &Repository) -> (Oid, Oid) {
        let mut index = t!(repo.index());
        let root = repo.path().parent().unwrap();
        t!(File::create(&root.join("foo")));
        t!(index.add_path(Path::new("foo")));

        let tree_id = t!(index.write_tree());
        let tree = t!(repo.find_tree(tree_id));
        let sig = t!(repo.signature());
        let head_id = t!(repo.refname_to_id("HEAD"));
        let parent = t!(repo.find_commit(head_id));
        let commit = t!(repo.commit(Some("HEAD"),
                                    &sig,
                                    &sig,
                                    "commit",
                                    &tree,
                                    &[&parent]));
        (commit, tree_id)
    }

    fn pack_header(len: u8) -> Vec<u8> {
        [].into_iter()
          .chain(b"PACK") // signature
          .chain(&[0, 0, 0, 2]) // version number
          .chain(&[0, 0, 0, len]) // number of objects
          .cloned().collect::<Vec<u8>>()
    }

    #[test]
    fn smoke() {
        let (_td, repo) = ::test::repo_init();
        let _builder = t!(repo.packbuilder());
    }

    #[test]
    fn smoke_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        t!(builder.write_buf(&mut buf, None));
        assert!(builder.hash().unwrap().is_zero());
        let expected = pack_header(0).iter()
            .chain(&[0x02, 0x9d, 0x08, 0x82, 0x3b,  // ^
                     0xd8, 0xa8, 0xea, 0xb5, 0x10,  // | SHA-1 of the zero
                     0xad, 0x6a, 0xc7, 0x5c, 0x82,  // | object pack header
                     0x3c, 0xfd, 0x3e, 0xd3, 0x1e]) // v
            .cloned().collect::<Vec<u8>>();
        assert_eq!(&*buf, &*expected);
    }

    #[test]
    fn insert_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        let (commit, _tree) = commit(&repo);
        t!(builder.insert_object(commit, None));
        assert_eq!(builder.object_count(), 1);
        t!(builder.write_buf(&mut buf, None));
        // Just check that the correct number of objects are written
        assert_eq!(&buf[0..12], &*pack_header(1));
    }

    #[test]
    fn insert_tree_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        let (_commit, tree) = commit(&repo);
        // will insert the tree itself and the blob, 2 objects
        t!(builder.insert_tree(tree));
        assert_eq!(builder.object_count(), 2);
        t!(builder.write_buf(&mut buf, None));
        // Just check that the correct number of objects are written
        assert_eq!(&buf[0..12], &*pack_header(2));
    }

    #[test]
    fn insert_commit_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        let (commit, _tree) = commit(&repo);
        // will insert the commit, its tree and the blob, 3 objects
        t!(builder.insert_commit(commit));
        assert_eq!(builder.object_count(), 3);
        t!(builder.write_buf(&mut buf, None));
        // Just check that the correct number of objects are written
        assert_eq!(&buf[0..12], &*pack_header(3));
    }

    #[test]
    fn progress_callback() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let (commit, _tree) = commit(&repo);
        t!(builder.insert_commit(commit));
        let mut progress_called = false;
        t!(builder.write_buf(&mut Buf::new(),
                             Some(&mut |_, _, _| {
                                 progress_called = true;
                                 true
                             })));
        assert_eq!(progress_called, true);
    }
}
<commit_msg>Use separate method to attach progress callback<commit_after>use std::marker;
use std::ptr;
use std::slice;
use libc::{c_int, c_uint, c_void, size_t};

use {raw, panic, Repository, Error, Oid, Revwalk, Buf};
use util::Binding;

/// Stages that are reported by the PackBuilder progress callback.
pub enum PackBuilderStage {
    /// Adding objects to the pack
    AddingObjects,
    /// Deltafication of the pack
    Deltafication,
}

pub type ProgressCb<'a> = FnMut(PackBuilderStage, u32, u32) -> bool + 'a;
pub type ForEachCb<'a> = FnMut(&[u8]) -> bool + 'a;

/// A builder for creating a packfile
pub struct PackBuilder<'repo> {
    raw: *mut raw::git_packbuilder,
    progress: Option<Box<Box<ProgressCb<'repo>>>>,
    _marker: marker::PhantomData<&'repo Repository>,
}

impl<'repo> PackBuilder<'repo> {
    /// Insert a single object. For an optimal pack it's mandatory to insert
    /// objects in recency order, commits followed by trees and blobs.
    pub fn insert_object(&mut self,
                         id: Oid,
                         name: Option<&str>)
                         -> Result<(), Error> {
        let name = try!(::opt_cstr(name));
        unsafe {
            try_call!(raw::git_packbuilder_insert(self.raw, &*id.raw(), name));
        }
        Ok(())
    }

    /// Insert a root tree object. This will add the tree as well as all
    /// referenced trees and blobs.
    pub fn insert_tree(&mut self, id: Oid) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_packbuilder_insert_tree(self.raw, &*id.raw()));
        }
        Ok(())
    }

    /// Insert a commit object. This will add a commit as well as the completed
    /// referenced tree.
    pub fn insert_commit(&mut self, id: Oid) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_packbuilder_insert_commit(self.raw, &*id.raw()));
        }
        Ok(())
    }

    /// Insert objects as given by the walk. Those commits and all objects they
    /// reference will be inserted into the packbuilder.
    pub fn insert_walk(&mut self, walk: &mut Revwalk) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_packbuilder_insert_walk(self.raw, walk.raw()));
        }
        Ok(())
    }

    /// Recursively insert an object and its referenced objects. Insert the
    /// object as well as any object it references.
    pub fn insert_recursive(&mut self,
                            id: Oid,
                            name: Option<&str>)
                            -> Result<(), Error> {
        let name = try!(::opt_cstr(name));
        unsafe {
            try_call!(raw::git_packbuilder_insert_recur(self.raw,
                                                        &*id.raw(),
                                                        name));
        }
        Ok(())
    }

    /// Write the contents of the packfile to an in-memory buffer. The contents
    /// of the buffer will become a valid packfile, even though there will be
    /// no attached index.
    pub fn write_buf(&mut self, buf: &mut Buf) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_packbuilder_write_buf(buf.raw(), self.raw));
        }
        Ok(())
    }

    /// Create the new pack and pass each object to the callback.
    pub fn foreach(&mut self,
                   mut cb: &mut ForEachCb)
                   -> Result<(), Error> {
        let ptr = &mut cb as *mut _;
        unsafe {
            try_call!(raw::git_packbuilder_foreach(self.raw,
                                                   foreach_c,
                                                   ptr as *mut _));
        }
        Ok(())
    }

    /// `progress` will be called with progress information during pack
    /// building. Be aware that this is called inline with pack building
    /// operations, so performance may be affected.
    pub fn set_progress_callback<F>(&mut self, progress: F) -> Result<(), Error>
        where F: FnMut(PackBuilderStage, u32, u32) -> bool + 'repo {
        let ptr = Box::into_raw(Box::new(Box::new(progress) as Box<ProgressCb>));
        let progress_c = Some(progress_c as raw::git_packbuilder_progress);
        unsafe {
            try_call!(raw::git_packbuilder_set_callbacks(self.raw,
                                                         progress_c,
                                                         ptr as *mut _));
            self.progress = Some(Box::from_raw(ptr));
        }
        Ok(())
    }

    /// Get the total number of objects the packbuilder will write out.
    pub fn object_count(&self) -> usize {
        unsafe { raw::git_packbuilder_object_count(self.raw) as usize }
    }

    /// Get the number of objects the packbuilder has already written out.
    pub fn written(&self) -> usize {
        unsafe { raw::git_packbuilder_written(self.raw) as usize }
    }

    /// Get the packfile's hash. A packfile's name is derived from the sorted
    /// hashing of all object names. This is only correct after the packfile
    /// has been written.
    pub fn hash(&self) -> Option<Oid> {
        if self.object_count() == 0 {
            unsafe {
                Some(Binding::from_raw(raw::git_packbuilder_hash(self.raw)))
            }
        } else {
            None
        }
    }
}

impl<'repo> Binding for PackBuilder<'repo> {
    type Raw = *mut raw::git_packbuilder;
    unsafe fn from_raw(ptr: *mut raw::git_packbuilder) -> PackBuilder<'repo> {
        PackBuilder {
            raw: ptr,
            progress: None,
            _marker: marker::PhantomData,
        }
    }
    fn raw(&self) -> *mut raw::git_packbuilder {
        self.raw
    }
}

impl<'repo> Drop for PackBuilder<'repo> {
    fn drop(&mut self) {
        unsafe {
            raw::git_packbuilder_set_callbacks(self.raw, None, ptr::null_mut());
            raw::git_packbuilder_free(self.raw);
        }
    }
}

impl Binding for PackBuilderStage {
    type Raw = raw::git_packbuilder_stage_t;
    unsafe fn from_raw(raw: raw::git_packbuilder_stage_t) -> PackBuilderStage {
        match raw {
            raw::GIT_PACKBUILDER_ADDING_OBJECTS => PackBuilderStage::AddingObjects,
            raw::GIT_PACKBUILDER_DELTAFICATION => PackBuilderStage::Deltafication,
            _ => panic!("Unknown git diff binary kind"),
        }
    }
    fn raw(&self) -> raw::git_packbuilder_stage_t {
        match *self {
            PackBuilderStage::AddingObjects => raw::GIT_PACKBUILDER_ADDING_OBJECTS,
            PackBuilderStage::Deltafication => raw::GIT_PACKBUILDER_DELTAFICATION,
        }
    }
}

extern "C" fn foreach_c(buf: *const c_void,
                        size: size_t,
                        data: *mut c_void)
                        -> c_int {
    unsafe {
        let buf = slice::from_raw_parts(buf as *const u8, size as usize);

        let r = panic::wrap(|| {
            let data = data as *mut &mut ForEachCb;
            (*data)(buf)
        });
        if r == Some(true) {
            0
        } else {
            -1
        }
    }
}

extern "C" fn progress_c(stage: raw::git_packbuilder_stage_t,
                         current: c_uint,
                         total: c_uint,
                         data: *mut c_void)
                         -> c_int {
    unsafe {
        let stage = Binding::from_raw(stage);

        let r = panic::wrap(|| {
            let data = data as *mut Box<ProgressCb>;
            (*data)(stage, current, total)
        });
        if r == Some(true) {
            0
        } else {
            -1
        }
    }
}

#[cfg(test)]
mod tests {
    use std::fs::File;
    use std::path::Path;
    use {Buf, Repository, Oid};

    fn commit(repo: &Repository) -> (Oid, Oid) {
        let mut index = t!(repo.index());
        let root = repo.path().parent().unwrap();
        t!(File::create(&root.join("foo")));
        t!(index.add_path(Path::new("foo")));

        let tree_id = t!(index.write_tree());
        let tree = t!(repo.find_tree(tree_id));
        let sig = t!(repo.signature());
        let head_id = t!(repo.refname_to_id("HEAD"));
        let parent = t!(repo.find_commit(head_id));
        let commit = t!(repo.commit(Some("HEAD"),
                                    &sig,
                                    &sig,
                                    "commit",
                                    &tree,
                                    &[&parent]));
        (commit, tree_id)
    }

    fn pack_header(len: u8) -> Vec<u8> {
        [].into_iter()
          .chain(b"PACK") // signature
          .chain(&[0, 0, 0, 2]) // version number
          .chain(&[0, 0, 0, len]) // number of objects
          .cloned().collect::<Vec<u8>>()
    }

    #[test]
    fn smoke() {
        let (_td, repo) = ::test::repo_init();
        let _builder = t!(repo.packbuilder());
    }

    #[test]
    fn smoke_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        t!(builder.write_buf(&mut buf));
        assert!(builder.hash().unwrap().is_zero());
        let expected = pack_header(0).iter()
            .chain(&[0x02, 0x9d, 0x08, 0x82, 0x3b,  // ^
                     0xd8, 0xa8, 0xea, 0xb5, 0x10,  // | SHA-1 of the zero
                     0xad, 0x6a, 0xc7, 0x5c, 0x82,  // | object pack header
                     0x3c, 0xfd, 0x3e, 0xd3, 0x1e]) // v
            .cloned().collect::<Vec<u8>>();
        assert_eq!(&*buf, &*expected);
    }

    #[test]
    fn insert_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        let (commit, _tree) = commit(&repo);
        t!(builder.insert_object(commit, None));
        assert_eq!(builder.object_count(), 1);
        t!(builder.write_buf(&mut buf));
        // Just check that the correct number of objects are written
        assert_eq!(&buf[0..12], &*pack_header(1));
    }

    #[test]
    fn insert_tree_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        let (_commit, tree) = commit(&repo);
        // will insert the tree itself and the blob, 2 objects
        t!(builder.insert_tree(tree));
        assert_eq!(builder.object_count(), 2);
        t!(builder.write_buf(&mut buf));
        // Just check that the correct number of objects are written
        assert_eq!(&buf[0..12], &*pack_header(2));
    }

    #[test]
    fn insert_commit_write_buf() {
        let (_td, repo) = ::test::repo_init();
        let mut builder = t!(repo.packbuilder());
        let mut buf = Buf::new();
        let (commit, _tree) = commit(&repo);
        // will insert the commit, its tree and the blob, 3 objects
        t!(builder.insert_commit(commit));
        assert_eq!(builder.object_count(), 3);
        t!(builder.write_buf(&mut buf));
        // Just check that the correct number of objects are written
        assert_eq!(&buf[0..12], &*pack_header(3));
    }

    #[test]
    fn progress_callback() {
        let mut progress_called = false;
        {
            let (_td, repo) = ::test::repo_init();
            let mut builder = t!(repo.packbuilder());
            let (commit, _tree) = commit(&repo);
            t!(builder.set_progress_callback(|_, _, _| {
                progress_called = true;
                true
            }));
            t!(builder.insert_commit(commit));
            t!(builder.write_buf(&mut Buf::new()));
        }
        assert_eq!(progress_called, true);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::collections::HashMap;
use std::result::Result;
use handle_table::{Handle};
use {EventLoop, TaskReaper};

pub mod promise_node;

thread_local!(pub static EVENT_LOOP: RefCell<Option<EventLoop>> = RefCell::new(None));

pub fn with_current_event_loop<F, R>(f: F) -> R
    where F: FnOnce(&EventLoop) -> R
{
    EVENT_LOOP.with(|maybe_event_loop| {
        match *maybe_event_loop.borrow() {
            None => panic!("current thread has no event loop"),
            Some(ref event_loop) => f(event_loop),
        }
    })
}

pub trait PromiseNode<T, E> {
    /// Arms the given event when the promised value is ready.
    fn on_ready(&mut self, event: EventHandle);

    /// Tells the node that `_self_ptr` is the pointer that owns this node, and will continue to own
    /// this node until it is destroyed or set_self_pointer() is called again. promise_node::Chain uses
    /// this to shorten redundant chains.  The default implementation does nothing; only
    /// promise_node::Chain should implement this.
    fn set_self_pointer(&mut self, _self_ptr: Weak<RefCell<promise_node::ChainState<T, E>>>) {}
    fn get(self: Box<Self>) -> Result<T, E>;
}

pub trait Event {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>>;
}

#[derive(PartialEq, Eq, Copy, Clone, Hash)]
pub struct EventHandle(pub Handle);

impl EventHandle {
    pub fn new() -> (EventHandle, EventDropper) {
        with_current_event_loop(|event_loop| {
            let node = EventNode { event: None, next: None, prev: None };
            let handle = EventHandle(event_loop.events.borrow_mut().push(node));
            (handle, EventDropper { event_handle: handle })
        })
    }

    pub fn set(&self, event: Box<Event>) {
        with_current_event_loop(|event_loop| {
            event_loop.events.borrow_mut()[self.0].event = Some(event);
        })
    }

    pub fn arm_breadth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_breadth_first(self);
        });
    }

    pub fn arm_depth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_depth_first(self);
        });
    }
}

pub struct EventNode {
    pub event: Option<Box<Event>>,
    pub next: Option<EventHandle>,
    pub prev: Option<EventHandle>
}

#[derive(PartialEq, Eq, Hash)]
pub struct EventDropper {
    event_handle: EventHandle,
}

impl Drop for EventDropper {
    fn drop(&mut self) {
        with_current_event_loop(|event_loop| {
            match event_loop.currently_firing.get() {
                Some(h) if h == self.event_handle => {
                    event_loop.to_destroy.set(Some(self.event_handle));
                    return;
                }
                _ => (),
            }
            let maybe_event_node = event_loop.events.borrow_mut().remove(self.event_handle.0);

            if let Some(event_node) = maybe_event_node {
                // event_node.next.prev = event_node.prev
                match event_node.next {
                    Some(e) => {
                        event_loop.events.borrow_mut()[e.0].prev = event_node.prev;
                    }
                    None => {}
                }
                // event_node.prev.next = event_node.next
                match event_node.prev {
                    Some(e) => {
                        event_loop.events.borrow_mut()[e.0].next = event_node.next;
                    }
                    None => {}
                }

                let insertion_point = event_loop.depth_first_insertion_point.get();
                if insertion_point.0 == self.event_handle.0 {
                    event_loop.depth_first_insertion_point.set(event_node.prev.unwrap());
                }

                let tail = event_loop.tail.get();
                if tail.0 == self.event_handle.0 {
                    event_loop.tail.set(event_node.prev.unwrap());
                }
            }
        });
    }
}

pub trait OpaqueEventDropper {}

impl <T, E> OpaqueEventDropper for Box<PromiseNode<T, E>> {}

impl OpaqueEventDropper for EventDropper {}

pub struct BoolEvent {
    fired: ::std::rc::Rc<::std::cell::Cell<bool>>,
}

impl BoolEvent {
    pub fn new(fired: ::std::rc::Rc<::std::cell::Cell<bool>>) -> BoolEvent {
        BoolEvent { fired: fired }
    }
}

impl Event for BoolEvent {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        self.fired.set(true);
        None
    }
}

pub enum OnReadyEvent {
    Empty,
    AlreadyReady,
    Full(EventHandle),
}

impl OnReadyEvent {
    fn is_already_ready(&self) -> bool {
        match self {
            &OnReadyEvent::AlreadyReady => true,
            _ => false,
        }
    }

    fn is_empty(&self) -> bool {
        match self {
            &OnReadyEvent::Empty => true,
            _ => false,
        }
    }

    fn init(&mut self, new_event: EventHandle) {
        if self.is_already_ready() {
            new_event.arm_breadth_first();
        } else {
            *self = OnReadyEvent::Full(new_event);
        }
    }

    fn arm(&mut self) {
        if self.is_empty() {
            *self = OnReadyEvent::AlreadyReady;
        } else {
            let old_self = ::std::mem::replace(self, OnReadyEvent::Empty);
            match old_self {
                OnReadyEvent::Full(event) => {
                    event.arm_depth_first();
                }
                _ => {
                    panic!("armed an event twice?");
                }
            }
        }
    }
}

pub struct PromiseAndFulfillerHub<T, E> where T: 'static, E: 'static {
    result: Option<Result<T, E>>,
    on_ready_event: OnReadyEvent,
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn new() -> PromiseAndFulfillerHub<T, E> {
        PromiseAndFulfillerHub { result: None::<Result<T, E>>, on_ready_event: OnReadyEvent::Empty }
    }
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn fulfill(&mut self, value: T) {
        if self.result.is_none() {
            self.result = Some(Ok(value));
            self.on_ready_event.arm();
        }
    }

    pub fn reject(&mut self, error: E) {
        if self.result.is_none() {
            self.result = Some(Err(error));
            self.on_ready_event.arm();
        }
    }
}

pub struct PromiseAndFulfillerWrapper<T, E> where T: 'static, E: 'static {
    hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>
}

impl <T, E> PromiseAndFulfillerWrapper<T, E> {
    pub fn new(hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>)
               -> PromiseAndFulfillerWrapper<T, E>
    {
        PromiseAndFulfillerWrapper { hub: hub }
    }
}

impl <T, E> Drop for PromiseAndFulfillerWrapper<T, E> {
    fn drop(&mut self) {
        self.hub.borrow_mut().on_ready_event = OnReadyEvent::Empty;
    }
}

impl <T, E> PromiseNode<T, E> for PromiseAndFulfillerWrapper<T, E> {
    fn on_ready(&mut self, event: EventHandle) {
        self.hub.borrow_mut().on_ready_event.init(event);
    }
    fn get(self: Box<Self>) -> Result<T, E> {
        match ::std::mem::replace(&mut self.hub.borrow_mut().result, None) {
            None => panic!("no result!"),
            Some(r) => r
        }
    }
}

pub struct TaskSetImpl<T, E> where T: 'static, E: 'static {
    reaper: Rc<RefCell<Box<TaskReaper<T, E>>>>,
    tasks: Rc<RefCell<HashMap<EventHandle, EventDropper>>>,
}

impl <T, E> TaskSetImpl <T, E> {
    pub fn new(reaper: Box<TaskReaper<T, E>>) -> TaskSetImpl<T, E> {
        TaskSetImpl {
            reaper: Rc::new(RefCell::new(reaper)),
            tasks: Rc::new(RefCell::new(HashMap::new())),
        }
    }

      pub fn add(&self, mut node: Box<PromiseNode<T, E>>) {
          let (handle, dropper) = EventHandle::new();
          node.on_ready(handle);
          let task = Task {
              weak_reaper: Rc::downgrade(&self.reaper),
              weak_tasks: Rc::downgrade(&self.tasks),
              node: Some(node),
              event_handle: handle
          };
          handle.set(Box::new(task));
          self.tasks.borrow_mut().insert(handle, dropper);
    }
}

pub struct Task<T, E> where T: 'static, E: 'static {
    weak_reaper: Weak<RefCell<Box<TaskReaper<T, E>>>>,
    weak_tasks: Weak<RefCell<HashMap<EventHandle, EventDropper>>>,
    node: Option<Box<PromiseNode<T, E>>>,
    event_handle: EventHandle,
}

impl <T, E> Event for Task<T, E> {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        let maybe_node = ::std::mem::replace(&mut self.node, None);
        match maybe_node {
            None => {
                unreachable!()
            }
            Some(node) => {
                match self.weak_reaper.upgrade() {
                    None => (),
                    Some(reaper) => {
                        match node.get() {
                            Ok(v) => {
                                reaper.borrow_mut().task_succeeded(v);
                            }
                            Err(e) => {
                                reaper.borrow_mut().task_failed(e);
                            }
                        }
                    }
                }
            }
        }
        let tasks = self.weak_tasks.upgrade().expect("dangling reference to tasks?");
        let mut tmp = tasks.borrow_mut();
        match tmp.remove(&self.event_handle) {
            None => None,
            Some(v) => Some(Box::new(v)),
        }
    }
}
<commit_msg>more 'if let'<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::collections::HashMap;
use std::result::Result;
use handle_table::{Handle};
use {EventLoop, TaskReaper};

pub mod promise_node;

thread_local!(pub static EVENT_LOOP: RefCell<Option<EventLoop>> = RefCell::new(None));

pub fn with_current_event_loop<F, R>(f: F) -> R
    where F: FnOnce(&EventLoop) -> R
{
    EVENT_LOOP.with(|maybe_event_loop| {
        match *maybe_event_loop.borrow() {
            None => panic!("current thread has no event loop"),
            Some(ref event_loop) => f(event_loop),
        }
    })
}

pub trait PromiseNode<T, E> {
    /// Arms the given event when the promised value is ready.
    fn on_ready(&mut self, event: EventHandle);

    /// Tells the node that `_self_ptr` is the pointer that owns this node, and will continue to own
    /// this node until it is destroyed or set_self_pointer() is called again. promise_node::Chain uses
    /// this to shorten redundant chains.  The default implementation does nothing; only
    /// promise_node::Chain should implement this.
    fn set_self_pointer(&mut self, _self_ptr: Weak<RefCell<promise_node::ChainState<T, E>>>) {}
    fn get(self: Box<Self>) -> Result<T, E>;
}

pub trait Event {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>>;
}

#[derive(PartialEq, Eq, Copy, Clone, Hash)]
pub struct EventHandle(pub Handle);

impl EventHandle {
    pub fn new() -> (EventHandle, EventDropper) {
        with_current_event_loop(|event_loop| {
            let node = EventNode { event: None, next: None, prev: None };
            let handle = EventHandle(event_loop.events.borrow_mut().push(node));
            (handle, EventDropper { event_handle: handle })
        })
    }

    pub fn set(&self, event: Box<Event>) {
        with_current_event_loop(|event_loop| {
            event_loop.events.borrow_mut()[self.0].event = Some(event);
        })
    }

    pub fn arm_breadth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_breadth_first(self);
        });
    }

    pub fn arm_depth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_depth_first(self);
        });
    }
}

pub struct EventNode {
    pub event: Option<Box<Event>>,
    pub next: Option<EventHandle>,
    pub prev: Option<EventHandle>
}

#[derive(PartialEq, Eq, Hash)]
pub struct EventDropper {
    event_handle: EventHandle,
}

impl Drop for EventDropper {
    fn drop(&mut self) {
        with_current_event_loop(|event_loop| {
            match event_loop.currently_firing.get() {
                Some(h) if h == self.event_handle => {
                    event_loop.to_destroy.set(Some(self.event_handle));
                    return;
                }
                _ => (),
            }
            let maybe_event_node = event_loop.events.borrow_mut().remove(self.event_handle.0);

            if let Some(event_node) = maybe_event_node {
                // event_node.next.prev = event_node.prev
                if let Some(e) = event_node.next {
                    event_loop.events.borrow_mut()[e.0].prev = event_node.prev;
                }
                // event_node.prev.next = event_node.next
                if let Some(e) = event_node.prev {
                    event_loop.events.borrow_mut()[e.0].next = event_node.next;
                }

                let insertion_point = event_loop.depth_first_insertion_point.get();
                if insertion_point.0 == self.event_handle.0 {
                    event_loop.depth_first_insertion_point.set(event_node.prev.unwrap());
                }

                let tail = event_loop.tail.get();
                if tail.0 == self.event_handle.0 {
                    event_loop.tail.set(event_node.prev.unwrap());
                }
            }
        });
    }
}

pub trait OpaqueEventDropper {}

impl <T, E> OpaqueEventDropper for Box<PromiseNode<T, E>> {}

impl OpaqueEventDropper for EventDropper {}

pub struct BoolEvent {
    fired: ::std::rc::Rc<::std::cell::Cell<bool>>,
}

impl BoolEvent {
    pub fn new(fired: ::std::rc::Rc<::std::cell::Cell<bool>>) -> BoolEvent {
        BoolEvent { fired: fired }
    }
}

impl Event for BoolEvent {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        self.fired.set(true);
        None
    }
}

pub enum OnReadyEvent {
    Empty,
    AlreadyReady,
    Full(EventHandle),
}

impl OnReadyEvent {
    fn is_already_ready(&self) -> bool {
        match self {
            &OnReadyEvent::AlreadyReady => true,
            _ => false,
        }
    }

    fn is_empty(&self) -> bool {
        match self {
            &OnReadyEvent::Empty => true,
            _ => false,
        }
    }

    fn init(&mut self, new_event: EventHandle) {
        if self.is_already_ready() {
            new_event.arm_breadth_first();
        } else {
            *self = OnReadyEvent::Full(new_event);
        }
    }

    fn arm(&mut self) {
        if self.is_empty() {
            *self = OnReadyEvent::AlreadyReady;
        } else {
            let old_self = ::std::mem::replace(self, OnReadyEvent::Empty);
            match old_self {
                OnReadyEvent::Full(event) => {
                    event.arm_depth_first();
                }
                _ => {
                    panic!("armed an event twice?");
                }
            }
        }
    }
}

pub struct PromiseAndFulfillerHub<T, E> where T: 'static, E: 'static {
    result: Option<Result<T, E>>,
    on_ready_event: OnReadyEvent,
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn new() -> PromiseAndFulfillerHub<T, E> {
        PromiseAndFulfillerHub { result: None::<Result<T, E>>, on_ready_event: OnReadyEvent::Empty }
    }
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn fulfill(&mut self, value: T) {
        if self.result.is_none() {
            self.result = Some(Ok(value));
            self.on_ready_event.arm();
        }
    }

    pub fn reject(&mut self, error: E) {
        if self.result.is_none() {
            self.result = Some(Err(error));
            self.on_ready_event.arm();
        }
    }
}

pub struct PromiseAndFulfillerWrapper<T, E> where T: 'static, E: 'static {
    hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>
}

impl <T, E> PromiseAndFulfillerWrapper<T, E> {
    pub fn new(hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>)
               -> PromiseAndFulfillerWrapper<T, E>
    {
        PromiseAndFulfillerWrapper { hub: hub }
    }
}

impl <T, E> Drop for PromiseAndFulfillerWrapper<T, E> {
    fn drop(&mut self) {
        self.hub.borrow_mut().on_ready_event = OnReadyEvent::Empty;
    }
}

impl <T, E> PromiseNode<T, E> for PromiseAndFulfillerWrapper<T, E> {
    fn on_ready(&mut self, event: EventHandle) {
        self.hub.borrow_mut().on_ready_event.init(event);
    }
    fn get(self: Box<Self>) -> Result<T, E> {
        match ::std::mem::replace(&mut self.hub.borrow_mut().result, None) {
            None => panic!("no result!"),
            Some(r) => r
        }
    }
}

pub struct TaskSetImpl<T, E> where T: 'static, E: 'static {
    reaper: Rc<RefCell<Box<TaskReaper<T, E>>>>,
    tasks: Rc<RefCell<HashMap<EventHandle, EventDropper>>>,
}

impl <T, E> TaskSetImpl <T, E> {
    pub fn new(reaper: Box<TaskReaper<T, E>>) -> TaskSetImpl<T, E> {
        TaskSetImpl {
            reaper: Rc::new(RefCell::new(reaper)),
            tasks: Rc::new(RefCell::new(HashMap::new())),
        }
    }

      pub fn add(&self, mut node: Box<PromiseNode<T, E>>) {
          let (handle, dropper) = EventHandle::new();
          node.on_ready(handle);
          let task = Task {
              weak_reaper: Rc::downgrade(&self.reaper),
              weak_tasks: Rc::downgrade(&self.tasks),
              node: Some(node),
              event_handle: handle
          };
          handle.set(Box::new(task));
          self.tasks.borrow_mut().insert(handle, dropper);
    }
}

pub struct Task<T, E> where T: 'static, E: 'static {
    weak_reaper: Weak<RefCell<Box<TaskReaper<T, E>>>>,
    weak_tasks: Weak<RefCell<HashMap<EventHandle, EventDropper>>>,
    node: Option<Box<PromiseNode<T, E>>>,
    event_handle: EventHandle,
}

impl <T, E> Event for Task<T, E> {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        let maybe_node = ::std::mem::replace(&mut self.node, None);
        match maybe_node {
            None => {
                unreachable!()
            }
            Some(node) => {
                match self.weak_reaper.upgrade() {
                    None => (),
                    Some(reaper) => {
                        match node.get() {
                            Ok(v) => {
                                reaper.borrow_mut().task_succeeded(v);
                            }
                            Err(e) => {
                                reaper.borrow_mut().task_failed(e);
                            }
                        }
                    }
                }
            }
        }
        let tasks = self.weak_tasks.upgrade().expect("dangling reference to tasks?");
        let mut tmp = tasks.borrow_mut();
        match tmp.remove(&self.event_handle) {
            None => None,
            Some(v) => Some(Box::new(v)),
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "Generate markdown from a document tree"];

import std::io;
import std::io::writer_util;

export mk_pass;

fn mk_pass(
    writer: fn~() -> io::writer
) -> pass {
    ret fn~(
        _srv: astsrv::srv,
        doc: doc::cratedoc
    ) -> doc::cratedoc {
        write_markdown(doc, writer());
        doc
    };
}

type ctxt = {
    w: io::writer
};

fn write_markdown(
    doc: doc::cratedoc,
    writer: io::writer
) {
    let ctxt = {
        w: writer
    };

    write_crate(ctxt, doc);
}

enum hlvl {
    h1 = 1,
    h2 = 2,
    h3 = 3
}

fn write_header(ctxt: ctxt, lvl: hlvl, title: str) {
    let hashes = str::from_chars(vec::init_elt(lvl as uint, '#'));
    ctxt.w.write_line(#fmt("%s %s", hashes, title));
    ctxt.w.write_line("");
}

fn write_crate(
    ctxt: ctxt,
    doc: doc::cratedoc
) {
    write_header(ctxt, h1, #fmt("Crate %s", doc.topmod.name));
    write_top_module(ctxt, doc.topmod);
}

fn write_top_module(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_mod_contents(ctxt, moddoc);
}

fn write_mod(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    let fullpath = str::connect(moddoc.path + [moddoc.name], "::");
    write_header(ctxt, h2, #fmt("Module `%s`", fullpath));
    write_mod_contents(ctxt, moddoc);
}

#[test]
fn should_write_full_path_to_mod() {
    let markdown = test::render("mod a { mod b { mod c { } } }");
    assert str::contains(markdown, "## Module `a::b::c`");
}

fn write_mod_contents(
    ctxt: ctxt,
    doc: doc::moddoc
) {
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);

    for constdoc in *doc.consts {
        write_const(ctxt, constdoc);
    }

    for fndoc in *doc.fns {
        write_fn(ctxt, fndoc);
    }

    for moddoc in *doc.mods {
        write_mod(ctxt, moddoc);
    }
}

#[test]
fn should_write_crate_brief_description() {
    let markdown = test::render("#[doc(brief = \"this is the crate\")];");
    assert str::contains(markdown, "this is the crate");
}

#[test]
fn should_write_crate_description() {
    let markdown = test::render("#[doc = \"this is the crate\"];");
    assert str::contains(markdown, "this is the crate");
}

fn write_fn(
    ctxt: ctxt,
    doc: doc::fndoc
) {
    write_header(ctxt, h3, #fmt("Function `%s`", doc.name));
    write_sig(ctxt, doc.sig);
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);
    write_args(ctxt, doc.args);
    write_return(ctxt, doc.return);
}

fn write_sig(ctxt: ctxt, sig: option<str>) {
    alt sig {
      some(sig) {
        ctxt.w.write_line(code_block_indent(sig));
        ctxt.w.write_line("");
      }
      none { fail "unimplemented" }
    }
}

fn code_block_indent(s: str) -> str {
    let lines = str::lines_any(s);
    let indented = vec::map(lines, { |line| #fmt("    %s", line) });
    str::connect(indented, "\n")
}

#[test]
fn should_write_the_function_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "\n    fn a()\n");
}

#[test]
fn should_insert_blank_line_after_fn_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "fn a()\n\n");
}

#[test]
fn should_correctly_indent_fn_signature() {
    let doc = test::create_doc("fn a() { }");
    let doc = ~{
        topmod: ~{
            fns: doc::fnlist([~{
                sig: some("line 1\nline 2")
                with *doc.topmod.fns[0]
            }])
            with *doc.topmod
        }
        with *doc
    };
    let markdown = test::write_markdown_str(doc);
    assert str::contains(markdown, "    line 1\n    line 2");
}

fn write_brief(
    ctxt: ctxt,
    brief: option<str>
) {
    alt brief {
      some(brief) {
        ctxt.w.write_line(brief);
        ctxt.w.write_line("");
      }
      none { }
    }
}

fn write_desc(
    ctxt: ctxt,
    desc: option<str>
) {
    alt desc {
        some(desc) {
            ctxt.w.write_line(desc);
            ctxt.w.write_line("");
        }
        none { }
    }
}

fn write_args(
    ctxt: ctxt,
    args: [doc::argdoc]
) {
    if vec::is_not_empty(args) {
        ctxt.w.write_line("Arguments:");
        ctxt.w.write_line("");
        vec::iter(args) {|arg| write_arg(ctxt, arg) };
        ctxt.w.write_line("");
    }
}

fn write_arg(ctxt: ctxt, arg: doc::argdoc) {
    assert option::is_some(arg.ty);
    ctxt.w.write_str(#fmt(
        "* `%s`: `%s`",
        arg.name,
        option::get(arg.ty)
    ));
    alt arg.desc {
      some(desc) {
        ctxt.w.write_str(#fmt(" - %s", desc));
      }
      none { }
    }
    ctxt.w.write_line("");
}

#[test]
fn should_write_argument_list() {
    let source = "fn a(b: int, c: int) { }";
    let markdown = test::render(source);
    assert str::contains(
        markdown,
        "Arguments:\n\
         \n\
         * `b`: `int`\n\
         * `c`: `int`\n\
         \n"
    );
}

#[test]
fn should_not_write_arguments_if_none() {
    let source = "fn a() { } fn b() { }";
    let markdown = test::render(source);
    assert !str::contains(markdown, "Arguments");
}

#[test]
fn should_write_argument_description() {
    let source = "#[doc(args(a = \"milk\"))] fn f(a: bool) { }";
    let markdown = test::render(source);
    assert str::contains(markdown, "`a`: `bool` - milk");
}

fn write_return(
    ctxt: ctxt,
    doc: doc::retdoc
) {
    alt doc.ty {
      some(ty) {
        ctxt.w.write_str(#fmt("Returns `%s`", ty));
        alt doc.desc {
          some(d) {
            ctxt.w.write_line(#fmt(" - %s", d));
            ctxt.w.write_line("");
          }
          none {
            ctxt.w.write_line("");
            ctxt.w.write_line("");
          }
        }
      }
      none { }
    }
}

#[test]
fn should_write_return_type_on_new_line() {
    let markdown = test::render("fn a() -> int { }");
    assert str::contains(markdown, "\nReturns `int`");
}

#[test]
fn should_write_blank_line_between_return_type_and_next_header() {
    let markdown = test::render(
        "fn a() -> int { } \
         fn b() -> int { }"
    );
    assert str::contains(markdown, "Returns `int`\n\n##");
}

#[test]
fn should_not_write_return_type_when_there_is_none() {
    let markdown = test::render("fn a() { }");
    assert !str::contains(markdown, "Returns");
}

#[test]
fn should_write_blank_line_after_return_description() {
    let markdown = test::render(
        "#[doc(return = \"blorp\")] fn a() -> int { }"
    );
    assert str::contains(markdown, "blorp\n\n");
}

#[test]
fn should_write_return_description_on_same_line_as_type() {
    let markdown = test::render(
        "#[doc(return = \"blorp\")] fn a() -> int { }"
    );
    assert str::contains(markdown, "Returns `int` - blorp");
}

fn write_const(
    ctxt: ctxt,
    doc: doc::constdoc
) {
    write_header(ctxt, h3, #fmt("Const `%s`", doc.name));
    write_sig(ctxt, doc.ty);
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);
}

#[test]
fn should_write_const_header() {
    let markdown = test::render("const a: bool = true;");
    assert str::contains(markdown, "### Const `a`\n\n");
}

#[test]
fn should_write_const_description() {
    let markdown = test::render(
        "#[doc(brief = \"a\", desc = \"b\")]\
         const a: bool = true;");
    assert str::contains(markdown, "\n\na\n\nb\n\n");
}

#[cfg(test)]
mod test {
    fn render(source: str) -> str {
        let doc = create_doc(source);
        let markdown = write_markdown_str(doc);
        #debug("markdown: %s", markdown);
        markdown
    }

    fn create_doc(source: str) -> doc::cratedoc {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        #debug("doc (extract): %?", doc);
        let doc = tystr_pass::mk_pass()(srv, doc);
        #debug("doc (tystr): %?", doc);
        let doc = path_pass::mk_pass()(srv, doc);
        #debug("doc (path): %?", doc);
        let doc = attr_pass::mk_pass()(srv, doc);
        #debug("doc (attr): %?", doc);
        doc
    }

    fn write_markdown_str(
        doc: doc::cratedoc
    ) -> str {
        let buffer = io::mk_mem_buffer();
        let writer = io::mem_buffer_writer(buffer);
        write_markdown(doc, writer);
        ret io::mem_buffer_str(buffer);
    }

    #[test]
    fn write_markdown_should_write_crate_header() {
        let srv = astsrv::mk_srv_from_str("");
        let doc = extract::from_srv(srv, "belch");
        let doc = attr_pass::mk_pass()(srv, doc);
        let markdown = write_markdown_str(doc);
        assert str::contains(markdown, "# Crate belch");
    }

    #[test]
    fn write_markdown_should_write_function_header() {
        let markdown = render("fn func() { }");
        assert str::contains(markdown, "### Function `func`");
    }

    #[test]
    fn write_markdown_should_write_mod_headers() {
        let markdown = render("mod moo { }");
        assert str::contains(markdown, "## Module `moo`");
    }

    #[test]
    fn should_leave_blank_line_after_header() {
        let markdown = render("mod morp { }");
        assert str::contains(markdown, "Module `morp`\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_fn_header_and_sig() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "Function `a`\n\n    fn a()");
    }

    #[test]
    fn should_leave_blank_line_after_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "brief\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_brief_and_desc() {
        let markdown = render(
            "#[doc(brief = \"brief\", desc = \"desc\")] fn a() { }"
        );
        assert str::contains(markdown, "brief\n\ndesc");
    }

}<commit_msg>rustdoc: Generate markdown for failure conditions<commit_after>#[doc = "Generate markdown from a document tree"];

import std::io;
import std::io::writer_util;

export mk_pass;

fn mk_pass(
    writer: fn~() -> io::writer
) -> pass {
    ret fn~(
        _srv: astsrv::srv,
        doc: doc::cratedoc
    ) -> doc::cratedoc {
        write_markdown(doc, writer());
        doc
    };
}

type ctxt = {
    w: io::writer
};

fn write_markdown(
    doc: doc::cratedoc,
    writer: io::writer
) {
    let ctxt = {
        w: writer
    };

    write_crate(ctxt, doc);
}

enum hlvl {
    h1 = 1,
    h2 = 2,
    h3 = 3
}

fn write_header(ctxt: ctxt, lvl: hlvl, title: str) {
    let hashes = str::from_chars(vec::init_elt(lvl as uint, '#'));
    ctxt.w.write_line(#fmt("%s %s", hashes, title));
    ctxt.w.write_line("");
}

fn write_crate(
    ctxt: ctxt,
    doc: doc::cratedoc
) {
    write_header(ctxt, h1, #fmt("Crate %s", doc.topmod.name));
    write_top_module(ctxt, doc.topmod);
}

fn write_top_module(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_mod_contents(ctxt, moddoc);
}

fn write_mod(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    let fullpath = str::connect(moddoc.path + [moddoc.name], "::");
    write_header(ctxt, h2, #fmt("Module `%s`", fullpath));
    write_mod_contents(ctxt, moddoc);
}

#[test]
fn should_write_full_path_to_mod() {
    let markdown = test::render("mod a { mod b { mod c { } } }");
    assert str::contains(markdown, "## Module `a::b::c`");
}

fn write_mod_contents(
    ctxt: ctxt,
    doc: doc::moddoc
) {
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);

    for constdoc in *doc.consts {
        write_const(ctxt, constdoc);
    }

    for fndoc in *doc.fns {
        write_fn(ctxt, fndoc);
    }

    for moddoc in *doc.mods {
        write_mod(ctxt, moddoc);
    }
}

#[test]
fn should_write_crate_brief_description() {
    let markdown = test::render("#[doc(brief = \"this is the crate\")];");
    assert str::contains(markdown, "this is the crate");
}

#[test]
fn should_write_crate_description() {
    let markdown = test::render("#[doc = \"this is the crate\"];");
    assert str::contains(markdown, "this is the crate");
}

fn write_fn(
    ctxt: ctxt,
    doc: doc::fndoc
) {
    write_header(ctxt, h3, #fmt("Function `%s`", doc.name));
    write_sig(ctxt, doc.sig);
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);
    write_args(ctxt, doc.args);
    write_return(ctxt, doc.return);
    write_failure(ctxt, doc.failure);
}

fn write_sig(ctxt: ctxt, sig: option<str>) {
    alt sig {
      some(sig) {
        ctxt.w.write_line(code_block_indent(sig));
        ctxt.w.write_line("");
      }
      none { fail "unimplemented" }
    }
}

fn code_block_indent(s: str) -> str {
    let lines = str::lines_any(s);
    let indented = vec::map(lines, { |line| #fmt("    %s", line) });
    str::connect(indented, "\n")
}

#[test]
fn should_write_the_function_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "\n    fn a()\n");
}

#[test]
fn should_insert_blank_line_after_fn_signature() {
    let markdown = test::render("#[doc = \"f\"] fn a() { }");
    assert str::contains(markdown, "fn a()\n\n");
}

#[test]
fn should_correctly_indent_fn_signature() {
    let doc = test::create_doc("fn a() { }");
    let doc = ~{
        topmod: ~{
            fns: doc::fnlist([~{
                sig: some("line 1\nline 2")
                with *doc.topmod.fns[0]
            }])
            with *doc.topmod
        }
        with *doc
    };
    let markdown = test::write_markdown_str(doc);
    assert str::contains(markdown, "    line 1\n    line 2");
}

fn write_brief(
    ctxt: ctxt,
    brief: option<str>
) {
    alt brief {
      some(brief) {
        ctxt.w.write_line(brief);
        ctxt.w.write_line("");
      }
      none { }
    }
}

fn write_desc(
    ctxt: ctxt,
    desc: option<str>
) {
    alt desc {
        some(desc) {
            ctxt.w.write_line(desc);
            ctxt.w.write_line("");
        }
        none { }
    }
}

fn write_args(
    ctxt: ctxt,
    args: [doc::argdoc]
) {
    if vec::is_not_empty(args) {
        ctxt.w.write_line("Arguments:");
        ctxt.w.write_line("");
        vec::iter(args) {|arg| write_arg(ctxt, arg) };
        ctxt.w.write_line("");
    }
}

fn write_arg(ctxt: ctxt, arg: doc::argdoc) {
    assert option::is_some(arg.ty);
    ctxt.w.write_str(#fmt(
        "* `%s`: `%s`",
        arg.name,
        option::get(arg.ty)
    ));
    alt arg.desc {
      some(desc) {
        ctxt.w.write_str(#fmt(" - %s", desc));
      }
      none { }
    }
    ctxt.w.write_line("");
}

#[test]
fn should_write_argument_list() {
    let source = "fn a(b: int, c: int) { }";
    let markdown = test::render(source);
    assert str::contains(
        markdown,
        "Arguments:\n\
         \n\
         * `b`: `int`\n\
         * `c`: `int`\n\
         \n"
    );
}

#[test]
fn should_not_write_arguments_if_none() {
    let source = "fn a() { } fn b() { }";
    let markdown = test::render(source);
    assert !str::contains(markdown, "Arguments");
}

#[test]
fn should_write_argument_description() {
    let source = "#[doc(args(a = \"milk\"))] fn f(a: bool) { }";
    let markdown = test::render(source);
    assert str::contains(markdown, "`a`: `bool` - milk");
}

fn write_return(
    ctxt: ctxt,
    doc: doc::retdoc
) {
    alt doc.ty {
      some(ty) {
        ctxt.w.write_str(#fmt("Returns `%s`", ty));
        alt doc.desc {
          some(d) {
            ctxt.w.write_line(#fmt(" - %s", d));
            ctxt.w.write_line("");
          }
          none {
            ctxt.w.write_line("");
            ctxt.w.write_line("");
          }
        }
      }
      none { }
    }
}

#[test]
fn should_write_return_type_on_new_line() {
    let markdown = test::render("fn a() -> int { }");
    assert str::contains(markdown, "\nReturns `int`");
}

#[test]
fn should_write_blank_line_between_return_type_and_next_header() {
    let markdown = test::render(
        "fn a() -> int { } \
         fn b() -> int { }"
    );
    assert str::contains(markdown, "Returns `int`\n\n##");
}

#[test]
fn should_not_write_return_type_when_there_is_none() {
    let markdown = test::render("fn a() { }");
    assert !str::contains(markdown, "Returns");
}

#[test]
fn should_write_blank_line_after_return_description() {
    let markdown = test::render(
        "#[doc(return = \"blorp\")] fn a() -> int { }"
    );
    assert str::contains(markdown, "blorp\n\n");
}

#[test]
fn should_write_return_description_on_same_line_as_type() {
    let markdown = test::render(
        "#[doc(return = \"blorp\")] fn a() -> int { }"
    );
    assert str::contains(markdown, "Returns `int` - blorp");
}

fn write_failure(ctxt: ctxt, str: option<str>) {
    alt str {
      some(str) {
        ctxt.w.write_line(#fmt("Failure conditions: %s", str));
        ctxt.w.write_line("");
      }
      none { }
    }
}

#[test]
fn should_write_failure_conditions() {
    let markdown = test::render(
        "#[doc(failure = \"it's the fail\")] fn a () { }");
    assert str::contains(
        markdown,
        "\n\nFailure conditions: it's the fail\n\n");
}

fn write_const(
    ctxt: ctxt,
    doc: doc::constdoc
) {
    write_header(ctxt, h3, #fmt("Const `%s`", doc.name));
    write_sig(ctxt, doc.ty);
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);
}

#[test]
fn should_write_const_header() {
    let markdown = test::render("const a: bool = true;");
    assert str::contains(markdown, "### Const `a`\n\n");
}

#[test]
fn should_write_const_description() {
    let markdown = test::render(
        "#[doc(brief = \"a\", desc = \"b\")]\
         const a: bool = true;");
    assert str::contains(markdown, "\n\na\n\nb\n\n");
}

#[cfg(test)]
mod test {
    fn render(source: str) -> str {
        let doc = create_doc(source);
        let markdown = write_markdown_str(doc);
        #debug("markdown: %s", markdown);
        markdown
    }

    fn create_doc(source: str) -> doc::cratedoc {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        #debug("doc (extract): %?", doc);
        let doc = tystr_pass::mk_pass()(srv, doc);
        #debug("doc (tystr): %?", doc);
        let doc = path_pass::mk_pass()(srv, doc);
        #debug("doc (path): %?", doc);
        let doc = attr_pass::mk_pass()(srv, doc);
        #debug("doc (attr): %?", doc);
        doc
    }

    fn write_markdown_str(
        doc: doc::cratedoc
    ) -> str {
        let buffer = io::mk_mem_buffer();
        let writer = io::mem_buffer_writer(buffer);
        write_markdown(doc, writer);
        ret io::mem_buffer_str(buffer);
    }

    #[test]
    fn write_markdown_should_write_crate_header() {
        let srv = astsrv::mk_srv_from_str("");
        let doc = extract::from_srv(srv, "belch");
        let doc = attr_pass::mk_pass()(srv, doc);
        let markdown = write_markdown_str(doc);
        assert str::contains(markdown, "# Crate belch");
    }

    #[test]
    fn write_markdown_should_write_function_header() {
        let markdown = render("fn func() { }");
        assert str::contains(markdown, "### Function `func`");
    }

    #[test]
    fn write_markdown_should_write_mod_headers() {
        let markdown = render("mod moo { }");
        assert str::contains(markdown, "## Module `moo`");
    }

    #[test]
    fn should_leave_blank_line_after_header() {
        let markdown = render("mod morp { }");
        assert str::contains(markdown, "Module `morp`\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_fn_header_and_sig() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "Function `a`\n\n    fn a()");
    }

    #[test]
    fn should_leave_blank_line_after_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "brief\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_brief_and_desc() {
        let markdown = render(
            "#[doc(brief = \"brief\", desc = \"desc\")] fn a() { }"
        );
        assert str::contains(markdown, "brief\n\ndesc");
    }

}<|endoftext|>


<commit_before>use std::num::{ Float, FloatMath, from_f64 };
use std::mem::size_of;

use music;
use reader;
use wave;

pub fn quantize<T>(input: f64) -> T where T: FromPrimitive {
    let quantization_levels = 2.0.powf(size_of::<T>() as f64 * 8.0) - 1.0;
    // Convert from [-1, 1] to take up full quantization range
    from_f64::<T>(input * (quantization_levels / 2.0)).expect("failed to quantize to given type")
}

pub fn quantize_samples<T>(input: Vec<f64>) -> Vec<T> where T: FromPrimitive {
    input.iter().map(|s| { quantize::<T>(*s) }).collect()
}

pub fn generate<F>(x: f64, f: F) -> f64 where F: Fn<(f64, ), f64> {
    f(x)
}

pub fn make_samples<F>(length: f64, sample_rate: uint, waveform: F) -> Vec<f64> where F: Fn<(f64, ), f64>+Copy {
    let num_samples = (sample_rate as f64 * length).floor() as uint;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in range(0u, num_samples) {
        let t = i as f64 / sample_rate as f64;
        samples.push(generate(t, waveform));
    }

    samples
}

pub fn normalize(samples: Vec<f64>) -> Vec<f64> {
    let peak = samples.iter().fold(0.0f64, |acc, sample| {
        acc.max(*sample)
    });

    samples.iter().map(|sample| {
        *sample / peak
    }).collect()
}

// This is really awful, is there a more elegant way to do this?
// TODO: Split out volume normalization into a function
pub fn make_samples_from_midi(sample_rate: uint, bpm: f64, filename: &str) -> Vec<f64> {
    let song = reader::read_midi(filename).unwrap();
    let length = (60.0 * song.max_time as f64) / (bpm * song.time_unit as f64);

    let mut notes_on_for_ticks: Vec<Vec<(u8, u8)>> = Vec::new();
    for _ in range(0, song.max_time) {
        let notes_on_for_tick: Vec<(u8, u8)> = Vec::new();
        notes_on_for_ticks.push(notes_on_for_tick);
    }

    for track in song.tracks.iter() {
        for i in range(0, track.messages.len()) {
            let event = track.messages[i];
            if event.message_type == 9 {
                let from_tick = event.time;
                let note = event.value1;
                let velocity = event.value2.unwrap();

                let mut to_tick = song.max_time;
                for j in range(i, track.messages.len()) {
                    let event_to = track.messages[j];
                    if event_to.message_type == 8 && event_to.value1 == note {
                        to_tick = event_to.time;
                        break;
                    }
                }

                for tick in range(from_tick, to_tick) {
                    notes_on_for_ticks[tick].push((note, velocity));
                }
            }
        }
    }

    let midi_frequency_function = |t: f64| -> f64 {
        let tick = (t * bpm * song.time_unit as f64 / 60.0) as uint;
        let mut out = 0.0;

        if tick < notes_on_for_ticks.len() {
            for tup in notes_on_for_ticks[tick].iter() {
                let note = tup.val0();
                let velocity = tup.val1();
                let frequency = music::note_midi(440.0, note as uint);
                let loudness = (6.908 * (velocity as f64 / 255.0)).exp() / 1000.0;
                out += loudness * (wave::SquareWave(frequency)(t) + wave::SquareWave(frequency)(t)) / 2.0
            }
        }

        out
    };

    let num_samples = (sample_rate as f64 * length).floor() as uint;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in range(0u, num_samples) {
        let t = i as f64 / sample_rate as f64;
        samples.push(midi_frequency_function(t));
    }

    normalize(samples)
}
<commit_msg>Treat a velocity 0 NoteOn as a NoteOff<commit_after>use std::num::{ Float, FloatMath, from_f64 };
use std::mem::size_of;

use music;
use reader;
use wave;

pub fn quantize<T>(input: f64) -> T where T: FromPrimitive {
    let quantization_levels = 2.0.powf(size_of::<T>() as f64 * 8.0) - 1.0;
    // Convert from [-1, 1] to take up full quantization range
    from_f64::<T>(input * (quantization_levels / 2.0)).expect("failed to quantize to given type")
}

pub fn quantize_samples<T>(input: Vec<f64>) -> Vec<T> where T: FromPrimitive {
    input.iter().map(|s| { quantize::<T>(*s) }).collect()
}

pub fn generate<F>(x: f64, f: F) -> f64 where F: Fn<(f64, ), f64> {
    f(x)
}

pub fn make_samples<F>(length: f64, sample_rate: uint, waveform: F) -> Vec<f64> where F: Fn<(f64, ), f64>+Copy {
    let num_samples = (sample_rate as f64 * length).floor() as uint;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in range(0u, num_samples) {
        let t = i as f64 / sample_rate as f64;
        samples.push(generate(t, waveform));
    }

    samples
}

pub fn normalize(samples: Vec<f64>) -> Vec<f64> {
    let peak = samples.iter().fold(0.0f64, |acc, sample| {
        acc.max(*sample)
    });

    samples.iter().map(|sample| {
        *sample / peak
    }).collect()
}

// This is really awful, is there a more elegant way to do this?
// TODO: Split out volume normalization into a function
pub fn make_samples_from_midi(sample_rate: uint, bpm: f64, filename: &str) -> Vec<f64> {
    let song = reader::read_midi(filename).unwrap();
    let length = (60.0 * song.max_time as f64) / (bpm * song.time_unit as f64);

    let mut notes_on_for_ticks: Vec<Vec<(u8, u8)>> = Vec::new();
    for _ in range(0, song.max_time) {
        let notes_on_for_tick: Vec<(u8, u8)> = Vec::new();
        notes_on_for_ticks.push(notes_on_for_tick);
    }

    for track in song.tracks.iter() {
        for i in range(0, track.messages.len()) {
            let event = track.messages[i];
            if event.message_type == 9 {
                let start_tick = event.time;
                let note = event.value1;
                let velocity = event.value2.unwrap();

                let mut end_tick = song.max_time;
                for j in range(i, track.messages.len()) {
                    let event_cursor = track.messages[j];

                    // NoteOn with velocity 0 == NoteOff
                    if (event_cursor.message_type == 8 && event_cursor.value1 == note) ||
                       (event_cursor.message_type == 9 && event_cursor.value1 == note && event_cursor.value2.unwrap() == 0) {
                        end_tick = event_cursor.time;
                        break;
                    }
                }

                for tick in range(start_tick, end_tick) {
                    notes_on_for_ticks[tick].push((note, velocity));
                }
            }
        }
    }

    let midi_frequency_function = |t: f64| -> f64 {
        let tick = (t * bpm * song.time_unit as f64 / 60.0) as uint;
        let mut out = 0.0;

        if tick < notes_on_for_ticks.len() {
            for tup in notes_on_for_ticks[tick].iter() {
                let note = tup.val0();
                let velocity = tup.val1();
                let frequency = music::note_midi(440.0, note as uint);
                let loudness = (6.908 * (velocity as f64 / 255.0)).exp() / 1000.0;
                out += loudness * wave::SquareWave(frequency)(t)
            }
        }

        out
    };

    let num_samples = (sample_rate as f64 * length).floor() as uint;
    let mut samples: Vec<f64> = Vec::with_capacity(num_samples);

    for i in range(0u, num_samples) {
        let t = i as f64 / sample_rate as f64;
        samples.push(midi_frequency_function(t));
    }

    normalize(samples)
}
<|endoftext|>