<commit_before>//! The Mach-o, mostly zero-copy, binary format parser and raw struct definitions
use core::fmt;

use scroll::{self, Pread};

use error;
use container;

pub mod header;
pub mod constants;
pub mod fat;
pub mod load_command;
pub mod symbols;
pub mod exports;
pub mod imports;
pub mod bind_opcodes;
pub mod relocation;

pub use self::constants::cputype as cputype;

/// Returns a big endian magical number
pub fn peek(bytes: &[u8], offset: usize) -> error::Result<u32> {
    Ok(bytes.pread_with::<u32>(offset, scroll::BE)?)
}

#[derive(Debug)]
/// A cross-platform, zero-copy, endian-aware, 32/64 bit Mach-o binary parser
pub struct MachO<'a> {
    /// The mach-o header
    pub header: header::Header,
    /// The load commands tell the kernel and dynamic linker how to use/interpret this binary
    pub load_commands: Vec<load_command::LoadCommand>,
    /// The load command "segments" - typically the pieces of the binary that are loaded into memory
    pub segments: load_command::Segments<'a>,
    /// The "Nlist" style symbols in this binary - strippable
    pub symbols: Option<symbols::Symbols<'a>>,
    /// The dylibs this library depends on
    pub libs: Vec<&'a str>,
    /// The entry point, 0 if none
    pub entry: u64,
    /// The name of the dylib, if any
    pub name: Option<&'a str>,
    /// Are we a little-endian binary?
    pub little_endian: bool,
    /// Are we a 64-bit binary
    pub is_64: bool,
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

impl<'a> MachO<'a> {
    pub fn is_object_file(&self) -> bool {
        self.header.filetype == header::MH_OBJECT
    }
    pub fn symbols(&self) -> symbols::SymbolIterator<'a> {
        if let &Some(ref symbols) = &self.symbols {
            symbols.into_iter()
        } else {
            symbols::SymbolIterator::default()
        }
    }
    /// Return the exported symbols in this binary (if any)
    pub fn exports(&self) -> error::Result<Vec<exports::Export>> {
        if let Some(ref trie) = self.export_trie {
            trie.exports(self.libs.as_slice())
        } else {
            Ok(vec![])
        }
    }
    /// Return the imported symbols in this binary that dyld knows about (if any)
    pub fn imports(&self) -> error::Result<Vec<imports::Import>> {
        if let Some(ref interpreter) = self.bind_interpreter {
            interpreter.imports(self.libs.as_slice(), self.segments.as_slice(), &self.ctx)
        } else {
            Ok(vec![])
        }
    }
    /// Parses the Mach-o binary from `bytes` at `offset`
    pub fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<MachO<'a>> {
        let offset = &mut offset;
        let header: header::Header = bytes.pread(*offset)?;
        let ctx = header.ctx()?;
        let little_endian = ctx.le.is_little();
        let is_64 = ctx.container.is_big();
        *offset = *offset + header.size();
        let ncmds = header.ncmds;
        let mut cmds: Vec<load_command::LoadCommand> = Vec::with_capacity(ncmds);
        let mut symbols = None;
        let mut libs = vec!["self"];
        let mut export_trie = None;
        let mut bind_interpreter = None;
        let mut entry = 0x0;
        let mut name = None;
        let mut segments = load_command::Segments::new(ctx);
        for _ in 0..ncmds {
            let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?;
            match cmd.command {
                load_command::CommandVariant::Segment32(command) => {
                    segments.push(load_command::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(load_command::Segment::from_64(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Symtab(command) => {
                    symbols = Some(symbols::Symbols::parse(bytes, &command, ctx)?);
                },
                  load_command::CommandVariant::LoadDylib      (command)
                | load_command::CommandVariant::LoadUpwardDylib(command)
                | load_command::CommandVariant::ReexportDylib  (command)
                | load_command::CommandVariant::LazyLoadDylib  (command) => {
                    let lib = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs.push(lib);
                },
                  load_command::CommandVariant::DyldInfo    (command)
                | load_command::CommandVariant::DyldInfoOnly(command) => {
                    export_trie = Some(exports::ExportTrie::new(bytes, &command));
                    bind_interpreter = Some(imports::BindInterpreter::new(bytes, &command));
                },
                load_command::CommandVariant::Unixthread(command) => {
                    entry = command.thread_state.eip as u64;
                },
                load_command::CommandVariant::Main(command) => {
                    entry = command.entryoff;
                },
                load_command::CommandVariant::IdDylib(command) => {
                    let id = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs[0] = id;
                    name = Some(id);
                },
                _ => ()
            }
            cmds.push(cmd)
        }
        Ok(MachO {
            header: header,
            load_commands: cmds,
            segments: segments,
            symbols: symbols,
            libs: libs,
            export_trie: export_trie,
            bind_interpreter: bind_interpreter,
            entry: entry,
            name: name,
            ctx: ctx,
            is_64: is_64,
            little_endian: little_endian,
        })
    }
}

#[cfg(feature = "std")]
/// A Mach-o multi architecture (Fat) binary container
pub struct MultiArch<'a> {
    data: &'a [u8],
    start: usize,
    pub narches: usize,
}

/// Iterator over the fat architecture headers in a `MultiArch` container
pub struct FatArchIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for FatArchIterator<'a> {
    type Item = error::Result<fat::FatArch>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let offset = (self.index * fat::SIZEOF_FAT_ARCH) + self.start;
            let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE).map_err(|e| e.into());
            self.index += 1;
            Some(arch)
        }
    }
}

/// Iterator over every `MachO` binary contained in this `MultiArch` container
pub struct MachOIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for MachOIterator<'a> {
    type Item = error::Result<MachO<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let index = self.index;
            let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
            self.index += 1;
            match self.data.pread_with::<fat::FatArch>(offset, scroll::BE) {
                Ok(arch) => {
                    let bytes = arch.slice(self.data);
                    let binary = MachO::parse(bytes, 0);
                    Some(binary)
                },
                Err(e) => Some(Err(e.into()))
            }
        }
    }
}

impl<'a, 'b> IntoIterator for &'b MultiArch<'a> {
    type Item = error::Result<MachO<'a>>;
    type IntoIter = MachOIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        MachOIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
}

#[cfg(feature = "std")]
impl<'a> MultiArch<'a> {
    /// Lazily construct `Self`
    pub fn new(bytes: &'a [u8]) -> error::Result<Self> {
        let header = fat::FatHeader::parse(bytes)?;
        Ok(MultiArch {
            data: bytes,
            start: fat::SIZEOF_FAT_HEADER,
            narches: header.nfat_arch as usize
        })
    }
    /// Iterate every fat arch header
    pub fn iter_arches(&self) -> FatArchIterator {
        FatArchIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
    /// Return all the architectures in this binary
    pub fn arches(&self) -> error::Result<Vec<fat::FatArch>> {
        let mut arches = Vec::with_capacity(self.narches);
        for arch in self.iter_arches() {
            arches.push(arch?);
        }
        Ok(arches)
    }
    /// Try to get the Mach-o binary at `index`
    pub fn get(&self, index: usize) -> error::Result<MachO> {
        if index >= self.narches {
            return Err(error::Error::Malformed(format!("Requested the {}-th binary, but there are only {} architectures in this container", index, self.narches).into()))
        }
        let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
        let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE)?;
        let bytes = arch.slice(self.data);
        Ok(MachO::parse(bytes, 0)?)
    }

