<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BlobBinding;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::codegen::UnionTypes::BlobOrString;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use encoding::all::UTF_8;
use encoding::types::{EncoderTrap, Encoding};
use ipc_channel::ipc;
use net_traits::blob_url_store::{BlobBuf, get_blob_origin};
use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos, ReadFileProgress};
use net_traits::{CoreResourceMsg, IpcSend};
use std::cell::Cell;
use std::mem;
use std::ops::Index;
use std::path::PathBuf;
use uuid::Uuid;

/// File-based blob
#[derive(JSTraceable)]
pub struct FileBlob {
    id: SelectedFileId,
    name: Option<PathBuf>,
    cache: DOMRefCell<Option<Vec<u8>>>,
    size: u64,
}

/// Blob backend implementation
#[must_root]
#[derive(JSTraceable)]
pub enum BlobImpl {
    /// File-based blob
    File(FileBlob),
    /// Memory-based blob
    Memory(Vec<u8>),
    /// Sliced blob, including parent blob and
    /// relative positions representing current slicing range,
    /// it is leaf of a two-layer fat tree
    Sliced(JS<Blob>, RelativePos),
}

impl BlobImpl {
    /// Construct memory-backed BlobImpl
    #[allow(unrooted_must_root)]
    pub fn new_from_bytes(bytes: Vec<u8>) -> BlobImpl {
        BlobImpl::Memory(bytes)
    }

    /// Construct file-backed BlobImpl from File ID
    pub fn new_from_file(file_id: SelectedFileId, name: PathBuf, size: u64) -> BlobImpl {
        BlobImpl::File(FileBlob {
            id: file_id,
            name: Some(name),
            cache: DOMRefCell::new(None),
            size: size,
        })
    }
}

// https://w3c.github.io/FileAPI/#blob
#[dom_struct]
pub struct Blob {
    reflector_: Reflector,
    #[ignore_heap_size_of = "No clear owner"]
    blob_impl: DOMRefCell<BlobImpl>,
    typeString: String,
    isClosed_: Cell<bool>,
}

impl Blob {
    #[allow(unrooted_must_root)]
    pub fn new(global: GlobalRef, blob_impl: BlobImpl, typeString: String) -> Root<Blob> {
        let boxed_blob = box Blob::new_inherited(blob_impl, typeString);
        reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
    }

    #[allow(unrooted_must_root)]
    pub fn new_inherited(blob_impl: BlobImpl, typeString: String) -> Blob {
        Blob {
            reflector_: Reflector::new(),
            blob_impl: DOMRefCell::new(blob_impl),
            // NOTE: Guarding the format correctness here,
            // https://w3c.github.io/FileAPI/#dfn-type
            typeString: normalize_type_string(&typeString),
            isClosed_: Cell::new(false),
        }
    }

    #[allow(unrooted_must_root)]
    fn new_sliced(parent: &Blob, rel_pos: RelativePos,
                  relativeContentType: DOMString) -> Root<Blob> {
        let global = parent.global();
        let blob_impl = match *parent.blob_impl.borrow() {
            BlobImpl::File(_) => {
                // Create new parent node
                BlobImpl::Sliced(JS::from_ref(parent), rel_pos)
            }
            BlobImpl::Memory(_) => {
                // Create new parent node
                BlobImpl::Sliced(JS::from_ref(parent), rel_pos)
            }
            BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => {
                // Adjust the slicing position, using same parent
                BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos))
            }
        };

        Blob::new(global.r(), blob_impl, relativeContentType.into())
    }

    // https://w3c.github.io/FileAPI/#constructorBlob
    pub fn Constructor(global: GlobalRef,
                       blobParts: Option<Vec<BlobOrString>>,
                       blobPropertyBag: &BlobBinding::BlobPropertyBag)
                       -> Fallible<Root<Blob>> {
        // TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView
        let bytes: Vec<u8> = match blobParts {
            None => Vec::new(),
            Some(blobparts) => match blob_parts_to_bytes(blobparts) {
                Ok(bytes) => bytes,
                Err(_) => return Err(Error::InvalidCharacter),
            }
        };

        Ok(Blob::new(global, BlobImpl::new_from_bytes(bytes), blobPropertyBag.type_.to_string()))
    }

    /// Get a slice to inner data, this might incur synchronous read and caching
    pub fn get_bytes(&self) -> Result<Vec<u8>, ()> {
        match *self.blob_impl.borrow() {
            BlobImpl::File(ref f) => {
                let (buffer, is_new_buffer) = match *f.cache.borrow() {
                    Some(ref bytes) => (bytes.clone(), false),
                    None => {
                        let global = self.global();
                        let bytes = read_file(global.r(), f.id.clone())?;
                        (bytes, true)
                    }
                };

                // Cache
                if is_new_buffer {
                    *f.cache.borrow_mut() = Some(buffer.clone());
                }

                Ok(buffer)
            }
            BlobImpl::Memory(ref s) => Ok(s.clone()),
            BlobImpl::Sliced(ref parent, ref rel_pos) => {
                parent.get_bytes().map(|v| {
                    let range = rel_pos.to_abs_range(v.len());
                    v.index(range).to_vec()
                })
            }
        }
    }

    /// Get a FileID representing the Blob content,
    /// used by URL.createObjectURL
    pub fn get_blob_url_id(&self) -> SelectedFileId {
        let opt_sliced_parent = match *self.blob_impl.borrow() {
            BlobImpl::Sliced(ref parent, ref rel_pos) => {
                Some((parent.promote(/* set_valid is */ false), rel_pos.clone(), parent.Size()))
            }
            _ => None
        };

        match opt_sliced_parent {
            Some((parent_id, rel_pos, size)) => self.create_sliced_url_id(&parent_id, &rel_pos, size),
            None => self.promote(/* set_valid is */ true),
        }
    }

    /// Promote non-Slice blob:
    /// 1. Memory-based: The bytes in data slice will be transferred to file manager thread.
    /// 2. File-based: Activation
    /// Depending on set_valid, the returned FileID can be part of
    /// valid or invalid Blob URL.
    fn promote(&self, set_valid: bool) -> SelectedFileId {
        let mut bytes = vec![];

        match *self.blob_impl.borrow_mut() {
            BlobImpl::Sliced(_, _) => {
                debug!("Sliced can't have a sliced parent");
                // Return dummy id
                return SelectedFileId(Uuid::new_v4().simple().to_string());
            }
            BlobImpl::File(ref f) => {
                if set_valid {
                    let global = self.global();
                    let origin = get_blob_origin(&global.r().get_url());
                    let (tx, rx) = ipc::channel().unwrap();

                    let msg = FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone());
                    self.send_to_file_manager(msg);

                    match rx.recv().unwrap() {
                        Ok(_) => return f.id.clone(),
                        // Return a dummy id on error
                        Err(_) => return SelectedFileId(Uuid::new_v4().simple().to_string())
                    }
                } else {
                    // no need to activate
                    return f.id.clone();
                }
            }
            BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes),
        };

        let global = self.global();
        let origin = get_blob_origin(&global.r().get_url());

        let blob_buf = BlobBuf {
            filename: None,
            type_string: self.typeString.clone(),
            size: bytes.len() as u64,
            bytes: bytes.to_vec(),
        };

        let (tx, rx) = ipc::channel().unwrap();
        let msg = FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, tx, origin.clone());
        self.send_to_file_manager(msg);

        match rx.recv().unwrap() {
            Ok(id) => {
                let id = SelectedFileId(id.0);
                *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob {
                    id: id.clone(),
                    name: None,
                    cache: DOMRefCell::new(Some(bytes.to_vec())),
                    size: bytes.len() as u64,
                });
                id
            }
            // Dummy id
            Err(_) => SelectedFileId(Uuid::new_v4().simple().to_string()),
        }
    }

    /// Get a FileID representing sliced parent-blob content
    fn create_sliced_url_id(&self, parent_id: &SelectedFileId,
                            rel_pos: &RelativePos, parent_len: u64) -> SelectedFileId {
        let global = self.global();

        let origin = get_blob_origin(&global.r().get_url());

        let (tx, rx) = ipc::channel().unwrap();
        let msg = FileManagerThreadMsg::AddSlicedURLEntry(parent_id.clone(),
                                                          rel_pos.clone(),
                                                          tx, origin.clone());
        self.send_to_file_manager(msg);
        match rx.recv().expect("File manager thread is down") {
            Ok(new_id) => {
                let new_id = SelectedFileId(new_id.0);

                *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob {
                    id: new_id.clone(),
                    name: None,
                    cache: DOMRefCell::new(None),
                    size: rel_pos.to_abs_range(parent_len as usize).len() as u64,
                });

                // Return the indirect id reference
                new_id
            }
            Err(_) => {
                // Return dummy id
                SelectedFileId(Uuid::new_v4().simple().to_string())
            }
        }
    }

    /// Cleanups at the time of destruction/closing
    fn clean_up_file_resource(&self) {
        if let BlobImpl::File(ref f) = *self.blob_impl.borrow() {
            let global = self.global();
            let origin = get_blob_origin(&global.r().get_url());

            let (tx, rx) = ipc::channel().unwrap();

            let msg = FileManagerThreadMsg::DecRef(f.id.clone(), origin, tx);
            self.send_to_file_manager(msg);
            let _ = rx.recv().unwrap();
        }
    }

    fn send_to_file_manager(&self, msg: FileManagerThreadMsg) {
        let global = self.global();
        let resource_threads = global.r().resource_threads();
        let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
    }
}

impl Drop for Blob {
    fn drop(&mut self) {
        if !self.IsClosed() {
            self.clean_up_file_resource();
        }
    }
}

fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<Vec<u8>, ()> {
    let resource_threads = global.resource_threads();
    let (chan, recv) = ipc::channel().map_err(|_|())?;
    let origin = get_blob_origin(&global.get_url());
    let check_url_validity = false;
    let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin);
    let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));

    let mut bytes = vec![];

    loop {
        match recv.recv().unwrap() {
            Ok(ReadFileProgress::Meta(mut blob_buf)) => {
                bytes.append(&mut blob_buf.bytes);
            }
            Ok(ReadFileProgress::Partial(mut bytes_in)) => {
                bytes.append(&mut bytes_in);
            }
            Ok(ReadFileProgress::EOF) => {
                return Ok(bytes);
            }
            Err(_) => return Err(()),
        }
    }
}

/// Extract bytes from BlobParts, used by Blob and File constructor
/// https://w3c.github.io/FileAPI/#constructorBlob
pub fn blob_parts_to_bytes(blobparts: Vec<BlobOrString>) -> Result<Vec<u8>, ()> {
    let mut ret = vec![];

    for blobpart in &blobparts {
        match blobpart {
            &BlobOrString::String(ref s) => {
                let mut bytes = UTF_8.encode(s, EncoderTrap::Replace).map_err(|_|())?;
                ret.append(&mut bytes);
            },
            &BlobOrString::Blob(ref b) => {
                let mut bytes = b.get_bytes().unwrap_or(vec![]);
                ret.append(&mut bytes);
            },
        }
    }

    Ok(ret)
}

impl BlobMethods for Blob {
    // https://w3c.github.io/FileAPI/#dfn-size
    fn Size(&self) -> u64 {
        // XXX: This will incur reading if file-based
        match self.get_bytes() {
            Ok(s) => s.len() as u64,
            _ => 0,
        }
    }

    // https://w3c.github.io/FileAPI/#dfn-type
    fn Type(&self) -> DOMString {
        DOMString::from(self.typeString.clone())
    }

    // https://w3c.github.io/FileAPI/#slice-method-algo
    fn Slice(&self,
             start: Option<i64>,
             end: Option<i64>,
             contentType: Option<DOMString>)
             -> Root<Blob> {
        let rel_pos = RelativePos::from_opts(start, end);
        Blob::new_sliced(self, rel_pos, contentType.unwrap_or(DOMString::from("")))
    }

    // https://w3c.github.io/FileAPI/#dfn-isClosed
    fn IsClosed(&self) -> bool {
        self.isClosed_.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-close
    fn Close(&self) {
        // Step 1
        if self.isClosed_.get() {
            return;
        }

        // Step 2
        self.isClosed_.set(true);

        // Step 3
        self.clean_up_file_resource();
    }
}

/// Get the normalized, MIME-parsable type string
/// https://w3c.github.io/FileAPI/#dfn-type
/// XXX: We will relax the restriction here,
/// since the spec has some problem over this part.
/// see https://github.com/w3c/FileAPI/issues/43
fn normalize_type_string(s: &str) -> String {
    if is_ascii_printable(s) {
        let s_lower = s.to_lowercase();
        // match s_lower.parse() as Result<Mime, ()> {
            // Ok(_) => s_lower,
            // Err(_) => "".to_string()
        s_lower
    } else {
        "".to_string()
    }
}

fn is_ascii_printable(string: &str) -> bool {
    // Step 5.1 in Sec 5.1 of File API spec
    // https://w3c.github.io/FileAPI/#constructorBlob
    string.chars().all(|c| c >= '\x20' && c <= '\x7E')
}
<commit_msg>Auto merge of #12896 - izgzhen:fix-blob-size, r=Manishearth<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BlobBinding;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::codegen::UnionTypes::BlobOrString;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use encoding::all::UTF_8;
use encoding::types::{EncoderTrap, Encoding};
use ipc_channel::ipc;
use net_traits::blob_url_store::{BlobBuf, get_blob_origin};
use net_traits::filemanager_thread::{FileManagerThreadMsg, SelectedFileId, RelativePos, ReadFileProgress};
use net_traits::{CoreResourceMsg, IpcSend};
use std::cell::Cell;
use std::mem;
use std::ops::Index;
use std::path::PathBuf;
use uuid::Uuid;

/// File-based blob
#[derive(JSTraceable)]
pub struct FileBlob {
    id: SelectedFileId,
    name: Option<PathBuf>,
    cache: DOMRefCell<Option<Vec<u8>>>,
    size: u64,
}

/// Blob backend implementation
#[must_root]
#[derive(JSTraceable)]
pub enum BlobImpl {
    /// File-based blob
    File(FileBlob),
    /// Memory-based blob
    Memory(Vec<u8>),
    /// Sliced blob, including parent blob and
    /// relative positions representing current slicing range,
    /// it is leaf of a two-layer fat tree
    Sliced(JS<Blob>, RelativePos),
}

impl BlobImpl {
    /// Construct memory-backed BlobImpl
    #[allow(unrooted_must_root)]
    pub fn new_from_bytes(bytes: Vec<u8>) -> BlobImpl {
        BlobImpl::Memory(bytes)
    }

    /// Construct file-backed BlobImpl from File ID
    pub fn new_from_file(file_id: SelectedFileId, name: PathBuf, size: u64) -> BlobImpl {
        BlobImpl::File(FileBlob {
            id: file_id,
            name: Some(name),
            cache: DOMRefCell::new(None),
            size: size,
        })
    }
}

// https://w3c.github.io/FileAPI/#blob
#[dom_struct]
pub struct Blob {
    reflector_: Reflector,
    #[ignore_heap_size_of = "No clear owner"]
    blob_impl: DOMRefCell<BlobImpl>,
    typeString: String,
    isClosed_: Cell<bool>,
}

impl Blob {
    #[allow(unrooted_must_root)]
    pub fn new(global: GlobalRef, blob_impl: BlobImpl, typeString: String) -> Root<Blob> {
        let boxed_blob = box Blob::new_inherited(blob_impl, typeString);
        reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
    }

    #[allow(unrooted_must_root)]
    pub fn new_inherited(blob_impl: BlobImpl, typeString: String) -> Blob {
        Blob {
            reflector_: Reflector::new(),
            blob_impl: DOMRefCell::new(blob_impl),
            // NOTE: Guarding the format correctness here,
            // https://w3c.github.io/FileAPI/#dfn-type
            typeString: normalize_type_string(&typeString),
            isClosed_: Cell::new(false),
        }
    }

    #[allow(unrooted_must_root)]
    fn new_sliced(parent: &Blob, rel_pos: RelativePos,
                  relativeContentType: DOMString) -> Root<Blob> {
        let global = parent.global();
        let blob_impl = match *parent.blob_impl.borrow() {
            BlobImpl::File(_) => {
                // Create new parent node
                BlobImpl::Sliced(JS::from_ref(parent), rel_pos)
            }
            BlobImpl::Memory(_) => {
                // Create new parent node
                BlobImpl::Sliced(JS::from_ref(parent), rel_pos)
            }
            BlobImpl::Sliced(ref grandparent, ref old_rel_pos) => {
                // Adjust the slicing position, using same parent
                BlobImpl::Sliced(grandparent.clone(), old_rel_pos.slice_inner(&rel_pos))
            }
        };

        Blob::new(global.r(), blob_impl, relativeContentType.into())
    }

    // https://w3c.github.io/FileAPI/#constructorBlob
    pub fn Constructor(global: GlobalRef,
                       blobParts: Option<Vec<BlobOrString>>,
                       blobPropertyBag: &BlobBinding::BlobPropertyBag)
                       -> Fallible<Root<Blob>> {
        // TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView
        let bytes: Vec<u8> = match blobParts {
            None => Vec::new(),
            Some(blobparts) => match blob_parts_to_bytes(blobparts) {
                Ok(bytes) => bytes,
                Err(_) => return Err(Error::InvalidCharacter),
            }
        };

        Ok(Blob::new(global, BlobImpl::new_from_bytes(bytes), blobPropertyBag.type_.to_string()))
    }

    /// Get a slice to inner data, this might incur synchronous read and caching
    pub fn get_bytes(&self) -> Result<Vec<u8>, ()> {
        match *self.blob_impl.borrow() {
            BlobImpl::File(ref f) => {
                let (buffer, is_new_buffer) = match *f.cache.borrow() {
                    Some(ref bytes) => (bytes.clone(), false),
                    None => {
                        let global = self.global();
                        let bytes = read_file(global.r(), f.id.clone())?;
                        (bytes, true)
                    }
                };

                // Cache
                if is_new_buffer {
                    *f.cache.borrow_mut() = Some(buffer.clone());
                }

                Ok(buffer)
            }
            BlobImpl::Memory(ref s) => Ok(s.clone()),
            BlobImpl::Sliced(ref parent, ref rel_pos) => {
                parent.get_bytes().map(|v| {
                    let range = rel_pos.to_abs_range(v.len());
                    v.index(range).to_vec()
                })
            }
        }
    }