    pub fn find<F: (Fn(error::Result<fat::FatArch>) -> bool)>(&'a self, f: F) -> Option<error::Result<MachO<'a>>> {
        for (i, arch) in self.iter_arches().enumerate() {
            if f(arch) {
                return Some(self.get(i));
            }
        }
        None
    }
    /// Try and find the `cputype` in `Self`, if there is one
    pub fn find_cputype(&self, cputype: u32) -> error::Result<Option<fat::FatArch>> {
        for arch in self.iter_arches() {
            let arch = arch?;
            if arch.cputype == cputype { return Ok(Some(arch)) }
        }
        Ok(None)
    }
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MultiArch<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MultiArch")
            .field("arches",  &self.arches().unwrap())
            .field("data",    &self.data.len())
            .finish()
    }
}

#[derive(Debug)]
/// Either a collection of multiple architectures, or a single mach-o binary
pub enum Mach<'a> {
    /// A "fat" multi-architecture binary container
    Fat(MultiArch<'a>),
    /// A regular Mach-o binary
    Binary(MachO<'a>)
}

impl<'a> Mach<'a> {
    /// Parse from `bytes` either a multi-arch binary or a regular mach-o binary
    pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
        let size = bytes.len();
        if size < 4 {
            let error = error::Error::Malformed(
                                       format!("size is smaller than a magical number"));
            return Err(error);
        }
        let magic = peek(&bytes, 0)?;
        match magic {
            fat::FAT_MAGIC => {
                let multi = MultiArch::new(bytes)?;
                Ok(Mach::Fat(multi))
            },
            // we're a regular binary
            _ => {
                let binary = MachO::parse(bytes, 0)?;
                Ok(Mach::Binary(binary))
            }
        }
    }
}
<commit_msg>Fix mach::MultiArch::get() return value lifetime (#41)<commit_after>//! The Mach-o, mostly zero-copy, binary format parser and raw struct definitions
use core::fmt;

use scroll::{self, Pread};

use error;
use container;

pub mod header;
pub mod constants;
pub mod fat;
pub mod load_command;
pub mod symbols;
pub mod exports;
pub mod imports;
pub mod bind_opcodes;
pub mod relocation;

pub use self::constants::cputype as cputype;

/// Returns a big endian magical number
pub fn peek(bytes: &[u8], offset: usize) -> error::Result<u32> {
    Ok(bytes.pread_with::<u32>(offset, scroll::BE)?)
}

#[derive(Debug)]
/// A cross-platform, zero-copy, endian-aware, 32/64 bit Mach-o binary parser
pub struct MachO<'a> {
    /// The mach-o header
    pub header: header::Header,
    /// The load commands tell the kernel and dynamic linker how to use/interpret this binary
    pub load_commands: Vec<load_command::LoadCommand>,
    /// The load command "segments" - typically the pieces of the binary that are loaded into memory
    pub segments: load_command::Segments<'a>,
    /// The "Nlist" style symbols in this binary - strippable
    pub symbols: Option<symbols::Symbols<'a>>,
    /// The dylibs this library depends on
    pub libs: Vec<&'a str>,
    /// The entry point, 0 if none
    pub entry: u64,
    /// The name of the dylib, if any
    pub name: Option<&'a str>,
    /// Are we a little-endian binary?
    pub little_endian: bool,
    /// Are we a 64-bit binary
    pub is_64: bool,
    ctx: container::Ctx,
    export_trie: Option<exports::ExportTrie<'a>>,
    bind_interpreter: Option<imports::BindInterpreter<'a>>,
}

impl<'a> MachO<'a> {
    pub fn is_object_file(&self) -> bool {
        self.header.filetype == header::MH_OBJECT
    }
    pub fn symbols(&self) -> symbols::SymbolIterator<'a> {
        if let &Some(ref symbols) = &self.symbols {
            symbols.into_iter()
        } else {
            symbols::SymbolIterator::default()
        }
    }
    /// Return the exported symbols in this binary (if any)
    pub fn exports(&self) -> error::Result<Vec<exports::Export>> {
        if let Some(ref trie) = self.export_trie {
            trie.exports(self.libs.as_slice())
        } else {
            Ok(vec![])
        }
    }
    /// Return the imported symbols in this binary that dyld knows about (if any)
    pub fn imports(&self) -> error::Result<Vec<imports::Import>> {
        if let Some(ref interpreter) = self.bind_interpreter {
            interpreter.imports(self.libs.as_slice(), self.segments.as_slice(), &self.ctx)
        } else {
            Ok(vec![])
        }
    }
    /// Parses the Mach-o binary from `bytes` at `offset`
    pub fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<MachO<'a>> {
        let offset = &mut offset;
        let header: header::Header = bytes.pread(*offset)?;
        let ctx = header.ctx()?;
        let little_endian = ctx.le.is_little();
        let is_64 = ctx.container.is_big();
        *offset = *offset + header.size();
        let ncmds = header.ncmds;
        let mut cmds: Vec<load_command::LoadCommand> = Vec::with_capacity(ncmds);
        let mut symbols = None;
        let mut libs = vec!["self"];
        let mut export_trie = None;
        let mut bind_interpreter = None;
        let mut entry = 0x0;
        let mut name = None;
        let mut segments = load_command::Segments::new(ctx);
        for _ in 0..ncmds {
            let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?;
            match cmd.command {
                load_command::CommandVariant::Segment32(command) => {
                    segments.push(load_command::Segment::from_32(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Segment64(command) => {
                    segments.push(load_command::Segment::from_64(bytes.as_ref(), &command, cmd.offset, ctx))
                },
                load_command::CommandVariant::Symtab(command) => {
                    symbols = Some(symbols::Symbols::parse(bytes, &command, ctx)?);
                },
                  load_command::CommandVariant::LoadDylib      (command)
                | load_command::CommandVariant::LoadUpwardDylib(command)
                | load_command::CommandVariant::ReexportDylib  (command)
                | load_command::CommandVariant::LazyLoadDylib  (command) => {
                    let lib = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs.push(lib);
                },
                  load_command::CommandVariant::DyldInfo    (command)
                | load_command::CommandVariant::DyldInfoOnly(command) => {
                    export_trie = Some(exports::ExportTrie::new(bytes, &command));
                    bind_interpreter = Some(imports::BindInterpreter::new(bytes, &command));
                },
                load_command::CommandVariant::Unixthread(command) => {
                    entry = command.thread_state.eip as u64;
                },
                load_command::CommandVariant::Main(command) => {
                    entry = command.entryoff;
                },
                load_command::CommandVariant::IdDylib(command) => {
                    let id = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
                    libs[0] = id;
                    name = Some(id);
                },
                _ => ()
            }
            cmds.push(cmd)
        }
        Ok(MachO {
            header: header,
            load_commands: cmds,
            segments: segments,
            symbols: symbols,
            libs: libs,
            export_trie: export_trie,
            bind_interpreter: bind_interpreter,
            entry: entry,
            name: name,
            ctx: ctx,
            is_64: is_64,
            little_endian: little_endian,
        })
    }
}

#[cfg(feature = "std")]
/// A Mach-o multi architecture (Fat) binary container
pub struct MultiArch<'a> {
    data: &'a [u8],
    start: usize,
    pub narches: usize,
}