    /// Get a FileID representing the Blob content,
    /// used by URL.createObjectURL
    pub fn get_blob_url_id(&self) -> SelectedFileId {
        let opt_sliced_parent = match *self.blob_impl.borrow() {
            BlobImpl::Sliced(ref parent, ref rel_pos) => {
                Some((parent.promote(/* set_valid is */ false), rel_pos.clone(), parent.Size()))
            }
            _ => None
        };

        match opt_sliced_parent {
            Some((parent_id, rel_pos, size)) => self.create_sliced_url_id(&parent_id, &rel_pos, size),
            None => self.promote(/* set_valid is */ true),
        }
    }

    /// Promote non-Slice blob:
    /// 1. Memory-based: The bytes in data slice will be transferred to file manager thread.
    /// 2. File-based: Activation
    /// Depending on set_valid, the returned FileID can be part of
    /// valid or invalid Blob URL.
    fn promote(&self, set_valid: bool) -> SelectedFileId {
        let mut bytes = vec![];

        match *self.blob_impl.borrow_mut() {
            BlobImpl::Sliced(_, _) => {
                debug!("Sliced can't have a sliced parent");
                // Return dummy id
                return SelectedFileId(Uuid::new_v4().simple().to_string());
            }
            BlobImpl::File(ref f) => {
                if set_valid {
                    let global = self.global();
                    let origin = get_blob_origin(&global.r().get_url());
                    let (tx, rx) = ipc::channel().unwrap();

                    let msg = FileManagerThreadMsg::ActivateBlobURL(f.id.clone(), tx, origin.clone());
                    self.send_to_file_manager(msg);

                    match rx.recv().unwrap() {
                        Ok(_) => return f.id.clone(),
                        // Return a dummy id on error
                        Err(_) => return SelectedFileId(Uuid::new_v4().simple().to_string())
                    }
                } else {
                    // no need to activate
                    return f.id.clone();
                }
            }
            BlobImpl::Memory(ref mut bytes_in) => mem::swap(bytes_in, &mut bytes),
        };

        let global = self.global();
        let origin = get_blob_origin(&global.r().get_url());

        let blob_buf = BlobBuf {
            filename: None,
            type_string: self.typeString.clone(),
            size: bytes.len() as u64,
            bytes: bytes.to_vec(),
        };

        let (tx, rx) = ipc::channel().unwrap();
        let msg = FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, tx, origin.clone());
        self.send_to_file_manager(msg);

        match rx.recv().unwrap() {
            Ok(id) => {
                let id = SelectedFileId(id.0);
                *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob {
                    id: id.clone(),
                    name: None,
                    cache: DOMRefCell::new(Some(bytes.to_vec())),
                    size: bytes.len() as u64,
                });
                id
            }
            // Dummy id
            Err(_) => SelectedFileId(Uuid::new_v4().simple().to_string()),
        }
    }

    /// Get a FileID representing sliced parent-blob content
    fn create_sliced_url_id(&self, parent_id: &SelectedFileId,
                            rel_pos: &RelativePos, parent_len: u64) -> SelectedFileId {
        let global = self.global();

        let origin = get_blob_origin(&global.r().get_url());

        let (tx, rx) = ipc::channel().unwrap();
        let msg = FileManagerThreadMsg::AddSlicedURLEntry(parent_id.clone(),
                                                          rel_pos.clone(),
                                                          tx, origin.clone());
        self.send_to_file_manager(msg);
        match rx.recv().expect("File manager thread is down") {
            Ok(new_id) => {
                let new_id = SelectedFileId(new_id.0);

                *self.blob_impl.borrow_mut() = BlobImpl::File(FileBlob {
                    id: new_id.clone(),
                    name: None,
                    cache: DOMRefCell::new(None),
                    size: rel_pos.to_abs_range(parent_len as usize).len() as u64,
                });

                // Return the indirect id reference
                new_id
            }
            Err(_) => {
                // Return dummy id
                SelectedFileId(Uuid::new_v4().simple().to_string())
            }
        }
    }

    /// Cleanups at the time of destruction/closing
    fn clean_up_file_resource(&self) {
        if let BlobImpl::File(ref f) = *self.blob_impl.borrow() {
            let global = self.global();
            let origin = get_blob_origin(&global.r().get_url());

            let (tx, rx) = ipc::channel().unwrap();

            let msg = FileManagerThreadMsg::DecRef(f.id.clone(), origin, tx);
            self.send_to_file_manager(msg);
            let _ = rx.recv().unwrap();
        }
    }

    fn send_to_file_manager(&self, msg: FileManagerThreadMsg) {
        let global = self.global();
        let resource_threads = global.r().resource_threads();
        let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
    }
}

impl Drop for Blob {
    fn drop(&mut self) {
        if !self.IsClosed() {
            self.clean_up_file_resource();
        }
    }
}

fn read_file(global: GlobalRef, id: SelectedFileId) -> Result<Vec<u8>, ()> {
    let resource_threads = global.resource_threads();
    let (chan, recv) = ipc::channel().map_err(|_|())?;
    let origin = get_blob_origin(&global.get_url());
    let check_url_validity = false;
    let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin);
    let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));

    let mut bytes = vec![];

    loop {
        match recv.recv().unwrap() {
            Ok(ReadFileProgress::Meta(mut blob_buf)) => {
                bytes.append(&mut blob_buf.bytes);
            }
            Ok(ReadFileProgress::Partial(mut bytes_in)) => {
                bytes.append(&mut bytes_in);
            }
            Ok(ReadFileProgress::EOF) => {
                return Ok(bytes);
            }
            Err(_) => return Err(()),
        }
    }
}

/// Extract bytes from BlobParts, used by Blob and File constructor
/// https://w3c.github.io/FileAPI/#constructorBlob
pub fn blob_parts_to_bytes(blobparts: Vec<BlobOrString>) -> Result<Vec<u8>, ()> {
    let mut ret = vec![];

    for blobpart in &blobparts {
        match blobpart {
            &BlobOrString::String(ref s) => {
                let mut bytes = UTF_8.encode(s, EncoderTrap::Replace).map_err(|_|())?;
                ret.append(&mut bytes);
            },
            &BlobOrString::Blob(ref b) => {
                let mut bytes = b.get_bytes().unwrap_or(vec![]);
                ret.append(&mut bytes);
            },
        }
    }

    Ok(ret)
}

impl BlobMethods for Blob {
    // https://w3c.github.io/FileAPI/#dfn-size
    fn Size(&self) -> u64 {
         match *self.blob_impl.borrow() {
            BlobImpl::File(ref f) => f.size,
            BlobImpl::Memory(ref v) => v.len() as u64,
            BlobImpl::Sliced(ref parent, ref rel_pos) =>
                rel_pos.to_abs_range(parent.Size() as usize).len() as u64,
         }
    }

    // https://w3c.github.io/FileAPI/#dfn-type
    fn Type(&self) -> DOMString {
        DOMString::from(self.typeString.clone())
    }

    // https://w3c.github.io/FileAPI/#slice-method-algo
    fn Slice(&self,
             start: Option<i64>,
             end: Option<i64>,
             contentType: Option<DOMString>)
             -> Root<Blob> {
        let rel_pos = RelativePos::from_opts(start, end);
        Blob::new_sliced(self, rel_pos, contentType.unwrap_or(DOMString::from("")))
    }

    // https://w3c.github.io/FileAPI/#dfn-isClosed
    fn IsClosed(&self) -> bool {
        self.isClosed_.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-close
    fn Close(&self) {
        // Step 1
        if self.isClosed_.get() {
            return;
        }

        // Step 2
        self.isClosed_.set(true);

        // Step 3
        self.clean_up_file_resource();
    }
}

/// Get the normalized, MIME-parsable type string
/// https://w3c.github.io/FileAPI/#dfn-type
/// XXX: We will relax the restriction here,
/// since the spec has some problem over this part.
/// see https://github.com/w3c/FileAPI/issues/43
fn normalize_type_string(s: &str) -> String {
    if is_ascii_printable(s) {
        let s_lower = s.to_lowercase();
        // match s_lower.parse() as Result<Mime, ()> {
            // Ok(_) => s_lower,
            // Err(_) => "".to_string()
        s_lower
    } else {
        "".to_string()
    }
}

fn is_ascii_printable(string: &str) -> bool {
    // Step 5.1 in Sec 5.1 of File API spec
    // https://w3c.github.io/FileAPI/#constructorBlob
    string.chars().all(|c| c >= '\x20' && c <= '\x7E')
}
<|endoftext|>


<commit_before><commit_msg>Build failed due invalid source code format. Fixed.<commit_after><|endoftext|>


<commit_before><commit_msg>Fix tidy errors<commit_after><|endoftext|>


<commit_before><commit_msg>expect<commit_after><|endoftext|>


<commit_before>#[cfg(test)]

use std::path::Path;
use serde_json;
use book::bookconfig::*;

#[test]
fn it_parses_json_config() {
    let text = r#"
{
    "title": "mdBook Documentation",
    "description": "Create book from markdown files. Like Gitbook but implemented in Rust",
    "author": "Mathieu David"
}"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_json_string(&text.to_string());

    let expected = r#"BookConfig {
    root: ".",
    dest: "book",
    src: "src",
    theme_path: "theme",
    title: "mdBook Documentation",
    author: "Mathieu David",
    description: "Create book from markdown files. Like Gitbook but implemented in Rust",
    indent_spaces: 4,
    multilingual: false
}"#;

    assert_eq!(format!("{:#?}", config), expected);
}

#[test]
fn it_parses_toml_config() {
    let text = r#"
title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
author = "Mathieu David"
"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_toml_string(&text.to_string());

    let expected = r#"BookConfig {
    root: ".",
    dest: "book",
    src: "src",
    theme_path: "theme",
    title: "mdBook Documentation",
    author: "Mathieu David",
    description: "Create book from markdown files. Like Gitbook but implemented in Rust",
    indent_spaces: 4,
    multilingual: false
}"#;

    assert_eq!(format!("{:#?}", config), expected);
}

#[test]
fn it_parses_json_nested_array_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays-nested.json

    let text = r#"
{
    "nest": {
        "type": "array",
        "value": [
            {"type": "array", "value": [
                {"type": "string", "value": "a"}
            ]},
            {"type": "array", "value": [
                {"type": "string", "value": "b"}
            ]}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "nest": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "a"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "b"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}

#[test]
fn it_parses_json_arrays_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays.json

    let text = r#"
{
    "ints": {
        "type": "array",
        "value": [
            {"type": "integer", "value": "1"},
            {"type": "integer", "value": "2"},
            {"type": "integer", "value": "3"}
        ]
    },
    "floats": {
        "type": "array",
        "value": [
            {"type": "float", "value": "1.1"},
            {"type": "float", "value": "2.1"},
            {"type": "float", "value": "3.1"}
        ]
    },
    "strings": {
        "type": "array",
        "value": [
            {"type": "string", "value": "a"},
            {"type": "string", "value": "b"},
            {"type": "string", "value": "c"}
        ]
    },
    "dates": {
        "type": "array",
        "value": [
            {"type": "datetime", "value": "1987-07-05T17:45:00Z"},
            {"type": "datetime", "value": "1979-05-27T07:32:00Z"},
            {"type": "datetime", "value": "2006-06-01T11:00:00Z"}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "dates": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1987-07-05T17:45:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1979-05-27T07:32:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "2006-06-01T11:00:00Z"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "floats": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "1.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "2.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "3.1"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "ints": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "2"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "3"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "strings": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "a"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "b"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "c"
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}
<commit_msg>fix test<commit_after>#[cfg(test)]

use std::path::Path;
use serde_json;
use book::bookconfig::*;

#[test]
fn it_parses_json_config() {
    let text = r#"
{
    "title": "mdBook Documentation",
    "description": "Create book from markdown files. Like Gitbook but implemented in Rust",
    "author": "Mathieu David"
}"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_json_string(&text.to_string());

    let mut expected = BookConfig::new(Path::new("."));
    expected.title = "mdBook Documentation".to_string();
    expected.author = "Mathieu David".to_string();
    expected.description = "Create book from markdown files. Like Gitbook but implemented in Rust".to_string();

    assert_eq!(format!("{:#?}", config), format!("{:#?}", expected));
}

#[test]
fn it_parses_toml_config() {
    let text = r#"
title = "mdBook Documentation"
description = "Create book from markdown files. Like Gitbook but implemented in Rust"
author = "Mathieu David"
"#;

    // TODO don't require path argument, take pwd
    let mut config = BookConfig::new(Path::new("."));

    config.parse_from_toml_string(&text.to_string());

    let mut expected = BookConfig::new(Path::new("."));
    expected.title = "mdBook Documentation".to_string();
    expected.author = "Mathieu David".to_string();
    expected.description = "Create book from markdown files. Like Gitbook but implemented in Rust".to_string();

    assert_eq!(format!("{:#?}", config), format!("{:#?}", expected));
}

#[test]
fn it_parses_json_nested_array_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays-nested.json

    let text = r#"
{
    "nest": {
        "type": "array",
        "value": [
            {"type": "array", "value": [
                {"type": "string", "value": "a"}
            ]},
            {"type": "array", "value": [
                {"type": "string", "value": "b"}
            ]}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "nest": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "a"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "array"
                            ),
                            "value": Array(
                                [
                                    Table(
                                        {
                                            "type": String(
                                                "string"
                                            ),
                                            "value": String(
                                                "b"
                                            )
                                        }
                                    )
                                ]
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}

#[test]
fn it_parses_json_arrays_to_toml() {

    // Example from:
    // toml-0.2.1/tests/valid/arrays.json

    let text = r#"
{
    "ints": {
        "type": "array",
        "value": [
            {"type": "integer", "value": "1"},
            {"type": "integer", "value": "2"},
            {"type": "integer", "value": "3"}
        ]
    },
    "floats": {
        "type": "array",
        "value": [
            {"type": "float", "value": "1.1"},
            {"type": "float", "value": "2.1"},
            {"type": "float", "value": "3.1"}
        ]
    },
    "strings": {
        "type": "array",
        "value": [
            {"type": "string", "value": "a"},
            {"type": "string", "value": "b"},
            {"type": "string", "value": "c"}
        ]
    },
    "dates": {
        "type": "array",
        "value": [
            {"type": "datetime", "value": "1987-07-05T17:45:00Z"},
            {"type": "datetime", "value": "1979-05-27T07:32:00Z"},
            {"type": "datetime", "value": "2006-06-01T11:00:00Z"}
        ]
    }
}"#;

    let c: serde_json::Value = serde_json::from_str(&text).unwrap();

    let result = json_object_to_btreemap(&c.as_object().unwrap());

    let expected = r#"{
    "dates": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1987-07-05T17:45:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "1979-05-27T07:32:00Z"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "datetime"
                            ),
                            "value": String(
                                "2006-06-01T11:00:00Z"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "floats": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "1.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "2.1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "float"
                            ),
                            "value": String(
                                "3.1"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "ints": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "1"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "2"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "integer"
                            ),
                            "value": String(
                                "3"
                            )
                        }
                    )
                ]
            )
        }
    ),
    "strings": Table(
        {
            "type": String(
                "array"
            ),
            "value": Array(
                [
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "a"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "b"
                            )
                        }
                    ),
                    Table(
                        {
                            "type": String(
                                "string"
                            ),
                            "value": String(
                                "c"
                            )
                        }
                    )
                ]
            )
        }
    )
}"#;

    assert_eq!(format!("{:#?}", result), expected);
}
<|endoftext|>


<commit_before><commit_msg>Update short_number_info.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Add test for #39485<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn g() {
    &panic!()
}

fn f() -> isize {
    (return 1, return 2)
}

fn main() {}
<|endoftext|>


<commit_before><commit_msg>Add a test for std::any::type_name() as a const fn<commit_after>// run-pass

#![feature(const_fn)]
#![feature(const_type_name)]
#![allow(dead_code)]

const fn type_name_wrapper<T>(_: &T) -> &'static str {
    std::any::type_name::<T>()
}

struct Struct<TA, TB, TC> {
    a: TA,
    b: TB,
    c: TC,
}

type StructInstantiation = Struct<i8, f64, bool>;

const CONST_STRUCT: StructInstantiation = StructInstantiation { a: 12, b: 13.7, c: false };

const CONST_STRUCT_NAME: &'static str = type_name_wrapper(&CONST_STRUCT);

fn main() {
    let non_const_struct = StructInstantiation { a: 87, b: 65.99, c: true };

    let non_const_struct_name = type_name_wrapper(&non_const_struct);

    assert_eq!(CONST_STRUCT_NAME, non_const_struct_name);
}
<|endoftext|>


<commit_before><commit_msg>Removed dead code.<commit_after><|endoftext|>


<commit_before><commit_msg>Fix documented signature of term `DELETE`<commit_after><|endoftext|>


<commit_before>use core::mem::size_of;

use super::SDTHeader;

#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
struct RSDP {
    signature: [u8; 8],
    checksum: u8,
    oemid: [u8; 6],
    revision: u8,
    addr: u32
}

const SIGNATURE: &'static [u8] = b"RSD PTR ";

impl RSDP {
    pub fn new() -> Option<Self> {
        //Search top of bios region
        let mut search_ptr = 0xE0000;
        while search_ptr < 0xFFFFF {
            let rsdp = search_ptr as *const RSDP;
            if unsafe { (*rsdp).valid() } {
                return Some(unsafe { *rsdp });
            }
            search_ptr += 16;
        }

        None
    }

    //TODO: Checksum validation
    pub fn valid(&self) -> bool {
        if self.signature == SIGNATURE {
            let ptr = (self as *const Self) as *const u8;
            let sum = (0..size_of::<Self>() as isize).fold(0, |sum, i| sum + unsafe { *ptr.offset(i) });

            sum == 0
        } else {
            false
        }
    }
}

#[repr(packed)]
#[derive(Clone, Debug, Default)]
pub struct RSDT {
    pub header: SDTHeader,
    pub addrs: &'static [u32]
}