/// Iterator over the fat architecture headers in a `MultiArch` container
pub struct FatArchIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for FatArchIterator<'a> {
    type Item = error::Result<fat::FatArch>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let offset = (self.index * fat::SIZEOF_FAT_ARCH) + self.start;
            let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE).map_err(|e| e.into());
            self.index += 1;
            Some(arch)
        }
    }
}

/// Iterator over every `MachO` binary contained in this `MultiArch` container
pub struct MachOIterator<'a> {
    index: usize,
    data: &'a[u8],
    narches: usize,
    start: usize,
}

impl<'a> Iterator for MachOIterator<'a> {
    type Item = error::Result<MachO<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.narches {
            None
        } else {
            let index = self.index;
            let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
            self.index += 1;
            match self.data.pread_with::<fat::FatArch>(offset, scroll::BE) {
                Ok(arch) => {
                    let bytes = arch.slice(self.data);
                    let binary = MachO::parse(bytes, 0);
                    Some(binary)
                },
                Err(e) => Some(Err(e.into()))
            }
        }
    }
}

impl<'a, 'b> IntoIterator for &'b MultiArch<'a> {
    type Item = error::Result<MachO<'a>>;
    type IntoIter = MachOIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        MachOIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
}

#[cfg(feature = "std")]
impl<'a> MultiArch<'a> {
    /// Lazily construct `Self`
    pub fn new(bytes: &'a [u8]) -> error::Result<Self> {
        let header = fat::FatHeader::parse(bytes)?;
        Ok(MultiArch {
            data: bytes,
            start: fat::SIZEOF_FAT_HEADER,
            narches: header.nfat_arch as usize
        })
    }
    /// Iterate every fat arch header
    pub fn iter_arches(&self) -> FatArchIterator {
        FatArchIterator {
            index: 0,
            data: self.data,
            narches: self.narches,
            start: self.start,
        }
    }
    /// Return all the architectures in this binary
    pub fn arches(&self) -> error::Result<Vec<fat::FatArch>> {
        let mut arches = Vec::with_capacity(self.narches);
        for arch in self.iter_arches() {
            arches.push(arch?);
        }
        Ok(arches)
    }
    /// Try to get the Mach-o binary at `index`
    pub fn get(&self, index: usize) -> error::Result<MachO<'a>> {
        if index >= self.narches {
            return Err(error::Error::Malformed(format!("Requested the {}-th binary, but there are only {} architectures in this container", index, self.narches).into()))
        }
        let offset = (index * fat::SIZEOF_FAT_ARCH) + self.start;
        let arch = self.data.pread_with::<fat::FatArch>(offset, scroll::BE)?;
        let bytes = arch.slice(self.data);
        Ok(MachO::parse(bytes, 0)?)
    }

    pub fn find<F: (Fn(error::Result<fat::FatArch>) -> bool)>(&'a self, f: F) -> Option<error::Result<MachO<'a>>> {
        for (i, arch) in self.iter_arches().enumerate() {
            if f(arch) {
                return Some(self.get(i));
            }
        }
        None
    }
    /// Try and find the `cputype` in `Self`, if there is one
    pub fn find_cputype(&self, cputype: u32) -> error::Result<Option<fat::FatArch>> {
        for arch in self.iter_arches() {
            let arch = arch?;
            if arch.cputype == cputype { return Ok(Some(arch)) }
        }
        Ok(None)
    }
}

#[cfg(feature = "std")]
impl<'a> fmt::Debug for MultiArch<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("MultiArch")
            .field("arches",  &self.arches().unwrap())
            .field("data",    &self.data.len())
            .finish()
    }
}