impl RSDT {
    pub fn new() -> Result<Self, &'static str> {
        match RSDP::new() {
            Some(rsdp) => {
                let header = rsdp.addr as *const SDTHeader;
                if unsafe { (*header).valid("RSDT") } {
                    Ok(RSDT {
                        header: unsafe { (*header).clone() },
                        addrs: unsafe { (*header).data() }
                    })
                } else {
                    Err("Did not find RSDT")
                }
            },
            None => {
                Err("Did not find RSDP")
            }
        }
    }
}
<commit_msg>Refactor `RSDP::new()` to return a `Result` instead<commit_after>use core::mem::size_of;

use super::SDTHeader;

#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
struct RSDP {
    signature: [u8; 8],
    checksum: u8,
    oemid: [u8; 6],
    revision: u8,
    addr: u32
}

const SIGNATURE: &'static [u8] = b"RSD PTR ";

impl RSDP {
    pub fn new() -> Result<Self, &'static str> {
        //Search top of bios region
        let mut search_ptr = 0xE0000;
        while search_ptr < 0xFFFFF {
            let rsdp = search_ptr as *const RSDP;
            if unsafe { (*rsdp).valid() } {
                return Ok(unsafe { *rsdp });
            }
            search_ptr += 16;
        }

        Err("Did not find RSDP")
    }

    //TODO: Checksum validation
    pub fn valid(&self) -> bool {
        if self.signature == SIGNATURE {
            let ptr = (self as *const Self) as *const u8;
            let sum = (0..size_of::<Self>() as isize).fold(0, |sum, i| sum + unsafe { *ptr.offset(i) });

            sum == 0
        } else {
            false
        }
    }
}

#[repr(packed)]
#[derive(Clone, Debug, Default)]
pub struct RSDT {
    pub header: SDTHeader,
    pub addrs: &'static [u32]
}

impl RSDT {
    pub fn new() -> Result<Self, &'static str> {
        match RSDP::new() {
            Ok(rsdp) => {
                let header = rsdp.addr as *const SDTHeader;
                if unsafe { (*header).valid("RSDT") } {
                    Ok(RSDT {
                        header: unsafe { (*header).clone() },
                        addrs: unsafe { (*header).data() }
                    })
                } else {
                    Err("Did not find RSDT")
                }
            },
            Err(e) => Err(e),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>file_size: use args_os() instead of args()<commit_after><|endoftext|>


<commit_before><commit_msg>Remove unused Error::from() call<commit_after><|endoftext|>


<commit_before><commit_msg>Adds Rust Problem 24<commit_after>/// Problem 24
/// A permutation is an ordered arrangement of objects. For example, 3124 is one
/// possible permutation of the digits 1, 2, 3 and 4. If all of the permutations
/// are listed numerically or alphabetically, we call it lexicographic order.
/// The lexicographic permutations of 0, 1 and 2 are:
///
///			012   021   102   120   201   210
///
/// What is the millionth lexicographic permutation of the digits
/// 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
fn main() {
	let p: Vec<u64> = nth_permutation(10, 1000000);
	print!("Answer: ");
	for d in p {
		print!("{}", d);
	}
	print!("\n");
}

/// Compute the nth permutation of a vector of length l. Returns a vector of
/// array indices corresponding to the premutation.
///
/// asserteq!(nth_permutation(3,1), [0,1,2]);
///
/// Permutations are numbered from 1..n!
fn nth_permutation(l: u64, n: u64) -> Vec<u64> {
	let mut rem: Vec<u64> = Vec::new();
	for i in 0u64..l {
		rem.push(i)
	}

	let mut p: Vec<u64> = Vec::new();
	// Loop over indices
	for i in 0u64..l {
		// Choose jth item of remaining to push
		let j = ((n-1)/factorial(l-i-1)) % (l-i);
		// Remove item from remaining and insert it into permutation
		p.push(rem.remove(j as usize));
	}
	p
}

fn factorial(n: u64) -> u64 {
	match n {
		0 => 1,
		1 => 1,
		2 => 2,
		3 => 6,
		4 => 24,
		5 => 120,
		6 => 720,
		7 => 5040,
		8 => 40320,
		9 => 362880,
		10 => 3628800,
		_ => n * factorial(n-1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![crate_name = "gl_init_platform"]
#![comment = "An adaptor for gl-init-rs `Context`s that allows interoperability \
              with gfx-rs."]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(macro_rules, phase)]

extern crate glinit = "gl-init-rs";
#[phase(plugin, link)]
extern crate log;
extern crate libc;

extern crate device;

use std::rc::Rc;

pub struct Window(glinit::Window);

impl Window {
    #[inline]
    pub fn new() -> Option<Window> {
        let win = match glinit::Window::new() {
            Err(_) => return None,
            Ok(w) => w
        };

        Some(Window(win))
    }

    #[inline]
    pub fn from_builder(builder: glinit::WindowBuilder) -> Option<Window> {
        let win = match builder.build() {
            Err(_) => return None,
            Ok(w) => w
        };

        Some(Window(win))
    }

    #[inline]
    pub fn from_existing(win: glinit::Window) -> Window {
        Window(win)
    }
}

impl<'a> device::GlProvider for &'a Window {
    fn get_proc_address(&self, name: &str) -> *const libc::c_void {
        let &&Window(ref win) = self;
        win.get_proc_address(name) as *const libc::c_void
    }
}

impl<'a> device::GraphicsContext<device::GlBackEnd> for &'a Window {
    fn make_current(&self) {
        let &&Window(ref win) = self;
        unsafe { win.make_current() };
    }

    fn swap_buffers(&self) {
        let &&Window(ref win) = self;
        win.swap_buffers();
    }
}

impl Window {
    #[inline]
    pub fn set_title(&self, title: &str) {
        let &Window(ref win) = self;
        win.set_title(title)
    }

    #[inline]
    pub fn get_position(&self) -> Option<(int, int)> {
        let &Window(ref win) = self;
        win.get_position()
    }

    #[inline]
    pub fn set_position(&self, x: uint, y: uint) {
        let &Window(ref win) = self;
        win.set_position(x, y)
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        let &Window(ref win) = self;
        win.get_inner_size()
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        let &Window(ref win) = self;
        win.get_outer_size()
    }

    #[inline]
    pub fn set_inner_size(&self, x: uint, y: uint) {
        let &Window(ref win) = self;
        win.set_inner_size(x, y)
    }

    #[inline]
    pub fn is_closed(&self) -> bool {
        let &Window(ref win) = self;
        win.is_closed()
    }

    #[inline]
    pub fn poll_events(&self) -> glinit::PollEventsIterator {
        let &Window(ref win) = self;
        win.poll_events()
    }

    #[inline]
    pub fn wait_events(&self) -> glinit::WaitEventsIterator {
        let &Window(ref win) = self;
        win.wait_events()
    }

    #[inline]
    pub unsafe fn make_current(&self) {
        let &Window(ref win) = self;
        win.make_current();
    }
}
<commit_msg>Cleaner gl_init_platform<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![crate_name = "gl_init_platform"]
#![comment = "An adaptor for gl-init-rs `Context`s that allows interoperability \
              with gfx-rs."]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(macro_rules, phase)]

extern crate glinit = "gl-init-rs";
#[phase(plugin, link)]
extern crate log;
extern crate libc;

extern crate device;

pub struct Window(glinit::Window);

impl Window {
    #[inline]
    pub fn new() -> Option<Window> {
        let win = match glinit::Window::new() {
            Err(_) => return None,
            Ok(w) => w
        };

        Some(Window(win))
    }

    #[inline]
    pub fn from_builder(builder: glinit::WindowBuilder) -> Option<Window> {
        let win = match builder.build() {
            Err(_) => return None,
            Ok(w) => w
        };

        Some(Window(win))
    }

    #[inline]
    pub fn from_existing(win: glinit::Window) -> Window {
        Window(win)
    }
}

impl<'a> device::GlProvider for &'a Window {
    fn get_proc_address(&self, name: &str) -> *const libc::c_void {
        let &&Window(ref win) = self;
        win.get_proc_address(name) as *const libc::c_void
    }
}

impl<'a> device::GraphicsContext<device::GlBackEnd> for &'a Window {
    fn make_current(&self) {
        let &&Window(ref win) = self;
        unsafe { win.make_current() };
    }

    fn swap_buffers(&self) {
        let &&Window(ref win) = self;
        win.swap_buffers();
    }
}

impl Deref<glinit::Window> for Window {
    fn deref(&self) -> &glinit::Window {
        let &Window(ref win) = self;
        win
    }
}
<|endoftext|>


<commit_before><commit_msg>Add a test for negative constants. Closes #358<commit_after>// Issue #358

const toplevel_mod: int = -1;

fn main() {
    assert toplevel_mod == -1;
}<|endoftext|>


<commit_before>generate_error_imports!();

generate_error_types!(ViewError, ViewErrorKind,
    StoreError     => "Store error",
    NoVersion      => "No version specified",
    PatternError   => "Error in Pattern",
    GlobBuildError => "Could not build glob() Argument"
);

<commit_msg>imag-view: use generate_error_module!() macro and reexport generated types<commit_after>generate_error_module!(
    generate_error_types!(ViewError, ViewErrorKind,
        StoreError     => "Store error",
        NoVersion      => "No version specified",
        PatternError   => "Error in Pattern",
        GlobBuildError => "Could not build glob() Argument"
    );
);

pub use self::error::ViewError;
pub use self::error::ViewErrorKind;

<|endoftext|>


<commit_before><commit_msg>added frame_stream.rs<commit_after>use std::io;
use std::net::SocketAddr;
use mio::{EventLoop, Token};
use mio::tcp::TcpStream;
use lifeguard::Pool;

use EventedByteStream;
use FrameEngine;
use Codec;
use Buffer;
use FrameHandler;
use EventedFrameStream;

use evented_frame_stream::Outbox;

pub struct FrameStream<'a, E, F, C, H> where
  E: 'a + EventedByteStream,
  C: 'a + Codec<F>,
  H: 'a + FrameHandler<E, F, C, H>,
  F: 'a + Send {
  efs: &'a mut EventedFrameStream<E, F>,
  token: Token,
  event_loop: &'a mut EventLoop<FrameEngine<E, F, C, H>>,
  outbox_pool: &'a mut Pool<Outbox<F>>,
}

impl <'a, E, F, C, H> FrameStream<'a, E, F, C, H> where
  E: 'a + EventedByteStream,
  C: 'a + Codec<F>,
  H: 'a + FrameHandler<E, F, C, H>,
  F: 'a + Send {

  pub fn new <'b> (
      efs: &'b mut EventedFrameStream<E, F>,
      event_loop: &'b mut EventLoop<FrameEngine<E, F, C, H>>,
      outbox_pool: &'b mut Pool<Outbox<F>>,
      token: Token) -> FrameStream<'b, E, F, C, H> {
    FrameStream {
      efs: efs,
      token: token,
      event_loop: event_loop,
      outbox_pool: outbox_pool
    }
  }

  pub fn token(&self) -> Token {
    self.token
  }

  pub fn send(&mut self, frame: F) {
    let FrameStream {
      ref mut efs,
      token,
      ref mut event_loop,
      ref mut outbox_pool,
    } = *self;
    efs.send(event_loop, token, outbox_pool, frame);
  }
}

// Methods that will only work for TCP Streams
impl <'a, F, C, H> FrameStream<'a, TcpStream, F, C, H> where
  C: 'a + Codec<F>,
  H: 'a + FrameHandler<TcpStream, F, C, H>,
  F: 'a + Send {

  pub fn peer_addr(&self) -> io::Result<SocketAddr> {
    self.efs.stream.peer_addr()
  }

  pub fn local_addr(&self) -> io::Result<SocketAddr> {
    self.efs.stream.local_addr()
  }
}
<|endoftext|>


<commit_before><commit_msg>rust custom types<commit_after>#[allow(dead_code)]
fn main() {
    struct Nil;

    struct Pair(i32, f64);

    struct Point {
      x: f64;
      y: f64;
    }

    struct Rectangle {
        p1: Point;
        p2: Point;
    }

    let point = Point{x: 0.3, y: 0.4};
    println!("point coordinates: ({}, {})", point.x, point.y);
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for inlining external documentation into the current AST.

use syntax::ast;
use syntax::ast_util;
use syntax::attr::AttrMetaMethods;

use rustc::metadata::csearch;
use rustc::metadata::decoder;
use rustc::middle::def;
use rustc::middle::ty;
use rustc::middle::subst;
use rustc::middle::stability;

use core;
use doctree;
use clean;

use super::Clean;

/// Attempt to inline the definition of a local node id into this AST.
///
/// This function will fetch the definition of the id specified, and if it is
/// from another crate it will attempt to inline the documentation from the
/// other crate into this crate.
///
/// This is primarily used for `pub use` statements which are, in general,
/// implementation details. Inlining the documentation should help provide a
/// better experience when reading the documentation in this use case.
///
/// The returned value is `None` if the `id` could not be inlined, and `Some`
/// of a vector of items if it was successfully expanded.
pub fn try_inline(id: ast::NodeId, into: Option<ast::Ident>)
                  -> Option<Vec<clean::Item>> {
    let cx = ::ctxtkey.get().unwrap();
    let tcx = match cx.maybe_typed {
        core::Typed(ref tycx) => tycx,
        core::NotTyped(_) => return None,
    };
    let def = match tcx.def_map.borrow().find(&id) {
        Some(def) => *def,
        None => return None,
    };
    let did = def.def_id();
    if ast_util::is_local(did) { return None }
    try_inline_def(&**cx, tcx, def).map(|vec| {
        vec.move_iter().map(|mut item| {
            match into {
                Some(into) if item.name.is_some() => {
                    item.name = Some(into.clean());
                }
                _ => {}
            }
            item
        }).collect()
    })
}

fn try_inline_def(cx: &core::DocContext,
                  tcx: &ty::ctxt,
                  def: def::Def) -> Option<Vec<clean::Item>> {
    let mut ret = Vec::new();
    let did = def.def_id();
    let inner = match def {
        def::DefTrait(did) => {
            record_extern_fqn(cx, did, clean::TypeTrait);
            clean::TraitItem(build_external_trait(tcx, did))
        }
        def::DefFn(did, style) => {
            // If this function is a tuple struct constructor, we just skip it
            if csearch::get_tuple_struct_definition_if_ctor(&tcx.sess.cstore,
                                                            did).is_some() {
                return None
            }
            record_extern_fqn(cx, did, clean::TypeFunction);
            clean::FunctionItem(build_external_function(tcx, did, style))
        }
        def::DefStruct(did) => {
            record_extern_fqn(cx, did, clean::TypeStruct);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            clean::StructItem(build_struct(tcx, did))
        }
        def::DefTy(did) => {
            record_extern_fqn(cx, did, clean::TypeEnum);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            build_type(tcx, did)
        }
        // Assume that the enum type is reexported next to the variant, and
        // variants don't show up in documentation specially.
        def::DefVariant(..) => return Some(Vec::new()),
        def::DefMod(did) => {
            record_extern_fqn(cx, did, clean::TypeModule);
            clean::ModuleItem(build_module(cx, tcx, did))
        }
        def::DefStatic(did, mtbl) => {
            record_extern_fqn(cx, did, clean::TypeStatic);
            clean::StaticItem(build_static(tcx, did, mtbl))
        }
        _ => return None,
    };
    let fqn = csearch::get_item_path(tcx, did);
    cx.inlined.borrow_mut().get_mut_ref().insert(did);
    ret.push(clean::Item {
        source: clean::Span::empty(),
        name: Some(fqn.last().unwrap().to_string()),
        attrs: load_attrs(tcx, did),
        inner: inner,
        visibility: Some(ast::Public),
        stability: stability::lookup(tcx, did).clean(),
        def_id: did,
    });
    Some(ret)
}

pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec<clean::Attribute> {
    let mut attrs = Vec::new();
    csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
        attrs.extend(v.move_iter().map(|mut a| {
            // FIXME this isn't quite always true, it's just true about 99% of
            //       the time when dealing with documentation. For example,
            //       this would treat doc comments of the form `#[doc = "foo"]`
            //       incorrectly.
            if a.name().get() == "doc" && a.value_str().is_some() {
                a.node.is_sugared_doc = true;
            }
            a.clean()
        }));
    });
    attrs
}

/// Record an external fully qualified name in the external_paths cache.
///
/// These names are used later on by HTML rendering to generate things like
/// source links back to the original item.
pub fn record_extern_fqn(cx: &core::DocContext,
                         did: ast::DefId,
                         kind: clean::TypeKind) {
    match cx.maybe_typed {
        core::Typed(ref tcx) => {
            let fqn = csearch::get_item_path(tcx, did);
            let fqn = fqn.move_iter().map(|i| i.to_string()).collect();
            cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
        }
        core::NotTyped(..) => {}
    }
}

pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
    let def = ty::lookup_trait_def(tcx, did);
    let methods = ty::trait_methods(tcx, did).clean();
    let provided = ty::provided_trait_methods(tcx, did);
    let mut methods = methods.move_iter().map(|meth| {
        if provided.iter().any(|a| a.def_id == meth.def_id) {
            clean::Provided(meth)
        } else {
            clean::Required(meth)
        }
    });
    let supertraits = ty::trait_supertraits(tcx, did);
    let mut parents = supertraits.iter().map(|i| {
        match i.clean() {
            clean::TraitBound(ty) => ty,
            clean::RegionBound => unreachable!()
        }
    });

    clean::Trait {
        generics: (&def.generics, subst::TypeSpace).clean(),
        methods: methods.collect(),
        parents: parents.collect()
    }
}

fn build_external_function(tcx: &ty::ctxt,
                           did: ast::DefId,
                           style: ast::FnStyle) -> clean::Function {
    let t = ty::lookup_item_type(tcx, did);
    clean::Function {
        decl: match ty::get(t.ty).sty {
            ty::ty_bare_fn(ref f) => (did, &f.sig).clean(),
            _ => fail!("bad function"),
        },
        generics: (&t.generics, subst::FnSpace).clean(),
        fn_style: style,
    }
}

fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct {
    use syntax::parse::token::special_idents::unnamed_field;

    let t = ty::lookup_item_type(tcx, did);
    let fields = ty::lookup_struct_fields(tcx, did);

    clean::Struct {
        struct_type: match fields.as_slice() {
            [] => doctree::Unit,
            [ref f] if f.name == unnamed_field.name => doctree::Newtype,
            [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple,
            _ => doctree::Plain,
        },
        generics: (&t.generics, subst::TypeSpace).clean(),
        fields: fields.iter().map(|f| f.clean()).collect(),
        fields_stripped: false,
    }
}

fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
    let t = ty::lookup_item_type(tcx, did);
    match ty::get(t.ty).sty {
        ty::ty_enum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => {
            return clean::EnumItem(clean::Enum {
                generics: (&t.generics, subst::TypeSpace).clean(),
                variants_stripped: false,
                variants: ty::enum_variants(tcx, edid).clean(),
            })
        }
        _ => {}
    }

    clean::TypedefItem(clean::Typedef {
        type_: t.ty.clean(),
        generics: (&t.generics, subst::TypeSpace).clean(),
    })
}

fn build_impls(cx: &core::DocContext,
               tcx: &ty::ctxt,
               did: ast::DefId) -> Vec<clean::Item> {
    ty::populate_implementations_for_type_if_necessary(tcx, did);
    let mut impls = Vec::new();

    match tcx.inherent_impls.borrow().find(&did) {
        None => {}
        Some(i) => {
            impls.extend(i.borrow().iter().map(|&did| { build_impl(cx, tcx, did) }));
        }
    }

    // If this is the first time we've inlined something from this crate, then
    // we inline *all* impls from the crate into this crate. Note that there's
    // currently no way for us to filter this based on type, and we likely need
    // many impls for a variety of reasons.
    //
    // Primarily, the impls will be used to populate the documentation for this
    // type being inlined, but impls can also be used when generating
    // documentation for primitives (no way to find those specifically).
    if cx.populated_crate_impls.borrow_mut().insert(did.krate) {
        csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
                                              did.krate,
                                              |def, _, _| {
            populate_impls(cx, tcx, def, &mut impls)
        });

        fn populate_impls(cx: &core::DocContext,
                          tcx: &ty::ctxt,
                          def: decoder::DefLike,
                          impls: &mut Vec<Option<clean::Item>>) {
            match def {
                decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)),
                decoder::DlDef(def::DefMod(did)) => {
                    csearch::each_child_of_item(&tcx.sess.cstore,
                                                did,
                                                |def, _, _| {
                        populate_impls(cx, tcx, def, impls)
                    })
                }
                _ => {}
            }
        }
    }

    impls.move_iter().filter_map(|a| a).collect()
}

fn build_impl(cx: &core::DocContext,
              tcx: &ty::ctxt,
              did: ast::DefId) -> Option<clean::Item> {
    if !cx.inlined.borrow_mut().get_mut_ref().insert(did) {
        return None
    }

    let associated_trait = csearch::get_impl_trait(tcx, did);
    // If this is an impl for a #[doc(hidden)] trait, be sure to not inline it.
    match associated_trait {
        Some(ref t) => {
            let trait_attrs = load_attrs(tcx, t.def_id);
            if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
                return None
            }
        }
        None => {}
    }

    let attrs = load_attrs(tcx, did);
    let ty = ty::lookup_item_type(tcx, did);
    let methods = csearch::get_impl_methods(&tcx.sess.cstore,
                                            did).iter().filter_map(|did| {
        let method = ty::method(tcx, *did);
        if method.vis != ast::Public && associated_trait.is_none() {
            return None
        }
        let mut item = ty::method(tcx, *did).clean();
        item.inner = match item.inner.clone() {
            clean::TyMethodItem(clean::TyMethod {
                fn_style, decl, self_, generics
            }) => {
                clean::MethodItem(clean::Method {
                    fn_style: fn_style,
                    decl: decl,
                    self_: self_,
                    generics: generics,
                })
            }
            _ => fail!("not a tymethod"),
        };
        Some(item)
    }).collect();
    return Some(clean::Item {
        inner: clean::ImplItem(clean::Impl {
            derived: clean::detect_derived(attrs.as_slice()),
            trait_: associated_trait.clean().map(|bound| {
                match bound {
                    clean::TraitBound(ty) => ty,
                    clean::RegionBound => unreachable!(),
                }
            }),
            for_: ty.ty.clean(),
            generics: (&ty.generics, subst::TypeSpace).clean(),
            methods: methods,
        }),
        source: clean::Span::empty(),
        name: None,
        attrs: attrs,
        visibility: Some(ast::Inherited),
        stability: stability::lookup(tcx, did).clean(),
        def_id: did,
    });

    fn is_doc_hidden(a: &clean::Attribute) -> bool {
        match *a {
            clean::List(ref name, ref inner) if name.as_slice() == "doc" => {
                inner.iter().any(|a| {
                    match *a {
                        clean::Word(ref s) => s.as_slice() == "hidden",
                        _ => false,
                    }
                })
            }
            _ => false
        }
    }
}

fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
                did: ast::DefId) -> clean::Module {
    let mut items = Vec::new();

    // FIXME: this doesn't handle reexports inside the module itself.
    //        Should they be handled?
    csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| {
        if vis != ast::Public { return }
        match def {
            decoder::DlDef(def) => {
                match try_inline_def(cx, tcx, def) {
                    Some(i) => items.extend(i.move_iter()),
                    None => {}
                }
            }
            // All impls were inlined above
            decoder::DlImpl(..) => {}
            decoder::DlField => fail!("unimplemented field"),
        }
    });

    clean::Module {
        items: items,
        is_crate: false,
    }
}

fn build_static(tcx: &ty::ctxt,
                did: ast::DefId,
                mutable: bool) -> clean::Static {
    clean::Static {
        type_: ty::lookup_item_type(tcx, did).ty.clean(),
        mutability: if mutable {clean::Mutable} else {clean::Immutable},
        expr: "\n\n\n".to_string(), // trigger the "[definition]" links
    }
}
<commit_msg>rustdoc: Inline items from foreign mods<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for inlining external documentation into the current AST.

use syntax::ast;
use syntax::ast_util;
use syntax::attr::AttrMetaMethods;

use rustc::metadata::csearch;
use rustc::metadata::decoder;
use rustc::middle::def;
use rustc::middle::ty;
use rustc::middle::subst;
use rustc::middle::stability;

use core;
use doctree;
use clean;

use super::Clean;

/// Attempt to inline the definition of a local node id into this AST.
///
/// This function will fetch the definition of the id specified, and if it is
/// from another crate it will attempt to inline the documentation from the
/// other crate into this crate.
///
/// This is primarily used for `pub use` statements which are, in general,
/// implementation details. Inlining the documentation should help provide a
/// better experience when reading the documentation in this use case.
///
/// The returned value is `None` if the `id` could not be inlined, and `Some`
/// of a vector of items if it was successfully expanded.
pub fn try_inline(id: ast::NodeId, into: Option<ast::Ident>)
                  -> Option<Vec<clean::Item>> {
    let cx = ::ctxtkey.get().unwrap();
    let tcx = match cx.maybe_typed {
        core::Typed(ref tycx) => tycx,
        core::NotTyped(_) => return None,
    };
    let def = match tcx.def_map.borrow().find(&id) {
        Some(def) => *def,
        None => return None,
    };
    let did = def.def_id();
    if ast_util::is_local(did) { return None }
    try_inline_def(&**cx, tcx, def).map(|vec| {
        vec.move_iter().map(|mut item| {
            match into {
                Some(into) if item.name.is_some() => {
                    item.name = Some(into.clean());
                }
                _ => {}
            }
            item
        }).collect()
    })
}

fn try_inline_def(cx: &core::DocContext,
                  tcx: &ty::ctxt,
                  def: def::Def) -> Option<Vec<clean::Item>> {
    let mut ret = Vec::new();
    let did = def.def_id();
    let inner = match def {
        def::DefTrait(did) => {
            record_extern_fqn(cx, did, clean::TypeTrait);
            clean::TraitItem(build_external_trait(tcx, did))
        }
        def::DefFn(did, style) => {
            // If this function is a tuple struct constructor, we just skip it
            if csearch::get_tuple_struct_definition_if_ctor(&tcx.sess.cstore,
                                                            did).is_some() {
                return None
            }
            record_extern_fqn(cx, did, clean::TypeFunction);
            clean::FunctionItem(build_external_function(tcx, did, style))
        }
        def::DefStruct(did) => {
            record_extern_fqn(cx, did, clean::TypeStruct);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            clean::StructItem(build_struct(tcx, did))
        }
        def::DefTy(did) => {
            record_extern_fqn(cx, did, clean::TypeEnum);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            build_type(tcx, did)
        }
        // Assume that the enum type is reexported next to the variant, and
        // variants don't show up in documentation specially.
        def::DefVariant(..) => return Some(Vec::new()),
        def::DefMod(did) => {
            record_extern_fqn(cx, did, clean::TypeModule);
            clean::ModuleItem(build_module(cx, tcx, did))
        }
        def::DefStatic(did, mtbl) => {
            record_extern_fqn(cx, did, clean::TypeStatic);
            clean::StaticItem(build_static(tcx, did, mtbl))
        }
        _ => return None,
    };
    let fqn = csearch::get_item_path(tcx, did);
    cx.inlined.borrow_mut().get_mut_ref().insert(did);
    ret.push(clean::Item {
        source: clean::Span::empty(),
        name: Some(fqn.last().unwrap().to_string()),
        attrs: load_attrs(tcx, did),
        inner: inner,
        visibility: Some(ast::Public),
        stability: stability::lookup(tcx, did).clean(),
        def_id: did,
    });
    Some(ret)
}

pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec<clean::Attribute> {
    let mut attrs = Vec::new();
    csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
        attrs.extend(v.move_iter().map(|mut a| {
            // FIXME this isn't quite always true, it's just true about 99% of
            //       the time when dealing with documentation. For example,
            //       this would treat doc comments of the form `#[doc = "foo"]`
            //       incorrectly.
            if a.name().get() == "doc" && a.value_str().is_some() {
                a.node.is_sugared_doc = true;
            }
            a.clean()
        }));
    });
    attrs
}

/// Record an external fully qualified name in the external_paths cache.
///
/// These names are used later on by HTML rendering to generate things like
/// source links back to the original item.
pub fn record_extern_fqn(cx: &core::DocContext,
                         did: ast::DefId,
                         kind: clean::TypeKind) {
    match cx.maybe_typed {
        core::Typed(ref tcx) => {
            let fqn = csearch::get_item_path(tcx, did);
            let fqn = fqn.move_iter().map(|i| i.to_string()).collect();
            cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
        }
        core::NotTyped(..) => {}
    }
}

pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
    let def = ty::lookup_trait_def(tcx, did);
    let methods = ty::trait_methods(tcx, did).clean();
    let provided = ty::provided_trait_methods(tcx, did);
    let mut methods = methods.move_iter().map(|meth| {
        if provided.iter().any(|a| a.def_id == meth.def_id) {
            clean::Provided(meth)
        } else {
            clean::Required(meth)
        }
    });
    let supertraits = ty::trait_supertraits(tcx, did);
    let mut parents = supertraits.iter().map(|i| {
        match i.clean() {
            clean::TraitBound(ty) => ty,
            clean::RegionBound => unreachable!()
        }
    });

    clean::Trait {
        generics: (&def.generics, subst::TypeSpace).clean(),
        methods: methods.collect(),
        parents: parents.collect()
    }
}

fn build_external_function(tcx: &ty::ctxt,
                           did: ast::DefId,
                           style: ast::FnStyle) -> clean::Function {
    let t = ty::lookup_item_type(tcx, did);
    clean::Function {
        decl: match ty::get(t.ty).sty {
            ty::ty_bare_fn(ref f) => (did, &f.sig).clean(),
            _ => fail!("bad function"),
        },
        generics: (&t.generics, subst::FnSpace).clean(),
        fn_style: style,
    }
}

fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct {
    use syntax::parse::token::special_idents::unnamed_field;

    let t = ty::lookup_item_type(tcx, did);
    let fields = ty::lookup_struct_fields(tcx, did);

    clean::Struct {
        struct_type: match fields.as_slice() {
            [] => doctree::Unit,
            [ref f] if f.name == unnamed_field.name => doctree::Newtype,
            [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple,
            _ => doctree::Plain,
        },
        generics: (&t.generics, subst::TypeSpace).clean(),
        fields: fields.iter().map(|f| f.clean()).collect(),
        fields_stripped: false,
    }
}

fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
    let t = ty::lookup_item_type(tcx, did);
    match ty::get(t.ty).sty {
        ty::ty_enum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => {
            return clean::EnumItem(clean::Enum {
                generics: (&t.generics, subst::TypeSpace).clean(),
                variants_stripped: false,
                variants: ty::enum_variants(tcx, edid).clean(),
            })
        }
        _ => {}
    }

    clean::TypedefItem(clean::Typedef {
        type_: t.ty.clean(),
        generics: (&t.generics, subst::TypeSpace).clean(),
    })
}

fn build_impls(cx: &core::DocContext,
               tcx: &ty::ctxt,
               did: ast::DefId) -> Vec<clean::Item> {
    ty::populate_implementations_for_type_if_necessary(tcx, did);
    let mut impls = Vec::new();

    match tcx.inherent_impls.borrow().find(&did) {
        None => {}
        Some(i) => {
            impls.extend(i.borrow().iter().map(|&did| { build_impl(cx, tcx, did) }));
        }
    }

    // If this is the first time we've inlined something from this crate, then
    // we inline *all* impls from the crate into this crate. Note that there's
    // currently no way for us to filter this based on type, and we likely need
    // many impls for a variety of reasons.
    //
    // Primarily, the impls will be used to populate the documentation for this
    // type being inlined, but impls can also be used when generating
    // documentation for primitives (no way to find those specifically).
    if cx.populated_crate_impls.borrow_mut().insert(did.krate) {
        csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
                                              did.krate,
                                              |def, _, _| {
            populate_impls(cx, tcx, def, &mut impls)
        });

        fn populate_impls(cx: &core::DocContext,
                          tcx: &ty::ctxt,
                          def: decoder::DefLike,
                          impls: &mut Vec<Option<clean::Item>>) {
            match def {
                decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)),
                decoder::DlDef(def::DefMod(did)) => {
                    csearch::each_child_of_item(&tcx.sess.cstore,
                                                did,
                                                |def, _, _| {
                        populate_impls(cx, tcx, def, impls)
                    })
                }
                _ => {}
            }
        }
    }

    impls.move_iter().filter_map(|a| a).collect()
}

fn build_impl(cx: &core::DocContext,
              tcx: &ty::ctxt,
              did: ast::DefId) -> Option<clean::Item> {
    if !cx.inlined.borrow_mut().get_mut_ref().insert(did) {
        return None
    }

    let associated_trait = csearch::get_impl_trait(tcx, did);
    // If this is an impl for a #[doc(hidden)] trait, be sure to not inline it.
    match associated_trait {
        Some(ref t) => {
            let trait_attrs = load_attrs(tcx, t.def_id);
            if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
                return None
            }
        }
        None => {}
    }

    let attrs = load_attrs(tcx, did);
    let ty = ty::lookup_item_type(tcx, did);
    let methods = csearch::get_impl_methods(&tcx.sess.cstore,
                                            did).iter().filter_map(|did| {
        let method = ty::method(tcx, *did);
        if method.vis != ast::Public && associated_trait.is_none() {
            return None
        }
        let mut item = ty::method(tcx, *did).clean();
        item.inner = match item.inner.clone() {
            clean::TyMethodItem(clean::TyMethod {
                fn_style, decl, self_, generics
            }) => {
                clean::MethodItem(clean::Method {
                    fn_style: fn_style,
                    decl: decl,
                    self_: self_,
                    generics: generics,
                })
            }
            _ => fail!("not a tymethod"),
        };
        Some(item)
    }).collect();
    return Some(clean::Item {
        inner: clean::ImplItem(clean::Impl {
            derived: clean::detect_derived(attrs.as_slice()),
            trait_: associated_trait.clean().map(|bound| {
                match bound {
                    clean::TraitBound(ty) => ty,
                    clean::RegionBound => unreachable!(),
                }
            }),
            for_: ty.ty.clean(),
            generics: (&ty.generics, subst::TypeSpace).clean(),
            methods: methods,
        }),
        source: clean::Span::empty(),
        name: None,
        attrs: attrs,
        visibility: Some(ast::Inherited),
        stability: stability::lookup(tcx, did).clean(),
        def_id: did,
    });

    fn is_doc_hidden(a: &clean::Attribute) -> bool {
        match *a {
            clean::List(ref name, ref inner) if name.as_slice() == "doc" => {
                inner.iter().any(|a| {
                    match *a {
                        clean::Word(ref s) => s.as_slice() == "hidden",
                        _ => false,
                    }
                })
            }
            _ => false
        }
    }
}

fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
                did: ast::DefId) -> clean::Module {
    let mut items = Vec::new();
    fill_in(cx, tcx, did, &mut items);
    return clean::Module {
        items: items,
        is_crate: false,
    };

    // FIXME: this doesn't handle reexports inside the module itself.
    //        Should they be handled?
    fn fill_in(cx: &core::DocContext, tcx: &ty::ctxt, did: ast::DefId,
               items: &mut Vec<clean::Item>) {
        csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| {
            match def {
                decoder::DlDef(def::DefForeignMod(did)) => {
                    fill_in(cx, tcx, did, items);
                }
                decoder::DlDef(def) if vis == ast::Public => {
                    match try_inline_def(cx, tcx, def) {
                        Some(i) => items.extend(i.move_iter()),
                        None => {}
                    }
                }
                decoder::DlDef(..) => {}
                // All impls were inlined above
                decoder::DlImpl(..) => {}
                decoder::DlField => fail!("unimplemented field"),
            }
        });
    }
}

fn build_static(tcx: &ty::ctxt,
                did: ast::DefId,
                mutable: bool) -> clean::Static {
    clean::Static {
        type_: ty::lookup_item_type(tcx, did).ty.clean(),
        mutability: if mutable {clean::Mutable} else {clean::Immutable},
        expr: "\n\n\n".to_string(), // trigger the "[definition]" links
    }
}
<|endoftext|>