#[derive(Debug)]
/// Either a collection of multiple architectures, or a single mach-o binary
pub enum Mach<'a> {
    /// A "fat" multi-architecture binary container
    Fat(MultiArch<'a>),
    /// A regular Mach-o binary
    Binary(MachO<'a>)
}

impl<'a> Mach<'a> {
    /// Parse from `bytes` either a multi-arch binary or a regular mach-o binary
    pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
        let size = bytes.len();
        if size < 4 {
            let error = error::Error::Malformed(
                                       format!("size is smaller than a magical number"));
            return Err(error);
        }
        let magic = peek(&bytes, 0)?;
        match magic {
            fat::FAT_MAGIC => {
                let multi = MultiArch::new(bytes)?;
                Ok(Mach::Fat(multi))
            },
            // we're a regular binary
            _ => {
                let binary = MachO::parse(bytes, 0)?;
                Ok(Mach::Binary(binary))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::num::{Zero, One};
use vec::Vec3;
use mat::{Mat1, Mat2, Mat3, Inv, Row};
use mat;

// some specializations:
impl<N: Num + Clone>
Inv for Mat1<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat1<N>> {
        let mut res : Mat1<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        if self.m11.is_zero() {
            false
        }
        else {
            let _1: N = One::one();
            self.m11 = _1 / self.m11;
            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat2<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat2<N>> {
        let mut res : Mat2<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let det = self.m11 * self.m22 - self.m21 * self.m12;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat2::new(
                self.m22 / det , -self.m12 / det,
                -self.m21 / det, self.m11 / det);

            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat3<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat3<N>> {
        let mut res = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let minor_m12_m23 = self.m22 * self.m33 - self.m32 * self.m23;
        let minor_m11_m23 = self.m21 * self.m33 - self.m31 * self.m23;
        let minor_m11_m22 = self.m21 * self.m32 - self.m31 * self.m22;

        let det = self.m11 * minor_m12_m23
                  - self.m12 * minor_m11_m23
                  + self.m13 * minor_m11_m22;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat3::new(
                (minor_m12_m23 / det),
                ((self.m13 * self.m32 - self.m33 * self.m12) / det),
                ((self.m12 * self.m23 - self.m22 * self.m13) / det),

                (-minor_m11_m23 / det),
                ((self.m11 * self.m33 - self.m31 * self.m13) / det),
                ((self.m13 * self.m21 - self.m23 * self.m11) / det),

                (minor_m11_m22  / det),
                ((self.m12 * self.m31 - self.m32 * self.m11) / det),
                ((self.m11 * self.m22 - self.m21 * self.m12) / det)
                );

            true
        }
    }
}

impl<N: Clone> Row<Vec3<N>> for Mat3<N> {
    #[inline]
    fn row(&self, i: uint) -> Vec3<N> {
        match i {
            0 => Vec3::new(self.m11.clone(), self.m12.clone(), self.m13.clone()),
            1 => Vec3::new(self.m21.clone(), self.m22.clone(), self.m23.clone()),
            2 => Vec3::new(self.m31.clone(), self.m32.clone(), self.m33.clone()),
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")
        }
    }

    #[inline]
    fn set_row(&mut self, i: uint, r: Vec3<N>) {
        match i {
            0 => {
                self.m11 = r.x.clone();
                self.m12 = r.y.clone();
                self.m13 = r.z;
            },
            1 => {
                self.m21 = r.x.clone();
                self.m22 = r.y.clone();
                self.m23 = r.z;
            },
            2 => {
                self.m31 = r.x.clone();
                self.m32 = r.y.clone();
                self.m33 = r.z;
            },
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")

        }
    }
}

// FIXME: move this to another file?
impl<N: Real + NumCast + Zero + One> mat::Mat4<N> {
    /// Computes a projection matrix given the frustrum near plane width, height, the field of
    /// view, and the distance to the clipping planes (`znear` and `zfar`).
    pub fn projection(width: N, height: N, fov: N, znear: N, zfar: N) -> mat::Mat4<N> {
        let aspect = width / height;

        let _1: N = One::one();
        let sy    = _1 / (fov * NumCast::from(0.5)).tan();
        let sx    = -sy / aspect;
        let sz    = -(zfar + znear) / (znear - zfar);
        let tz    = zfar * znear * NumCast::from(2.0) / (znear - zfar);

        mat::Mat4::new(
            sx,           Zero::zero(), Zero::zero(), Zero::zero(),
            Zero::zero(), sy,           Zero::zero(), Zero::zero(),
            Zero::zero(), Zero::zero(), sz,           tz,
            Zero::zero(), Zero::zero(), One::one(),   Zero::zero()
            )
    }
}
<commit_msg>Rename `Mat4::projection` to `mat4::new_perspective`.<commit_after>use std::num::{Zero, One};
use vec::Vec3;
use mat::{Mat1, Mat2, Mat3, Inv, Row};
use mat;

// some specializations:
impl<N: Num + Clone>
Inv for Mat1<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat1<N>> {
        let mut res : Mat1<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        if self.m11.is_zero() {
            false
        }
        else {
            let _1: N = One::one();
            self.m11 = _1 / self.m11;
            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat2<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat2<N>> {
        let mut res : Mat2<N> = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let det = self.m11 * self.m22 - self.m21 * self.m12;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat2::new(
                self.m22 / det , -self.m12 / det,
                -self.m21 / det, self.m11 / det);

            true
        }
    }
}

impl<N: Num + Clone>
Inv for Mat3<N> {
    #[inline]
    fn inverse(&self) -> Option<Mat3<N>> {
        let mut res = self.clone();

        if res.inplace_inverse() {
            Some(res)
        }
        else {
            None
        }
    }

    #[inline]
    fn inplace_inverse(&mut self) -> bool {
        let minor_m12_m23 = self.m22 * self.m33 - self.m32 * self.m23;
        let minor_m11_m23 = self.m21 * self.m33 - self.m31 * self.m23;
        let minor_m11_m22 = self.m21 * self.m32 - self.m31 * self.m22;

        let det = self.m11 * minor_m12_m23
                  - self.m12 * minor_m11_m23
                  + self.m13 * minor_m11_m22;

        if det.is_zero() {
            false
        }
        else {
            *self = Mat3::new(
                (minor_m12_m23 / det),
                ((self.m13 * self.m32 - self.m33 * self.m12) / det),
                ((self.m12 * self.m23 - self.m22 * self.m13) / det),

                (-minor_m11_m23 / det),
                ((self.m11 * self.m33 - self.m31 * self.m13) / det),
                ((self.m13 * self.m21 - self.m23 * self.m11) / det),

                (minor_m11_m22  / det),
                ((self.m12 * self.m31 - self.m32 * self.m11) / det),
                ((self.m11 * self.m22 - self.m21 * self.m12) / det)
                );

            true
        }
    }
}

impl<N: Clone> Row<Vec3<N>> for Mat3<N> {
    #[inline]
    fn row(&self, i: uint) -> Vec3<N> {
        match i {
            0 => Vec3::new(self.m11.clone(), self.m12.clone(), self.m13.clone()),
            1 => Vec3::new(self.m21.clone(), self.m22.clone(), self.m23.clone()),
            2 => Vec3::new(self.m31.clone(), self.m32.clone(), self.m33.clone()),
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")
        }
    }

    #[inline]
    fn set_row(&mut self, i: uint, r: Vec3<N>) {
        match i {
            0 => {
                self.m11 = r.x.clone();
                self.m12 = r.y.clone();
                self.m13 = r.z;
            },
            1 => {
                self.m21 = r.x.clone();
                self.m22 = r.y.clone();
                self.m23 = r.z;
            },
            2 => {
                self.m31 = r.x.clone();
                self.m32 = r.y.clone();
                self.m33 = r.z;
            },
            _ => fail!("Index out of range: 3d matrices do not have " + i.to_str() + " rows.")

        }
    }
}

// FIXME: move this to another file?
impl<N: Real + NumCast + Zero + One> mat::Mat4<N> {
    /// Computes a projection matrix given the frustrum near plane width, height, the field of
    /// view, and the distance to the clipping planes (`znear` and `zfar`).
    pub fn new_perspective(width: N, height: N, fov: N, znear: N, zfar: N) -> mat::Mat4<N> {
        let aspect = width / height;

        let _1: N = One::one();
        let sy    = _1 / (fov * NumCast::from(0.5)).tan();
        let sx    = -sy / aspect;
        let sz    = -(zfar + znear) / (znear - zfar);
        let tz    = zfar * znear * NumCast::from(2.0) / (znear - zfar);

        mat::Mat4::new(
            sx,           Zero::zero(), Zero::zero(), Zero::zero(),
            Zero::zero(), sy,           Zero::zero(), Zero::zero(),
            Zero::zero(), Zero::zero(), sz,           tz,
            Zero::zero(), Zero::zero(), One::one(),   Zero::zero()
            )
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();
    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some((ub - lb + 1))
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if char == *c {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    let mut last_index = first_index + 1;
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if x == c {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
        } else {
            return None;
        }
    }
    return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<commit_msg>Refactor find_end_of_match<commit_after>use std::ascii::AsciiExt;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();
    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some(ub - lb + 1)
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if char == *c {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    if let Some(indices) = get_match_indices(string, rest_of_query, first_index) {
        Some(indices[indices.len() - 1])
    } else {
        None
    }
}

fn get_match_indices(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<Vec<usize>> {
    let mut ret = Vec::new();
    let mut last_index = first_index + 1;
    ret.push(first_index);
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if x == c {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
            ret.push(last_index - 1);
        } else {
            return None;
        }
    }
    Some(ret)
}

#[test]
fn get_match_indices_test() {
    assert_eq!(get_match_indices(chars!("asdf"), chars!("sdf"), 0).unwrap(), vec![0, 1, 2, 3]);
    assert_eq!(get_match_indices(chars!("aoeuasdf"), chars!("sdf"), 4).unwrap(), vec![4, 5, 6, 7]);
    assert_eq!(get_match_indices(chars!(" a s d f"), chars!("sdf"), 1).unwrap(), vec![1, 3, 5, 7]);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;

use self::parser_combinators::{try, between, spaces, string, parser, many, many1, digit, any_char, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;
use std::str::FromStr;
use std::num::FromStrRadix;

/// Parser for signed integer constants.
///
/// This parses signed integer constants in decimal and hexadecimal.
///
/// TODO: add support for octal
/// TODO: add support for binary
/// TODO: add support for R6RS exponents
fn sint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {

        fn hex_string<I>(input: State<I>) -> ParseResult<isize, I>
            where I: Stream<Item=char> {
                (satisfy(|c| c == '#')
                    .and(satisfy(|c| c == 'x' || c == 'X')))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    .map(|x| {
                        isize::from_str_radix(
                            x.iter()
                             .fold(
                                String::new(),
                                |mut s: String, i| { s.push(*i); s })
                             .as_slice(),
                        16).unwrap()
                    }).parse_state(input)
        }

        fn dec_string<I>(input: State<I>) -> ParseResult<isize, I>
            where I: Stream<Item=char> {
                optional(satisfy(|c| c == '#')
                    .and(satisfy(|c| c == 'd' || c == 'D')))
                .with(many1::<Vec<_>, _>(digit())
                    .map(|x| isize::from_str(x.iter().fold(
                        String::new(), |mut s: String, i| { s.push(*i); s })
                        .as_slice()
                    ).unwrap()
                    )).parse_state(input)
            }

        optional(satisfy(|c| c == '-'))
            .and(
                try(parser(hex_string))
                .or(parser(dec_string))
                )
            .map(|x| {
                if let Some(sign) = x.0 {
                    let mut s = String::new();
                    s.push(sign);
                    s.push('1');
                    x.1 * isize::from_str(s.as_slice()).unwrap()
                } else {
                    x.1
                }
                })
            .skip(not_followed_by(satisfy(|c|
                c == 'u' || c == 'U' || c == '.' || c == 'f' || c == 'F')
            ))
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}
/// Parser for unsigned integer constants.
///
/// This parses unssigned integer constants in decimal and hexadecimal.
///
/// TODO: add support for octal
/// TODO: add support for binary
/// TODO: add support for R6RS exponents
fn uint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {

        fn hex_string<I>(input: State<I>) -> ParseResult<usize, I>
            where I: Stream<Item=char> {
            (satisfy(|c| c == '#')
                .and(satisfy(|c| c == 'x' || c == 'X')))
                .with(many1::<Vec<_>, _>(hex_digit()))
                .map(|x| usize::from_str_radix(
                        x.iter()
                         .fold(
                            String::new(),
                            |mut s: String, i| { s.push(*i); s })
                         .as_slice(),
                    16).unwrap()
                ).parse_state(input)
        }

        try(parser(hex_string))
        .or( many1::<Vec<_>, _>(digit())
            .map(|x|usize::from_str(x.iter().fold(
                String::new(), |mut s: String, i| { s.push(*i); s })
                .as_slice()
            ).unwrap())
        )
        .skip(satisfy(|c| c == 'u' || c == 'U'))
        .map(|x: usize| NumNode::UIntConst(UIntNode{value: x}))
        .parse_state(input)
}

/// Parser for floating-point constants.
///
/// This parses floating-point constants. Currently, this parser
/// recognizes numbers with decimal points as floating point, followed
/// by an optional `f` or `F`. Numbers with `f`s but no decimal points,
/// i.e. `1F`, are currently not recognized. While this form of number
/// is not specified by R6RS, I'd like to support it anyway as it's
/// a common form for floating-point numbers. Priority: low.
fn float_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        many1::<Vec<_>, _>(digit())
            .and(satisfy(|c| c == '.'))
            .and(many1::<Vec<_>, _>(digit()))
            .map(|x| {
                let mut s = String::new();
                for i in (x.0).0.iter() { s.push(*i); } ;
                s.push((x.0).1);

                for i in x.1.iter() { s.push(*i); };
                NumNode::FloatConst(FloatNode{
                    value: f64::from_str(s.as_slice()).unwrap()
                })
            })
            .skip(optional(satisfy(|c| c == 'f' || c == 'F')))
            .parse_state(input)
}

/// Parses boolean constants.
///
/// Note that this parser recognizes the strings `"true"` and `"false"`
/// as true and false. While this is not specified in R6RS, the use of
/// these tokens is common enough in other programming languages that
/// I've decided that Seax Scheme should support it as well. This may
/// be removed in a future version if it causes unforseen compatibility
/// issues.
///
/// `#t`, `#T`, or `true`  -> `true`
/// `#f`, `#F`, or `false` -> `false`
pub fn bool_const<I>(input: State<I>) -> ParseResult<BoolNode, I>
    where I: Stream<Item=char> {
        let t_const = try(string("#t"))
            .or(try(string("#T")))
            .or(try(string("true")))
            .map(|_| BoolNode{ value: true });
        let f_const = try(string("#f"))
            .or(try(string("#F")))
            .or(try(string("false")))
            .map(|_| BoolNode{ value: false });
        t_const
            .or(f_const)
            .parse_state(input)
    }

/// Parses a floating-point, signed integer, or unsigned integer constant.
pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        try(parser(sint_const))
            .or(try(parser(uint_const)))
            .or(try(parser(float_const)))
            .parse_state(input)
}

/// Parser for valid R6RS identifiers.
///
/// An identifier may begin with an alphabetic character or
/// one of the following special characters `!`, `$`, `&`, `:`, `^`,
/// `<`, `>`, `_`,`~`,`\`, or `?`. Subsequent characters may also include
/// numbers or the special characters `+`, `-`, `.`, and `@`.
///
/// Essentially, this parser recognizes the regular expression
/// `[a-zA-Z!\$%:\^<>_~\\\?][a-zA-Z0-9!\$%:\^<>_~\\\?\+\-\.@]*`.
///
/// For more information, consult the
/// [R6RS](http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-7.html).
pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {

        fn initial<I>(input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                satisfy(|c|
                    c.is_alphabetic()
                    // R6RS 'special initial' characters
                    || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                    || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                    || c == '?'
                ).parse_state(input)
            }

        fn subsequent<I>(input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {

            satisfy(|c|
                c.is_alphanumeric()
                    // R6RS 'special initial' characters
                    || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                    || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                    || c == '?'
                    // R6RS 'special subsequent' characters
                    || c == '+' || c == '-' || c == '.' || c == '@'
                ).parse_state(input)
            }

        fn rest<I>(input: State<I>) -> ParseResult<String, I>
            where I: Stream<Item=char> {
                many::<Vec<_>, _>(parser(subsequent))
                    .map(|it|
                        it.iter().fold(
                            String::new(),
                            |mut s: String, i| {
                                s.push(*i);
                                s
                            })
                        )
                    .parse_state(input)
            }

        parser(initial)
            .and(parser(rest))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn character<I> (input: State<I>) -> ParseResult<CharNode, I>
    where I: Stream<Item=char> {

        fn char_name<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("tab").map(|_| '\t'))
                    .or(try(string("newline")).map(|_| '\n'))
                    .parse_state(input)
        }

        string("#\\")
            .with(
                parser(char_name)
                .or(parser(any_char))
            ).map(|c| CharNode { value: c})
            .parse_state(input)

}

/// Parses Scheme expressions.
#[allow(unconditional_recursion)]
pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();

        fn sexpr<I>(input: State<I>) -> ParseResult<ExprNode, I>
            where I: Stream<Item=char> {
                between(
                    satisfy(|c| c == '('),
                    satisfy(|c| c == ')'),
                    parser(name)
                        .and(many(parser(expr)))
                        .map(|x| {
                            SExpr(SExprNode {
                                operator: x.0,
                                operands: x.1
                            })
                        })
                ).parse_state(input)
            }

        fn list<I>(input: State<I>) -> ParseResult<ExprNode, I>
            where I: Stream<Item=char> {
                between(
                    satisfy(|c| c == '('),
                    satisfy(|c| c == ')'),
                    many(parser(expr))
                        .map(|x| {
                            ListConst(ListNode {
                                elements: x
                            })
                        })
                ).parse_state(input)
            }

        spaces.clone().with(
            try(parser(sexpr))
                .or(try(parser(list)))
                .or(try(parser(name).map(Name)))
                .or(try(parser(number).map(NumConst)))
            ).parse_state(input)
}

#[cfg(test)]
mod tests;<commit_msg>Implemented all R6RS named characters<commit_after>extern crate "parser-combinators" as parser_combinators;

use self::parser_combinators::{try, between, spaces, string, parser, many, many1, digit, any_char, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};

use super::ast::*;
use super::ast::ExprNode::*;

use std::str::FromStr;
use std::num::FromStrRadix;
use std::char;

/// Parser for signed integer constants.
///
/// This parses signed integer constants in decimal and hexadecimal.
///
/// TODO: add support for octal
/// TODO: add support for binary
/// TODO: add support for R6RS exponents
fn sint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {

        fn hex_string<I>(input: State<I>) -> ParseResult<isize, I>
            where I: Stream<Item=char> {
                (satisfy(|c| c == '#')
                    .and(satisfy(|c| c == 'x' || c == 'X')))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    .map(|x| {
                        isize::from_str_radix(
                            x.iter()
                             .fold(
                                String::new(),
                                |mut s: String, i| { s.push(*i); s })
                             .as_slice(),
                        16).unwrap()
                    }).parse_state(input)
        }

        fn dec_string<I>(input: State<I>) -> ParseResult<isize, I>
            where I: Stream<Item=char> {
                optional(satisfy(|c| c == '#')
                    .and(satisfy(|c| c == 'd' || c == 'D')))
                .with(many1::<Vec<_>, _>(digit())
                    .map(|x| isize::from_str(x.iter().fold(
                        String::new(), |mut s: String, i| { s.push(*i); s })
                        .as_slice()
                    ).unwrap()
                    )).parse_state(input)
            }

        optional(satisfy(|c| c == '-'))
            .and(
                try(parser(hex_string))
                .or(parser(dec_string))
                )
            .map(|x| {
                if let Some(sign) = x.0 {
                    let mut s = String::new();
                    s.push(sign);
                    s.push('1');
                    x.1 * isize::from_str(s.as_slice()).unwrap()
                } else {
                    x.1
                }
                })
            .skip(not_followed_by(satisfy(|c|
                c == 'u' || c == 'U' || c == '.' || c == 'f' || c == 'F')
            ))
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}
/// Parser for unsigned integer constants.
///
/// This parses unssigned integer constants in decimal and hexadecimal.
///
/// TODO: add support for octal
/// TODO: add support for binary
/// TODO: add support for R6RS exponents
fn uint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {

        fn hex_string<I>(input: State<I>) -> ParseResult<usize, I>
            where I: Stream<Item=char> {
            (satisfy(|c| c == '#')
                .and(satisfy(|c| c == 'x' || c == 'X')))
                .with(many1::<Vec<_>, _>(hex_digit()))
                .map(|x| usize::from_str_radix(
                        x.iter()
                         .fold(
                            String::new(),
                            |mut s: String, i| { s.push(*i); s })
                         .as_slice(),
                    16).unwrap()
                ).parse_state(input)
        }

        try(parser(hex_string))
        .or( many1::<Vec<_>, _>(digit())
            .map(|x|usize::from_str(x.iter().fold(
                String::new(), |mut s: String, i| { s.push(*i); s })
                .as_slice()
            ).unwrap())
        )
        .skip(satisfy(|c| c == 'u' || c == 'U'))
        .map(|x: usize| NumNode::UIntConst(UIntNode{value: x}))
        .parse_state(input)
}

/// Parser for floating-point constants.
///
/// This parses floating-point constants. Currently, this parser
/// recognizes numbers with decimal points as floating point, followed
/// by an optional `f` or `F`. Numbers with `f`s but no decimal points,
/// i.e. `1F`, are currently not recognized. While this form of number
/// is not specified by R6RS, I'd like to support it anyway as it's
/// a common form for floating-point numbers. Priority: low.
fn float_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        many1::<Vec<_>, _>(digit())
            .and(satisfy(|c| c == '.'))
            .and(many1::<Vec<_>, _>(digit()))
            .map(|x| {
                let mut s = String::new();
                for i in (x.0).0.iter() { s.push(*i); } ;
                s.push((x.0).1);

                for i in x.1.iter() { s.push(*i); };
                NumNode::FloatConst(FloatNode{
                    value: f64::from_str(s.as_slice()).unwrap()
                })
            })
            .skip(optional(satisfy(|c| c == 'f' || c == 'F')))
            .parse_state(input)
}

/// Parses boolean constants.
///
/// Note that this parser recognizes the strings `"true"` and `"false"`
/// as true and false. While this is not specified in R6RS, the use of
/// these tokens is common enough in other programming languages that
/// I've decided that Seax Scheme should support it as well. This may
/// be removed in a future version if it causes unforseen compatibility
/// issues.
///
/// `#t`, `#T`, or `true`  -> `true`
/// `#f`, `#F`, or `false` -> `false`
pub fn bool_const<I>(input: State<I>) -> ParseResult<BoolNode, I>
    where I: Stream<Item=char> {
        let t_const = try(string("#t"))
            .or(try(string("#T")))
            .or(try(string("true")))
            .map(|_| BoolNode{ value: true });
        let f_const = try(string("#f"))
            .or(try(string("#F")))
            .or(try(string("false")))
            .map(|_| BoolNode{ value: false });
        t_const
            .or(f_const)
            .parse_state(input)
    }

/// Parses a floating-point, signed integer, or unsigned integer constant.
pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        try(parser(sint_const))
            .or(try(parser(uint_const)))
            .or(try(parser(float_const)))
            .parse_state(input)
}

/// Parser for valid R6RS identifiers.
///
/// An identifier may begin with an alphabetic character or
/// one of the following special characters `!`, `$`, `&`, `:`, `^`,
/// `<`, `>`, `_`,`~`,`\`, or `?`. Subsequent characters may also include
/// numbers or the special characters `+`, `-`, `.`, and `@`.
///
/// Essentially, this parser recognizes the regular expression
/// `[a-zA-Z!\$%:\^<>_~\\\?][a-zA-Z0-9!\$%:\^<>_~\\\?\+\-\.@]*`.
///
/// For more information, consult the
/// [R6RS](http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-7.html).
pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {

        fn initial<I>(input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                satisfy(|c|
                    c.is_alphabetic()
                    // R6RS 'special initial' characters
                    || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                    || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                    || c == '?'
                ).parse_state(input)
            }

        fn subsequent<I>(input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {

            satisfy(|c|
                c.is_alphanumeric()
                    // R6RS 'special initial' characters
                    || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                    || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                    || c == '?'
                    // R6RS 'special subsequent' characters
                    || c == '+' || c == '-' || c == '.' || c == '@'
                ).parse_state(input)
            }

        fn rest<I>(input: State<I>) -> ParseResult<String, I>
            where I: Stream<Item=char> {
                many::<Vec<_>, _>(parser(subsequent))
                    .map(|it|
                        it.iter().fold(
                            String::new(),
                            |mut s: String, i| {
                                s.push(*i);
                                s
                            })
                        )
                    .parse_state(input)
            }

        parser(initial)
            .and(parser(rest))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn character<I> (input: State<I>) -> ParseResult<CharNode, I>
    where I: Stream<Item=char> {

        fn newline<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("newline"))
                    .or(try(string("linefeed")))
                    .map(|_| '\n')
                    .parse_state(input)
            }

        fn tab<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("tab")).map(|_| '\t').parse_state(input)
            }

        fn nul<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("nul"))
                    .map(|_| char::from_u32(0x0000).unwrap())
                    .parse_state(input)
            }

        fn backspace<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("backspace"))
                    .map(|_| char::from_u32(0x0008).unwrap())
                    .parse_state(input)
            }

        fn vtab<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("vtab"))
                    .map(|_| char::from_u32(0x000B).unwrap())
                    .parse_state(input)
            }

        fn page<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("page"))
                    .map(|_| char::from_u32(0x000C).unwrap())
                    .parse_state(input)
            }

        fn retn<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("return"))
                    .map(|_| char::from_u32(0x000D).unwrap())
                    .parse_state(input)
            }

        fn esc<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("esc"))
                    .map(|_| char::from_u32(0x001B).unwrap())
                    .parse_state(input)
            }

        fn delete<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("delete"))
                    .map(|_| char::from_u32(0x007F).unwrap())
                    .parse_state(input)
            }

        fn alarm<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("alarm"))
                    .map(|_| char::from_u32(0x0007).unwrap())
                    .parse_state(input)
            }

        fn space<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                try(string("space"))
                    .map(|_| char::from_u32(0x0020).unwrap())
                    .parse_state(input)
            }

        fn char_name<I> (input: State<I>) -> ParseResult<char, I>
            where I: Stream<Item=char> {
                parser(newline)
                    .or(parser(tab))
                    .or(parser(vtab))
                    .or(parser(backspace))
                    .or(parser(nul))
                    .or(parser(page))
                    .or(parser(retn))
                    .or(parser(esc))
                    .or(parser(delete))
                    .or(parser(alarm))
                    .or(parser(space))
                    .parse_state(input)
        }

        string("#\\")
            .with(
                parser(char_name)
                .or(parser(any_char))
            ).map(|c| CharNode { value: c})
            .parse_state(input)

}

/// Parses Scheme expressions.
#[allow(unconditional_recursion)]
pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();

        fn sexpr<I>(input: State<I>) -> ParseResult<ExprNode, I>
            where I: Stream<Item=char> {
                between(
                    satisfy(|c| c == '('),
                    satisfy(|c| c == ')'),
                    parser(name)
                        .and(many(parser(expr)))
                        .map(|x| {
                            SExpr(SExprNode {
                                operator: x.0,
                                operands: x.1
                            })
                        })
                ).parse_state(input)
            }

        fn list<I>(input: State<I>) -> ParseResult<ExprNode, I>
            where I: Stream<Item=char> {
                between(
                    satisfy(|c| c == '('),
                    satisfy(|c| c == ')'),
                    many(parser(expr))
                        .map(|x| {
                            ListConst(ListNode {
                                elements: x
                            })
                        })
                ).parse_state(input)
            }

        spaces.clone().with(
            try(parser(sexpr))
                .or(try(parser(list)))
                .or(try(parser(name).map(Name)))
                .or(try(parser(number).map(NumConst)))
            ).parse_state(input)
}

#[cfg(test)]
mod tests;<|endoftext|>


<commit_before>use cbits::leveldb::*;
use libc::{size_t};
use std::slice::*;
use std::vec::raw::*;
use std::vec::*;
use std::iter;
use super::Database;
use super::options::ReadOptions;

pub struct Iterator {
  iter: *mut leveldb_iterator_t,
}

pub trait Iterable {
  fn iter(&self, options: ReadOptions) -> Iterator;
}

impl Iterable for Database {
  fn iter(&self, options: ReadOptions) -> Iterator {
    Iterator::new(self, options)
  }
}

impl Iterator {
  fn new(database: &Database,
         options: ReadOptions) -> Iterator {
    unsafe {
      let iter = leveldb_create_iterator(database.database,
                                         options.options());
      leveldb_iter_seek_to_first(iter);
      Iterator { iter: iter }
    }
  }

  pub fn valid(self) -> bool {
    unsafe { leveldb_iter_valid(self.iter) != 0 }
  }

  pub fn seek_to_first(self) {
    unsafe { leveldb_iter_seek_to_first(self.iter) }
  }

  pub fn current_value(self) -> Vec<i8> {
    unsafe {
      let length: size_t = 0;
      let value = leveldb_iter_value(self.iter,
                                     &length);
      from_buf(value, length as uint)
    }
  }
}

impl iter::Iterator<Vec<i8>> for Iterator {
  fn next(&mut self) -> Option<Vec<i8>> {
    unsafe {
      if self.valid() {
        let vec = self.current_value();
        leveldb_iter_next(self.iter);
        Some(vec)
      } else {
        None
      }
    }
  }
}

<commit_msg>Let iterator return u8<commit_after>use cbits::leveldb::*;
use libc::{size_t};
use std::slice::*;
use std::vec::raw::*;
use std::vec::*;
use std::iter;
use super::Database;
use super::options::ReadOptions;

pub struct Iterator {
  iter: *mut leveldb_iterator_t,
}

pub trait Iterable {
  fn iter(&self, options: ReadOptions) -> Iterator;
}

impl Iterable for Database {
  fn iter(&self, options: ReadOptions) -> Iterator {
    Iterator::new(self, options)
  }
}

impl Iterator {
  fn new(database: &Database,
         options: ReadOptions) -> Iterator {
    unsafe {
      let iter = leveldb_create_iterator(database.database,
                                         options.options());
      leveldb_iter_seek_to_first(iter);
      Iterator { iter: iter }
    }
  }

  pub fn valid(self) -> bool {
    unsafe { leveldb_iter_valid(self.iter) != 0 }
  }

  pub fn seek_to_first(self) {
    unsafe { leveldb_iter_seek_to_first(self.iter) }
  }

  pub fn current_value(self) -> Vec<u8> {
    unsafe {
      let length: size_t = 0;
      let value = leveldb_iter_value(self.iter,
                                     &length) as *const u8;
      from_buf(value, length as uint)
    }
  }
}

impl iter::Iterator<Vec<u8>> for Iterator {
  fn next(&mut self) -> Option<Vec<u8>> {
    unsafe {
      if self.valid() {
        let vec = self.current_value();
        leveldb_iter_next(self.iter);
        Some(vec)
      } else {
        None
      }
    }
  }
}

<|endoftext|>


<commit_before><commit_msg>resolve wrong boundary<commit_after><|endoftext|>


<commit_before>use crate::metrics::{self, Meter, MeterProvider};
use std::sync::{Arc, RwLock};

lazy_static::lazy_static! {
    /// The global `Meter` provider singleton.
    static ref GLOBAL_METER_PROVIDER: RwLock<GlobalMeterProvider> = RwLock::new(GlobalMeterProvider::new(metrics::noop::NoopMeterProvider::new()));
}

/// Represents the globally configured [`MeterProvider`] instance for this
/// application.
#[derive(Debug, Clone)]
pub struct GlobalMeterProvider {
    provider: Arc<dyn MeterProvider + Send + Sync>,
}

impl MeterProvider for GlobalMeterProvider {
    fn meter(
        &self,
        name: &'static str,
        version: Option<&'static str>,
        schema_url: Option<&'static str>,
    ) -> Meter {
        self.provider.meter(name, version, schema_url)
    }
}

impl GlobalMeterProvider {
    /// Create a new global meter provider
    pub fn new<P>(provider: P) -> Self
    where
        P: MeterProvider + Send + Sync + 'static,
    {
        GlobalMeterProvider {
            provider: Arc::new(provider),
        }
    }
}

/// Sets the given [`MeterProvider`] instance as the current global meter
/// provider.
pub fn set_meter_provider<P>(new_provider: P)
where
    P: metrics::MeterProvider + Send + Sync + 'static,
{
    let mut global_provider = GLOBAL_METER_PROVIDER
        .write()
        .expect("GLOBAL_METER_PROVIDER RwLock poisoned");
    *global_provider = GlobalMeterProvider::new(new_provider);
}

/// Returns an instance of the currently configured global [`MeterProvider`]
/// through [`GlobalMeterProvider`].
pub fn meter_provider() -> GlobalMeterProvider {
    GLOBAL_METER_PROVIDER
        .read()
        .expect("GLOBAL_METER_PROVIDER RwLock poisoned")
        .clone()
}

/// Creates a named [`Meter`] via the configured [`GlobalMeterProvider`].
///
/// If the name is an empty string, the provider will use a default name.
///
/// This is a more convenient way of expressing `global::meter_provider().meter(name)`.
pub fn meter(name: &'static str) -> Meter {
    meter_provider().meter(name, None, None)
}

/// Creates a [`Meter`] with the name and version.
pub fn meter_with_version(
    name: &'static str,
    version: &'static str,
    schema_url: &'static str,
) -> Meter {
    meter_provider().meter(name, Some(version), Some(schema_url))
}
<commit_msg>fix(sdk): `meter_with_version` should accept optional parameter for optional parameters. (#752)<commit_after>use crate::metrics::{self, Meter, MeterProvider};
use std::sync::{Arc, RwLock};

lazy_static::lazy_static! {
    /// The global `Meter` provider singleton.
    static ref GLOBAL_METER_PROVIDER: RwLock<GlobalMeterProvider> = RwLock::new(GlobalMeterProvider::new(metrics::noop::NoopMeterProvider::new()));
}

/// Represents the globally configured [`MeterProvider`] instance for this
/// application.
#[derive(Debug, Clone)]
pub struct GlobalMeterProvider {
    provider: Arc<dyn MeterProvider + Send + Sync>,
}

impl MeterProvider for GlobalMeterProvider {
    fn meter(
        &self,
        name: &'static str,
        version: Option<&'static str>,
        schema_url: Option<&'static str>,
    ) -> Meter {
        self.provider.meter(name, version, schema_url)
    }
}

impl GlobalMeterProvider {
    /// Create a new global meter provider
    pub fn new<P>(provider: P) -> Self
    where
        P: MeterProvider + Send + Sync + 'static,
    {
        GlobalMeterProvider {
            provider: Arc::new(provider),
        }
    }
}

/// Sets the given [`MeterProvider`] instance as the current global meter
/// provider.
pub fn set_meter_provider<P>(new_provider: P)
where
    P: metrics::MeterProvider + Send + Sync + 'static,
{
    let mut global_provider = GLOBAL_METER_PROVIDER
        .write()
        .expect("GLOBAL_METER_PROVIDER RwLock poisoned");
    *global_provider = GlobalMeterProvider::new(new_provider);
}

/// Returns an instance of the currently configured global [`MeterProvider`]
/// through [`GlobalMeterProvider`].
pub fn meter_provider() -> GlobalMeterProvider {
    GLOBAL_METER_PROVIDER
        .read()
        .expect("GLOBAL_METER_PROVIDER RwLock poisoned")
        .clone()
}

/// Creates a named [`Meter`] via the configured [`GlobalMeterProvider`].
///
/// If the name is an empty string, the provider will use a default name.
///
/// This is a more convenient way of expressing `global::meter_provider().meter(name, None, None)`.
pub fn meter(name: &'static str) -> Meter {
    meter_provider().meter(name, None, None)
}

/// Creates a [`Meter`] with the name, version and schema url.
///
/// - name SHOULD uniquely identify the instrumentation scope, such as the instrumentation library (e.g. io.opentelemetry.contrib.mongodb), package, module or class name.
/// - version specifies the version of the instrumentation scope if the scope has a version
/// - schema url specifies the Schema URL that should be recorded in the emitted telemetry.
///
/// This is a convenient way of `global::meter_provider().meter(...)`
/// # Example
/// ```rust
/// use opentelemetry_api::global::meter_with_version;
/// let meter = meter_with_version("io.opentelemetry", Some("0.17"), Some("https://opentelemetry.io/schemas/1.2.0"));
/// ```
///
pub fn meter_with_version(
    name: &'static str,
    version: Option<&'static str>,
    schema_url: Option<&'static str>,
) -> Meter {
    meter_provider().meter(name, version, schema_url)
}
<|endoftext|>