<commit_before>use raft::client::RaftClient;
use raft::state_machine::master::ExecError;
use super::DEFAULT_SERVICE_ID;
use super::heartbeat_rpc::*;
use super::raft::client::SMClient;
use super::client::{MemberClient, ObserverClient as ObserverClient};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::{thread, time};
use bifrost_hasher::hash_str;

static PING_INTERVAL: u64 = 100;

pub struct MemberService {
    member_client: MemberClient,
    sm_client: Arc<SMClient>,
    raft_client: Arc<RaftClient>,
    address: String,
    closed: AtomicBool,
    id: u64,
}

impl MemberService {
    pub fn new(server_address: &String, raft_client: &Arc<RaftClient>) -> Arc<MemberService> {
        let server_id = hash_str(server_address);
        let sm_client = Arc::new(SMClient::new(DEFAULT_SERVICE_ID, &raft_client));
        let service = Arc::new(MemberService {
            sm_client: sm_client.clone(),
            member_client: MemberClient {
                id: server_id,
                sm_client: sm_client.clone()
            },
            raft_client: raft_client.clone(),
            address: server_address.clone(),
            closed: AtomicBool::new(false),
            id: server_id,
        });
        sm_client.join(&server_address);
        let service_clone = service.clone();
        thread::spawn(move || {
            while !service_clone.closed.load(Ordering::Relaxed) {
                let rpc_client = service_clone.raft_client.current_leader_rpc_client();
                if let Some(rpc_client) = rpc_client {
                    let heartbeat_client = AsyncServiceClient::new(DEFAULT_SERVICE_ID, &rpc_client);
                    heartbeat_client.ping(&service_clone.id);
                }
                thread::sleep(time::Duration::from_millis(PING_INTERVAL))
            }
        });
        return service;
    }
    pub fn close(&self) {
        self.closed.store(true, Ordering::Relaxed);
    }
    pub fn leave(&self) -> Result<Result<(), ()>, ExecError>{
        self.close();
        self.sm_client.leave(&self.id)
    }
    pub fn join_group(&self, group: &String) -> Result<Result<(), ()>, ExecError> {
        self.member_client.join_group(group)
    }
    pub fn leave_group(&self, group: &String) -> Result<Result<(), ()>, ExecError> {
        self.member_client.leave_group(group)
    }
    pub fn client(&self) -> ObserverClient {
        ObserverClient::new_from_sm(&self.sm_client)
    }
    pub fn get_server_id(&self) -> u64 {
        self.id
    }
}

impl Drop for MemberService {
    fn drop(&mut self) {
        self.leave();
    }
}

<commit_msg>fix membership member interfaces<commit_after>use raft::client::RaftClient;
use raft::state_machine::master::ExecError;
use super::DEFAULT_SERVICE_ID;
use super::heartbeat_rpc::*;
use super::raft::client::SMClient;
use super::client::{MemberClient, ObserverClient as ObserverClient};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::{thread, time};
use bifrost_hasher::hash_str;

use futures::prelude::*;

static PING_INTERVAL: u64 = 100;

pub struct MemberService {
    member_client: MemberClient,
    sm_client: Arc<SMClient>,
    raft_client: Arc<RaftClient>,
    address: String,
    closed: AtomicBool,
    id: u64,
}

impl MemberService {
    pub fn new(server_address: &String, raft_client: &Arc<RaftClient>) -> Arc<MemberService> {
        let server_id = hash_str(server_address);
        let sm_client = Arc::new(SMClient::new(DEFAULT_SERVICE_ID, &raft_client));
        let service = Arc::new(MemberService {
            sm_client: sm_client.clone(),
            member_client: MemberClient {
                id: server_id,
                sm_client: sm_client.clone()
            },
            raft_client: raft_client.clone(),
            address: server_address.clone(),
            closed: AtomicBool::new(false),
            id: server_id,
        });
        sm_client.join(&server_address);
        let service_clone = service.clone();
        thread::spawn(move || {
            while !service_clone.closed.load(Ordering::Relaxed) {
                let rpc_client = service_clone.raft_client.current_leader_rpc_client().wait();
                if let Ok(rpc_client) = rpc_client {
                    let heartbeat_client = AsyncServiceClient::new(DEFAULT_SERVICE_ID, &rpc_client);
                    heartbeat_client.ping(&service_clone.id);
                }
                thread::sleep(time::Duration::from_millis(PING_INTERVAL))
            }
        });
        return service;
    }
    pub fn close(&self) {
        self.closed.store(true, Ordering::Relaxed);
    }
    pub fn leave(&self) -> impl Future<Item = Result<(), ()>, Error = ExecError>{
        self.close();
        self.sm_client.leave(&self.id)
    }
    pub fn join_group(&self, group: &String) -> impl Future<Item = Result<(), ()>, Error = ExecError> {
        self.member_client.join_group(group)
    }
    pub fn leave_group(&self, group: &String) -> impl Future<Item = Result<(), ()>, Error = ExecError> {
        self.member_client.leave_group(group)
    }
    pub fn client(&self) -> ObserverClient {
        ObserverClient::new_from_sm(&self.sm_client)
    }
    pub fn get_server_id(&self) -> u64 {
        self.id
    }
}

impl Drop for MemberService {
    fn drop(&mut self) {
        self.leave();
    }
}

<|endoftext|>


<commit_before>use core::ptr::Unique;
use memory::{Frame, FrameAllocator};
use self::table::{Table, Level4};
use self::entry::*;

mod entry;
mod table;
pub mod translate;
pub mod mapping;

pub fn test<A>(frame_allocator: &mut A)
    where A: super::FrameAllocator
{
    use self::entry::PRESENT;
    mapping::map(&Page::containing_address(0xdeadbeaa000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeab000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeac000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbead000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xcafebeaf000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0x0), PRESENT, frame_allocator);
}

pub const PAGE_SIZE: usize = 4096;
const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

pub struct Page {
    number: usize,
}

impl Page {
    fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page { number: address / PAGE_SIZE }
    }

    fn start_address(&self) -> VirtualAddress {
        self.number * PAGE_SIZE
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}

pub struct RecursivePageTable {
    p4: Unique<Table<Level4>>,
}

impl RecursivePageTable {
    fn p4(&self) -> &Table<Level4> {
        unsafe { self.p4.get() }
    }

    fn p4_mut(&mut self) -> &mut Table<Level4> {
        unsafe { self.p4.get_mut() }
    }

    pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> {
        let offset = virtual_address % PAGE_SIZE;
        self.translate_page(Page::containing_address(virtual_address))
            .map(|frame| frame.number * PAGE_SIZE + offset)
    }

    fn translate_page(&self, page: Page) -> Option<Frame> {
        let p3 = self.p4().next_table(page.p4_index());

        let huge_page = || {
            p3.and_then(|p3| {
                let p3_entry = &p3[page.p3_index()];
                // 1GiB page?
                if let Some(start_frame) = p3_entry.pointed_frame() {
                    if p3_entry.flags().contains(HUGE_PAGE) {
                        // address must be 1GiB aligned
                        assert!(start_frame.number % (ENTRY_COUNT * ENTRY_COUNT) == 0);
                        return Some(Frame {
                            number: start_frame.number + page.p2_index() * ENTRY_COUNT +
                                    page.p1_index(),
                        });
                    }
                }
                if let Some(p2) = p3.next_table(page.p3_index()) {
                    let p2_entry = &p2[page.p2_index()];
                    // 2MiB page?
                    if let Some(start_frame) = p2_entry.pointed_frame() {
                        if p2_entry.flags().contains(HUGE_PAGE) {
                            // address must be 2MiB aligned
                            assert!(start_frame.number % ENTRY_COUNT == 0);
                            return Some(Frame { number: start_frame.number + page.p1_index() });
                        }
                    }
                }
                None
            })
        };

        p3.and_then(|p3| p3.next_table(page.p3_index()))
          .and_then(|p2| p2.next_table(page.p2_index()))
          .and_then(|p1| p1[page.p1_index()].pointed_frame())
          .or_else(huge_page)
    }

    pub fn map<A>(&mut self, page: &Page, flags: EntryFlags, allocator: &mut A)
        where A: FrameAllocator
    {
        let frame = allocator.allocate_frame().expect("out of memory");
        self.map_to(page, frame, flags, allocator)
    }

    pub fn map_to<A>(&mut self, page: &Page, frame: Frame, flags: EntryFlags, allocator: &mut A)
        where A: FrameAllocator
    {
        let mut p3 = self.p4_mut().next_table_create(page.p4_index(), allocator);
        let mut p2 = p3.next_table_create(page.p3_index(), allocator);
        let mut p1 = p2.next_table_create(page.p2_index(), allocator);

        assert!(!p1[page.p1_index()].flags().contains(PRESENT));
        p1[page.p1_index()].set(frame, flags | PRESENT);
    }

    pub fn identity_map<A>(&mut self, frame: Frame, flags: EntryFlags, allocator: &mut A)
        where A: FrameAllocator
    {
        let page = Page { number: frame.number };
        self.map_to(&page, frame, flags, allocator)
    }

    fn unmap<A>(&mut self, page: &Page, allocator: &mut A)
        where A: FrameAllocator
    {
        use x86::tlb;

        assert!(self.translate(page.start_address()).is_some());

        let p1 = self.p4_mut()
                     .next_table_mut(page.p4_index())
                     .and_then(|p3| p3.next_table_mut(page.p3_index()))
                     .and_then(|p2| p2.next_table_mut(page.p2_index()))
                     .unwrap();
        let frame = p1[page.p1_index()].pointed_frame().unwrap();
        p1[page.p1_index()].set_unused();
        unsafe { tlb::flush(page.start_address()) };
        // TODO free p(1,2,3) table if empty
        allocator.deallocate_frame(frame);
    }
}

pub struct InactivePageTable {
    p4_frame: Frame, // recursive mapped
}

impl InactivePageTable {
    pub fn create_new_on_identity_mapped_frame(&self,
                                               identity_mapped_frame: Frame)
                                               -> InactivePageTable {
        let page_address = Page { number: identity_mapped_frame.number }.start_address();
        // frame must be identity mapped
        assert!(self.read(|lock| lock.translate(page_address)) == Some(page_address));

        let table = unsafe { &mut *(page_address as *mut Table<Level4>) };
        table[511].set(Frame { number: identity_mapped_frame.number }, WRITABLE);
        InactivePageTable { p4_frame: identity_mapped_frame }
    }

    pub fn read<F, R>(&self, f: F) -> R
        where F: FnOnce(&RecursivePageTable) -> R
    {
        self.activate_temporary(|pt| f(pt))
    }

    pub fn modify<F>(&mut self, f: F)
        where F: FnOnce(&mut RecursivePageTable)
    {
        self.activate_temporary(f)
    }

    fn activate_temporary<F, R>(&self, f: F) -> R
        where F: FnOnce(&mut RecursivePageTable) -> R
    {
        use memory::paging::table::P4;

        let mut page_table = RecursivePageTable { p4: unsafe { Unique::new(P4) } };

        let backup = page_table.p4()[511].pointed_frame().unwrap();
        if backup == self.p4_frame {
            f(&mut page_table)
        } else {
            page_table.p4_mut()[511]
                .set(Frame { number: self.p4_frame.number }, PRESENT | WRITABLE);
            let ret = f(&mut page_table);
            page_table.p4_mut()[511].set(backup, PRESENT | WRITABLE);
            ret
        }
    }
}
<commit_msg>Add a RecursivePageTable::new function<commit_after>use core::ptr::Unique;
use memory::{Frame, FrameAllocator};
use self::table::{Table, Level4};
use self::entry::*;

mod entry;
mod table;
pub mod translate;
pub mod mapping;

pub fn test<A>(frame_allocator: &mut A)
    where A: super::FrameAllocator
{
    use self::entry::PRESENT;
    mapping::map(&Page::containing_address(0xdeadbeaa000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeab000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeac000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbead000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xcafebeaf000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0x0), PRESENT, frame_allocator);
}

pub const PAGE_SIZE: usize = 4096;
const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

pub struct Page {
    number: usize,
}

impl Page {
    fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page { number: address / PAGE_SIZE }
    }

    fn start_address(&self) -> VirtualAddress {
        self.number * PAGE_SIZE
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}

pub struct RecursivePageTable {
    p4: Unique<Table<Level4>>,
}

impl RecursivePageTable {
    pub unsafe fn new() -> RecursivePageTable {
        use self::table::P4;
        RecursivePageTable {
            p4: Unique::new(P4),
        }
    }

    fn p4(&self) -> &Table<Level4> {
        unsafe { self.p4.get() }
    }

    fn p4_mut(&mut self) -> &mut Table<Level4> {
        unsafe { self.p4.get_mut() }
    }

    pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> {
        let offset = virtual_address % PAGE_SIZE;
        self.translate_page(Page::containing_address(virtual_address))
            .map(|frame| frame.number * PAGE_SIZE + offset)
    }

    fn translate_page(&self, page: Page) -> Option<Frame> {
        let p3 = self.p4().next_table(page.p4_index());

        let huge_page = || {
            p3.and_then(|p3| {
                let p3_entry = &p3[page.p3_index()];
                // 1GiB page?
                if let Some(start_frame) = p3_entry.pointed_frame() {
                    if p3_entry.flags().contains(HUGE_PAGE) {
                        // address must be 1GiB aligned
                        assert!(start_frame.number % (ENTRY_COUNT * ENTRY_COUNT) == 0);
                        return Some(Frame {
                            number: start_frame.number + page.p2_index() * ENTRY_COUNT +
                                    page.p1_index(),
                        });
                    }
                }
                if let Some(p2) = p3.next_table(page.p3_index()) {
                    let p2_entry = &p2[page.p2_index()];
                    // 2MiB page?
                    if let Some(start_frame) = p2_entry.pointed_frame() {
                        if p2_entry.flags().contains(HUGE_PAGE) {
                            // address must be 2MiB aligned
                            assert!(start_frame.number % ENTRY_COUNT == 0);
                            return Some(Frame { number: start_frame.number + page.p1_index() });
                        }
                    }
                }
                None
            })
        };

        p3.and_then(|p3| p3.next_table(page.p3_index()))
          .and_then(|p2| p2.next_table(page.p2_index()))
          .and_then(|p1| p1[page.p1_index()].pointed_frame())
          .or_else(huge_page)
    }

    pub fn map<A>(&mut self, page: &Page, flags: EntryFlags, allocator: &mut A)
        where A: FrameAllocator
    {
        let frame = allocator.allocate_frame().expect("out of memory");
        self.map_to(page, frame, flags, allocator)
    }

    pub fn map_to<A>(&mut self, page: &Page, frame: Frame, flags: EntryFlags, allocator: &mut A)
        where A: FrameAllocator
    {
        let mut p3 = self.p4_mut().next_table_create(page.p4_index(), allocator);
        let mut p2 = p3.next_table_create(page.p3_index(), allocator);
        let mut p1 = p2.next_table_create(page.p2_index(), allocator);

        assert!(!p1[page.p1_index()].flags().contains(PRESENT));
        p1[page.p1_index()].set(frame, flags | PRESENT);
    }

    pub fn identity_map<A>(&mut self, frame: Frame, flags: EntryFlags, allocator: &mut A)
        where A: FrameAllocator
    {
        let page = Page { number: frame.number };
        self.map_to(&page, frame, flags, allocator)
    }

    fn unmap<A>(&mut self, page: &Page, allocator: &mut A)
        where A: FrameAllocator
    {
        use x86::tlb;

        assert!(self.translate(page.start_address()).is_some());

        let p1 = self.p4_mut()
                     .next_table_mut(page.p4_index())
                     .and_then(|p3| p3.next_table_mut(page.p3_index()))
                     .and_then(|p2| p2.next_table_mut(page.p2_index()))
                     .unwrap();
        let frame = p1[page.p1_index()].pointed_frame().unwrap();
        p1[page.p1_index()].set_unused();
        unsafe { tlb::flush(page.start_address()) };
        // TODO free p(1,2,3) table if empty
        allocator.deallocate_frame(frame);
    }
}

pub struct InactivePageTable {
    p4_frame: Frame, // recursive mapped
}

impl InactivePageTable {
    pub fn create_new_on_identity_mapped_frame(&self,
                                               identity_mapped_frame: Frame)
                                               -> InactivePageTable {
        let page_address = Page { number: identity_mapped_frame.number }.start_address();
        // frame must be identity mapped
        assert!(self.read(|lock| lock.translate(page_address)) == Some(page_address));

        let table = unsafe { &mut *(page_address as *mut Table<Level4>) };
        table[511].set(Frame { number: identity_mapped_frame.number }, WRITABLE);
        InactivePageTable { p4_frame: identity_mapped_frame }
    }

    pub fn read<F, R>(&self, f: F) -> R
        where F: FnOnce(&RecursivePageTable) -> R
    {
        self.activate_temporary(|pt| f(pt))
    }

    pub fn modify<F>(&mut self, f: F)
        where F: FnOnce(&mut RecursivePageTable)
    {
        self.activate_temporary(f)
    }

    fn activate_temporary<F, R>(&self, f: F) -> R
        where F: FnOnce(&mut RecursivePageTable) -> R
    {
        use memory::paging::table::P4;

        let mut page_table = RecursivePageTable { p4: unsafe { Unique::new(P4) } };

        let backup = page_table.p4()[511].pointed_frame().unwrap();
        if backup == self.p4_frame {
            f(&mut page_table)
        } else {
            page_table.p4_mut()[511]
                .set(Frame { number: self.p4_frame.number }, PRESENT | WRITABLE);
            let ret = f(&mut page_table);
            page_table.p4_mut()[511].set(backup, PRESENT | WRITABLE);
            ret
        }
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

//! Platform tree operations crate

#![experimental]
#![feature(quote, globs)]

#![crate_name="platformtree"]
#![crate_type="rlib"]

extern crate regex;
extern crate syntax;
#[cfg(test)] extern crate hamcrest;

pub mod builder;
pub mod node;
pub mod parser;

#[path="../zinc/hal/lpc17xx/platformtree.rs"] mod lpc17xx_pt;
#[path="../zinc/hal/tiva_c/platformtree.rs"] mod tiva_c_pt;
#[path="../zinc/drivers/drivers_pt.rs"] mod drivers_pt;

#[cfg(test)] mod test_helpers;
#[cfg(test)] mod parser_test;
<commit_msg>experimental not known anymore<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

//! Platform tree operations crate

#![feature(quote, globs)]

#![crate_name="platformtree"]
#![crate_type="rlib"]

extern crate regex;
extern crate syntax;
#[cfg(test)] extern crate hamcrest;

pub mod builder;
pub mod node;
pub mod parser;

#[path="../zinc/hal/lpc17xx/platformtree.rs"] mod lpc17xx_pt;
#[path="../zinc/hal/tiva_c/platformtree.rs"] mod tiva_c_pt;
#[path="../zinc/drivers/drivers_pt.rs"] mod drivers_pt;

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


<commit_before>use crate::grammar::model::Fragment;
use crate::grammar::parsers::whitespace;
use codespan::{FileId, Files};

fn setup(src: &str) -> (Files<String>, FileId) {
    let mut f: Files<String> = Files::new();
    let id = f.add("test", src.to_string());
    (f, id)
}

#[test]
pub fn single_comment() {
    let (f, h) = setup("// line comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), " line comment");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty_single_comment() {
    let (f, h) = setup("//");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), "");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_with_tail() {
    let (f, h) = setup("// line comment\nnot a comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 14);
        assert_eq!(val.source(), " line comment");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_comment_single() {
    let (f, h) = setup("/* single line multi comment */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::multiline_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), " single line multi comment ");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_comment_mutli() {
    let (f, h) = setup("/* mutli line\n * multi comment */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::multiline_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), " mutli line\n * multi comment ");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_comment_empty() {
    let (f, h) = setup("/**/");
    let frag = Fragment::new(&f, h);
    let res = whitespace::multiline_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), "");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comments_and_whitespace() {
    let (f, h) = setup("// line comment\n// this is another comment\n    // third comment\n");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
pub fn empty() {
    let (f, h) = setup("");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn line_comment_only() {
    let (f, h) = setup("// comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
pub fn whitespace_only() {
    let (f, h) = setup("\t  \n\n   \t  ");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multiline_comment_only() {
    let (f, h) = setup("/* comment */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multiline_comments_and_whitespace() {
    let (f, h) = setup("/* these are many */\n  /* multiline comments */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn everything() {
    let (f, h) = setup(" // single\n /* these are many */\n  /* multiline comments */ // another");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_in_single() {
    let (f, h) = setup("// comment /* not nested */ comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn single_in_multi() {
    let (f, h) = setup("/* comment // not nested */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}
<commit_msg>Fix compiler warning<commit_after>use crate::grammar::model::Fragment;
use crate::grammar::parsers::whitespace;
use codespan::{FileId, Files};

fn setup(src: &str) -> (Files<String>, FileId) {
    let mut f: Files<String> = Files::new();
    let id = f.add("test", src.to_string());
    (f, id)
}

#[test]
pub fn single_comment() {
    let (f, h) = setup("// line comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), " line comment");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty_single_comment() {
    let (f, h) = setup("//");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), "");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_with_tail() {
    let (f, h) = setup("// line comment\nnot a comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 14);
        assert_eq!(val.source(), " line comment");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_comment_single() {
    let (f, h) = setup("/* single line multi comment */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::multiline_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), " single line multi comment ");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_comment_mutli() {
    let (f, h) = setup("/* mutli line\n * multi comment */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::multiline_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), " mutli line\n * multi comment ");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_comment_empty() {
    let (f, h) = setup("/**/");
    let frag = Fragment::new(&f, h);
    let res = whitespace::multiline_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), "");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comments_and_whitespace() {
    let (f, h) = setup("// line comment\n// this is another comment\n    // third comment\n");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
pub fn empty() {
    let (f, h) = setup("");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn line_comment_only() {
    let (f, h) = setup("// comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
pub fn whitespace_only() {
    let (f, h) = setup("\t  \n\n   \t  ");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multiline_comment_only() {
    let (f, h) = setup("/* comment */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multiline_comments_and_whitespace() {
    let (f, h) = setup("/* these are many */\n  /* multiline comments */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn everything() {
    let (f, h) = setup(" // single\n /* these are many */\n  /* multiline comments */ // another");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn multi_in_single() {
    let (f, h) = setup("// comment /* not nested */ comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn single_in_multi() {
    let (f, h) = setup("/* comment // not nested */");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}
<|endoftext|>


<commit_before>use compression::{NUM_DOCS_PER_BLOCK, BlockDecoder, VIntDecoder};
use DocId;
use postings::{Postings, FreqHandler, DocSet, HasLen, SkipResult};
use std::num::Wrapping;
use fastfield::DeleteBitSet;

const EMPTY_DATA: [u8; 0] = [0u8; 0];

/// `SegmentPostings` represents the inverted list or postings associated to
/// a term in a `Segment`.
///
/// As we iterate through the `SegmentPostings`, the frequencies are optionally decoded.
/// Positions on the other hand, are optionally entirely decoded upfront.
pub struct SegmentPostings<'a> {
    len: usize,
    // Removing this makes the code slower
    // See https://github.com/tantivy-search/tantivy/issues/89
    block_len: usize,
    doc_offset: u32,
    block_decoder: BlockDecoder,
    freq_handler: FreqHandler,
    remaining_data: &'a [u8],
    cur: Wrapping<usize>,
    delete_bitset: DeleteBitSet,
}

impl<'a> SegmentPostings<'a> {
    fn load_next_block(&mut self) {
        let num_remaining_docs = self.len - self.cur.0;
        if num_remaining_docs >= NUM_DOCS_PER_BLOCK {
            self.remaining_data =
                self.block_decoder
                    .uncompress_block_sorted(self.remaining_data, self.doc_offset);
            self.remaining_data = self.freq_handler.read_freq_block(self.remaining_data);
            self.doc_offset = self.block_decoder.output(NUM_DOCS_PER_BLOCK - 1);
            self.block_len = NUM_DOCS_PER_BLOCK;
        } else {
            self.remaining_data =
                self.block_decoder
                    .uncompress_vint_sorted(self.remaining_data,
                                            self.doc_offset,
                                            num_remaining_docs);
            self.freq_handler
                .read_freq_vint(self.remaining_data, num_remaining_docs);
            self.block_len = num_remaining_docs;
        }
    }

    /// Reads a Segment postings from an &[u8]
    ///
    /// * `len` - number of document in the posting lists.
    /// * `data` - data array. The complete data is not necessarily used.
    /// * `freq_handler` - the freq handler is in charge of decoding
    ///   frequencies and/or positions
    pub fn from_data(len: u32,
                     data: &'a [u8],
                     delete_bitset: &'a DeleteBitSet,
                     freq_handler: FreqHandler)
                     -> SegmentPostings<'a> {
        SegmentPostings {
            len: len as usize,
            block_len: len as usize,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: freq_handler,
            remaining_data: data,
            cur: Wrapping(usize::max_value()),
            delete_bitset: delete_bitset.clone(),
        }
    }

    /// Returns an empty segment postings object
    pub fn empty() -> SegmentPostings<'static> {
        SegmentPostings {
            len: 0,
            block_len: 0,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: FreqHandler::new_without_freq(),
            remaining_data: &EMPTY_DATA,
            delete_bitset: DeleteBitSet::empty(),
            cur: Wrapping(usize::max_value()),
        }
    }

    /// Index within a block is used as an address when
    /// interacting with the `FreqHandler`
    fn index_within_block(&self) -> usize {
        self.cur.0 % NUM_DOCS_PER_BLOCK
    }

    /// Sets the current position to a location relative
    /// to the current block
    #[inline]
    fn set_within_block(&mut self, inner_pos: usize) {
        self.cur = Wrapping(self.cur.0 & !(NUM_DOCS_PER_BLOCK - 1)) + Wrapping(inner_pos)
    }
}

impl<'a> DocSet for SegmentPostings<'a> {
    // goes to the next element.
    // next needs to be called a first time to point to the correct element.
    #[inline]
    fn advance(&mut self) -> bool {
        loop {
            self.cur += Wrapping(1);
            if self.cur.0 >= self.len {
                return false;
            }
            if self.index_within_block() == 0 {
                self.load_next_block();
            }
            if !self.delete_bitset.is_deleted(self.doc()) {
                return true;
            }
        }
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        if !self.advance() {
            return SkipResult::End;
        }

        let mut pos = self.index_within_block();
        // skip blocks until one that might contain the target
        loop {
            // check if we need to go to the next block
            if target > self.block_decoder.output(self.block_len - 1) {
                self.cur += Wrapping(self.block_len - pos);
                self.load_next_block();
                pos = 0;

                // there was no more data
                if self.cur.0 == self.len {
                    return SkipResult::End;
                }
            } else if target < self.block_decoder.output(pos) {
                // We've overpassed the target after the first `advance` call
                // or we're at the beginning of a block.
                // Either way, we're on the first `DocId` greater than `target`
                return SkipResult::OverStep;
            } else {
                break;
            }
        }

        debug_assert!(target >= self.block_decoder.output(pos));
        debug_assert!(target <= self.block_decoder.output(self.block_len - 1));

        // we're in the right block, do a binary search
        let mut start = pos;
        let mut count = self.block_len - start;
        while count > 0 {
            let step = count / 2;
            let mid = start + step;
            let doc = self.block_decoder.output(mid);
            if doc < target {
                start = mid + 1;
                count -= step + 1;
            } else {
                count = step;
            }
        }

        // `doc` is now >= `target`
        let doc = self.block_decoder.output(start);
        self.set_within_block(start);

        if !self.delete_bitset.is_deleted(doc) {
            if doc == target {
                return SkipResult::Reached;
            } else {
                return SkipResult::OverStep;
            }
        }

        if self.advance() {
            return SkipResult::OverStep;
        }
        return SkipResult::End;
    }

    #[inline]
    fn doc(&self) -> DocId {
        self.block_decoder.output(self.index_within_block())
    }
}

impl<'a> HasLen for SegmentPostings<'a> {
    fn len(&self) -> usize {
        self.len
    }
}

impl<'a> Postings for SegmentPostings<'a> {
    fn term_freq(&self) -> u32 {
        self.freq_handler.freq(self.index_within_block())
    }

    fn positions(&self) -> &[u32] {
        self.freq_handler.positions(self.index_within_block())
    }
}
<commit_msg>Use an exponential search<commit_after>use compression::{NUM_DOCS_PER_BLOCK, BlockDecoder, VIntDecoder};
use DocId;
use postings::{Postings, FreqHandler, DocSet, HasLen, SkipResult};
use std::cmp;
use std::num::Wrapping;
use fastfield::DeleteBitSet;

const EMPTY_DATA: [u8; 0] = [0u8; 0];

/// `SegmentPostings` represents the inverted list or postings associated to
/// a term in a `Segment`.
///
/// As we iterate through the `SegmentPostings`, the frequencies are optionally decoded.
/// Positions on the other hand, are optionally entirely decoded upfront.
pub struct SegmentPostings<'a> {
    len: usize,
    // Removing this makes the code slower
    // See https://github.com/tantivy-search/tantivy/issues/89
    block_len: usize,
    doc_offset: u32,
    block_decoder: BlockDecoder,
    freq_handler: FreqHandler,
    remaining_data: &'a [u8],
    cur: Wrapping<usize>,
    delete_bitset: DeleteBitSet,
}

impl<'a> SegmentPostings<'a> {
    fn load_next_block(&mut self) {
        let num_remaining_docs = self.len - self.cur.0;
        if num_remaining_docs >= NUM_DOCS_PER_BLOCK {
            self.remaining_data =
                self.block_decoder
                    .uncompress_block_sorted(self.remaining_data, self.doc_offset);
            self.remaining_data = self.freq_handler.read_freq_block(self.remaining_data);
            self.doc_offset = self.block_decoder.output(NUM_DOCS_PER_BLOCK - 1);
            self.block_len = NUM_DOCS_PER_BLOCK;
        } else {
            self.remaining_data =
                self.block_decoder
                    .uncompress_vint_sorted(self.remaining_data,
                                            self.doc_offset,
                                            num_remaining_docs);
            self.freq_handler
                .read_freq_vint(self.remaining_data, num_remaining_docs);
            self.block_len = num_remaining_docs;
        }
    }

    /// Reads a Segment postings from an &[u8]
    ///
    /// * `len` - number of document in the posting lists.
    /// * `data` - data array. The complete data is not necessarily used.
    /// * `freq_handler` - the freq handler is in charge of decoding
    ///   frequencies and/or positions
    pub fn from_data(len: u32,
                     data: &'a [u8],
                     delete_bitset: &'a DeleteBitSet,
                     freq_handler: FreqHandler)
                     -> SegmentPostings<'a> {
        SegmentPostings {
            len: len as usize,
            block_len: len as usize,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: freq_handler,
            remaining_data: data,
            cur: Wrapping(usize::max_value()),
            delete_bitset: delete_bitset.clone(),
        }
    }

    /// Returns an empty segment postings object
    pub fn empty() -> SegmentPostings<'static> {
        SegmentPostings {
            len: 0,
            block_len: 0,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: FreqHandler::new_without_freq(),
            remaining_data: &EMPTY_DATA,
            delete_bitset: DeleteBitSet::empty(),
            cur: Wrapping(usize::max_value()),
        }
    }

    /// Index within a block is used as an address when
    /// interacting with the `FreqHandler`
    fn index_within_block(&self) -> usize {
        self.cur.0 % NUM_DOCS_PER_BLOCK
    }

    /// Sets the current position to a location relative
    /// to the current block
    #[inline]
    fn set_within_block(&mut self, inner_pos: usize) {
        self.cur = Wrapping(self.cur.0 & !(NUM_DOCS_PER_BLOCK - 1)) + Wrapping(inner_pos)
    }
}

impl<'a> DocSet for SegmentPostings<'a> {
    // goes to the next element.
    // next needs to be called a first time to point to the correct element.
    #[inline]
    fn advance(&mut self) -> bool {
        loop {
            self.cur += Wrapping(1);
            if self.cur.0 >= self.len {
                return false;
            }
            if self.index_within_block() == 0 {
                self.load_next_block();
            }
            if !self.delete_bitset.is_deleted(self.doc()) {
                return true;
            }
        }
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        if !self.advance() {
            return SkipResult::End;
        }

        let mut pos = self.index_within_block();
        // skip blocks until one that might contain the target
        loop {
            // check if we need to go to the next block
            if target > self.block_decoder.output(self.block_len - 1) {
                self.cur += Wrapping(self.block_len - pos);
                self.load_next_block();
                pos = 0;

                // there was no more data
                if self.cur.0 == self.len {
                    return SkipResult::End;
                }
            } else if target < self.block_decoder.output(pos) {
                // We've overpassed the target after the first `advance` call
                // or we're at the beginning of a block.
                // Either way, we're on the first `DocId` greater than `target`
                return SkipResult::OverStep;
            } else {
                break;
            }
        }

        debug_assert!(target >= self.block_decoder.output(pos));
        debug_assert!(target <= self.block_decoder.output(self.block_len - 1));

        // we're in the right block now, start with an exponential search
        let mut start = pos;
        let mut end = self.block_len;
        let mut count = 1;
        loop {
            let new = start + count;
            if new < end && self.block_decoder.output(new) < target {
                start = new;
                count *= 2;
            } else {
                break;
            }
        }
        end = cmp::min(start + count, end);

        // now do a binary search
        let mut count = end - start;
        while count > 0 {
            let step = count / 2;
            let mid = start + step;
            let doc = self.block_decoder.output(mid);
            if doc < target {
                start = mid + 1;
                count -= step + 1;
            } else {
                count = step;
            }
        }

        // `doc` is now >= `target`
        let doc = self.block_decoder.output(start);
        self.set_within_block(start);

        if !self.delete_bitset.is_deleted(doc) {
            if doc == target {
                return SkipResult::Reached;
            } else {
                return SkipResult::OverStep;
            }
        }

        if self.advance() {
            return SkipResult::OverStep;
        }
        return SkipResult::End;
    }

    #[inline]
    fn doc(&self) -> DocId {
        self.block_decoder.output(self.index_within_block())
    }
}

impl<'a> HasLen for SegmentPostings<'a> {
    fn len(&self) -> usize {
        self.len
    }
}

impl<'a> Postings for SegmentPostings<'a> {
    fn term_freq(&self) -> u32 {
        self.freq_handler.freq(self.index_within_block())
    }

    fn positions(&self) -> &[u32] {
        self.freq_handler.positions(self.index_within_block())
    }
}
<|endoftext|>


<commit_before>use std::num::{Zero, One, Real, NumCast};
use nalgebra::traits::division_ring::DivisionRing;
use nalgebra::traits::iterable::Iterable;
use nalgebra::traits::indexable::Indexable;
use nalgebra::traits::dim::Dim;
use ncollide::geom::transformed::Transformed;
use ncollide::geom::ball::Ball;
use ncollide::geom::box::Box;
use ncollide::geom::plane::Plane;
use object::implicit_geom::{DefaultGeom, Plane, Ball, Implicit};

pub trait Volumetric<N, II> {
    fn volume(&self)      -> N;
    fn inertia(&self, &N) -> II;
}

impl<G: Volumetric<N, II>, M, N, II> Volumetric<N, II> for Transformed<G, M, N> {
    fn volume(&self) -> N {
        self.geom().volume()
    }

    fn inertia(&self, mass: &N) -> II {
        // FIXME: take in account the transform
        self.geom().inertia(mass)
    }
}

impl<N: Real + DivisionRing + NumCast + Clone,
     V: Clone + Iterable<N> + Dim,
     M,
     II: Zero + Indexable<(uint, uint), N>>
Volumetric<N, II> for DefaultGeom<N, V, M, II> {
    #[inline]
    fn volume(&self) -> N {
        match *self {
            // FIXME: dont know why the compiler is not happy calling volume() on Plane and Ball
            Plane(_)        => Zero::zero(), // p.volume(),
            Ball(ref b)     => ball_volume(b.radius(), Dim::dim::<V>()), // b.volume(),
            Implicit(ref i) => i.volume()
        }
    }

    #[inline]
    fn inertia(&self, mass: &N) -> II {
        match *self {
            Plane(ref p)    => p.inertia(mass),
            Ball(ref b)     => b.inertia(mass),
            Implicit(ref i) => i.inertia(mass)
        }
    }
}

fn ball_volume<N: Real + DivisionRing + NumCast>(radius: N, dim: uint) -> N {
    Real::pi::<N>() * radius.pow(&NumCast::from::<N, uint>(dim))
}

impl<N: Real + DivisionRing + NumCast + Clone,
     V: Clone + Dim,
     II: Zero + Indexable<(uint, uint), N>>
Volumetric<N, II> for Ball<N, V> {
    #[inline]
    fn volume(&self)  -> N {
        ball_volume(self.radius(), Dim::dim::<V>())
    }

    #[inline]
    fn inertia(&self, mass: &N) -> II {
        let dim = Dim::dim::<V>();

        if dim == 2 {
            let diag = self.radius() * self.radius() * *mass / NumCast::from::<N, float>(2.0);

            let mut res = Zero::zero::<II>();

            res.set((0, 0), diag);

            res
        }
        else if dim == 3 {
            let _0   = Zero::zero::<N>();
            let diag = NumCast::from::<N, float>(2.0 / 5.0) *
                       *mass                                *
                       self.radius()                        *
                       self.radius();

            let mut res = Zero::zero::<II>();

            res.set((0, 0), diag.clone());
            res.set((1, 1), diag.clone());
            res.set((2, 2), diag.clone());

            res
        }
        else {
            fail!("Inertia tensor for n-dimensional boxes, n > 3, is not implemented.")
        }
    }
}

impl<N:  Zero + One + NumCast + DivisionRing + Clone,
     V:  Clone + Iterable<N> + Indexable<uint, N> + Dim,
     II: Zero + Indexable<(uint, uint), N>>
Volumetric<N, II> for Box<N, V> {
    #[inline]
    fn volume(&self) -> N {
        let mut res  = One::one::<N>();

        let he = self.half_extents();

        for half_extent in he.iter() {
            res = res * *half_extent * NumCast::from::<N, float>(2.0)
        }

        res
    }

    #[inline]
    fn inertia(&self, mass: &N) -> II {
        let dim = Dim::dim::<V>();

        if dim == 2 {
            let _2   = NumCast::from::<N, float>(2.0);
            let _i12 = NumCast::from::<N, float>(1.0 / 12.0);
            let w    = _i12 * *mass * _2 * _2;
            let ix   = w * self.half_extents().at(0) * self.half_extents().at(0);
            let iy   = w * self.half_extents().at(1) * self.half_extents().at(1);

            let mut res = Zero::zero::<II>();

            res.set((0, 0), ix + iy);

            res
        }
        else if dim == 3 {
            let _0   = Zero::zero::<N>();
            let _2   = NumCast::from::<N, float>(2.0);
            let _i12 = NumCast::from::<N, float>(1.0 / 12.0);
            let w    = _i12 * *mass * _2 * _2;
            let ix   = w * self.half_extents().at(0) * self.half_extents().at(0);
            let iy   = w * self.half_extents().at(1) * self.half_extents().at(1);
            let iz   = w * self.half_extents().at(2) * self.half_extents().at(2);

            let mut res  = Zero::zero::<II>();

            res.set((0, 0), iy + iz);
            res.set((1, 1), ix + iz);
            res.set((2, 2), ix + iy);

            res
        }
        else {
            fail!("Inertia tensor for n-dimensional boxes, n > 3, is not implemented.")
        }
    }
}

impl<N: Zero, V, II: Zero> Volumetric<N, II> for Plane<V> {
    #[inline]
    fn volume(&self) -> N {
        Zero::zero()
    }

    #[inline]
    fn inertia(&self, _: &N) -> II {
        Zero::zero()
    }
}
<commit_msg>Add Volumetric impls. for Cone and Cylinder.<commit_after>use std::num::{Zero, One, Real, NumCast};
use nalgebra::traits::division_ring::DivisionRing;
use nalgebra::traits::iterable::Iterable;
use nalgebra::traits::indexable::Indexable;
use nalgebra::traits::dim::Dim;
use ncollide::geom::transformed::Transformed;
use ncollide::geom::ball::Ball;
use ncollide::geom::box::Box;
use ncollide::geom::cylinder::Cylinder;
use ncollide::geom::cone::Cone;
use ncollide::geom::plane::Plane;
use object::implicit_geom::{DefaultGeom, Plane, Ball, Implicit};

pub trait Volumetric<N, II> {
    fn volume(&self)      -> N;
    fn inertia(&self, &N) -> II;
}

impl<G: Volumetric<N, II>, M, N, II> Volumetric<N, II> for Transformed<G, M, N> {
    fn volume(&self) -> N {
        self.geom().volume()
    }

    fn inertia(&self, mass: &N) -> II {
        // FIXME: take in account the transform
        self.geom().inertia(mass)
    }
}

impl<N: Real + DivisionRing + NumCast + Clone,
     V: Clone + Iterable<N> + Dim,
     M,
     II: Zero + Indexable<(uint, uint), N>>
Volumetric<N, II> for DefaultGeom<N, V, M, II> {
    #[inline]
    fn volume(&self) -> N {
        match *self {
            // FIXME: dont know why the compiler is not happy calling volume() on Plane and Ball
            Plane(_)        => Zero::zero(), // p.volume(),
            Ball(ref b)     => ball_volume(b.radius(), Dim::dim::<V>()), // b.volume(),
            Implicit(ref i) => i.volume()
        }
    }

    #[inline]
    fn inertia(&self, mass: &N) -> II {
        match *self {
            Plane(ref p)    => p.inertia(mass),
            Ball(ref b)     => b.inertia(mass),
            Implicit(ref i) => i.inertia(mass)
        }
    }
}

fn ball_volume<N: Real + DivisionRing + NumCast>(radius: N, dim: uint) -> N {
    Real::pi::<N>() * radius.pow(&NumCast::from::<N, uint>(dim))
}

impl<N: Real + DivisionRing + NumCast + Clone,
     V: Clone + Dim,
     II: Zero + Indexable<(uint, uint), N>>
Volumetric<N, II> for Ball<N, V> {
    #[inline]
    fn volume(&self)  -> N {
        ball_volume(self.radius(), Dim::dim::<V>())
    }

    fn inertia(&self, mass: &N) -> II {
        let dim = Dim::dim::<V>();

        if dim == 2 {
            let diag = self.radius() * self.radius() * *mass / NumCast::from::<N, float>(2.0);

            let mut res = Zero::zero::<II>();

            res.set((0, 0), diag);

            res
        }
        else if dim == 3 {
            let _0   = Zero::zero::<N>();
            let diag = NumCast::from::<N, float>(2.0 / 5.0) *
                       *mass                                *
                       self.radius()                        *
                       self.radius();

            let mut res = Zero::zero::<II>();

            res.set((0, 0), diag.clone());
            res.set((1, 1), diag.clone());
            res.set((2, 2), diag.clone());

            res
        }
        else {
            fail!("Inertia tensor for n-dimensional boxes, n > 3, is not implemented.")
        }
    }
}

impl<N:  Zero + One + NumCast + DivisionRing + Clone,
     V:  Clone + Iterable<N> + Indexable<uint, N> + Dim,
     II: Zero + Indexable<(uint, uint), N>>
Volumetric<N, II> for Box<N, V> {
    fn volume(&self) -> N {
        let mut res  = One::one::<N>();

        let he = self.half_extents();

        for half_extent in he.iter() {
            res = res * *half_extent * NumCast::from::<N, float>(2.0)
        }

        res
    }

    fn inertia(&self, mass: &N) -> II {
        let dim = Dim::dim::<V>();

        if dim == 2 {
            let _2   = NumCast::from::<N, float>(2.0);
            let _i12 = NumCast::from::<N, float>(1.0 / 12.0);
            let w    = _i12 * *mass * _2 * _2;
            let ix   = w * self.half_extents().at(0) * self.half_extents().at(0);
            let iy   = w * self.half_extents().at(1) * self.half_extents().at(1);

            let mut res = Zero::zero::<II>();

            res.set((0, 0), ix + iy);

            res
        }
        else if dim == 3 {
            let _0   = Zero::zero::<N>();
            let _2   = NumCast::from::<N, float>(2.0);
            let _i12 = NumCast::from::<N, float>(1.0 / 12.0);
            let w    = _i12 * *mass * _2 * _2;
            let ix   = w * self.half_extents().at(0) * self.half_extents().at(0);
            let iy   = w * self.half_extents().at(1) * self.half_extents().at(1);
            let iz   = w * self.half_extents().at(2) * self.half_extents().at(2);

            let mut res  = Zero::zero::<II>();

            res.set((0, 0), iy + iz);
            res.set((1, 1), ix + iz);
            res.set((2, 2), ix + iy);

            res
        }
        else {
            fail!("Inertia tensor for n-dimensional boxes, n > 3, is not implemented.")
        }
    }
}

impl<N:  Zero + One + NumCast + DivisionRing + Real + Clone,
     II: Zero + Dim + Indexable<(uint, uint), N>>
Volumetric<N, II> for Cylinder<N> {
    fn volume(&self) -> N {
        let dim = Dim::dim::<II>();

        if dim == 2 {
            // same as a rectangle
            self.half_height() * self.radius() * NumCast::from(4.0f64)
        }
        else if dim == 3 {
            self.half_height() * self.radius() * self.radius() * Real::pi() * NumCast::from(2.0f64)
        }
        else {
            fail!("Volume for n-dimensional cylinders, n > 3, is not implemented.")
        }
    }

    fn inertia(&self, mass: &N) -> II {
        let dim = Dim::dim::<II>();

        if dim == 2 {
            // same as the box
            let _2:   N = NumCast::from(2.0f64);
            let _i12: N = NumCast::from(1.0f64 / 12.0);
            let w       = _i12 * *mass * _2 * _2;
            let ix      = w * self.half_height() * self.half_height();
            let iy      = w * self.radius() * self.radius();

            let mut res = Zero::zero::<II>();

            res.set((0, 0), ix + iy);

            res
        }
        else if dim == 3 {
            let sq_radius = self.radius() * self.radius();
            let sq_height = self.half_height() * self.half_height() * NumCast::from(4.0f64);
            let off_principal = mass * (NumCast::from::<N, f64>(3.0) * sq_radius + sq_height)
                                / NumCast::from::<N, f64>(12.0);

            let mut res = Zero::zero::<II>();

            res.set((0, 0), mass * sq_radius / NumCast::from(2.0f64));
            res.set((1, 1), off_principal.clone());
            res.set((2, 2), off_principal);

            res
        }
        else {
            fail!("Inertia tensor for n-dimensional cylinder, n > 3, is not implemented.")
        }
    }
}

impl<N:  Zero + One + NumCast + DivisionRing + Real + Clone,
     II: Zero + Dim + Indexable<(uint, uint), N>>
Volumetric<N, II> for Cone<N> {
    fn volume(&self) -> N {
        let dim = Dim::dim::<II>();

        if dim == 2 {
            // same as a isosceles triangle
            self.radius() * self.half_height() * NumCast::from(2.0f64)
        }
        else if dim == 3 {
            self.radius() * self.radius()      *
            Real::pi()    * self.half_height() *
            NumCast::from(2.0f64 / 3.0)
        }
        else {
            fail!("Volume for n-dimensional cone, n > 3, is not implemented.")
        }
    }

    fn inertia(&self, mass: &N) -> II {
        let dim = Dim::dim::<II>();

        if dim == 2 {
            // FIXME: not sure about that…
            let mut res = Zero::zero::<II>();

            res.set(
                (0, 0),
                self.radius() * self.half_height() * self.half_height() * self.half_height()
                              / NumCast::from(3.0f64)
            );

            res
        }
        else if dim == 3 {
            let m_sq_radius = mass * self.radius() * self.radius();
            let m_sq_height = mass * self.half_height() * self.half_height() *
                                     NumCast::from(4.0f64);
            let off_principal = NumCast::from::<N, f64>(3.0 / 20.0) * m_sq_radius +
                                NumCast::from::<N, f64>(3.0 / 5.0)  * m_sq_height;

            let principal = NumCast::from::<N, f64>(3.0 / 10.0) * m_sq_radius;

            let mut res = Zero::zero::<II>();

            res.set((0, 0), principal);
            res.set((1, 1), off_principal.clone());
            res.set((2, 2), off_principal);

            res
        }

        else {
            fail!("Inertia tensor for n-dimensional cone, n > 3, is not implemented.")
        }
    }
}

impl<N: Zero, V, II: Zero> Volumetric<N, II> for Plane<V> {
    #[inline]
    fn volume(&self) -> N {
        Zero::zero()
    }

    #[inline]
    fn inertia(&self, _: &N) -> II {
        Zero::zero()
    }
}
<|endoftext|>


<commit_before>use std::{
    fmt::{self, Display, Formatter},
    fs::{self, read_to_string},
    path::{Path, PathBuf},
    sync::Arc,
};

use salsa::query_group;

use crate::database::PROJECT_DIRECTORY;

#[query_group(InputDbStorage)]
pub trait InputDb: InputWatcher {
    fn get_input(&self, input: Input) -> Option<Arc<String>>;
    fn get_open_input(&self, input: Input) -> Option<Arc<String>>;
}

fn get_input(db: &dyn InputDb, input: Input) -> Option<Arc<String>> {
    if let Some(content) = db.get_open_input(input.clone()) {
        return Some(content);
    };

    match input {
        Input::File(_) | Input::ExternalFile(_) => {
            let path = input.to_path().unwrap();
            match read_to_string(path.clone()) {
                Ok(content) => Some(Arc::new(content)),
                Err(error) if matches!(error.kind(), std::io::ErrorKind::NotFound) => None,
                _ => panic!("Unexpected error when reading file {:?}.", path),
            }
        }
        Input::Untitled(_) => None,
    }
}
fn get_open_input(db: &dyn InputDb, input: Input) -> Option<Arc<String>> {
    // The following line of code shouldn't be neccessary, but it is.
    //
    // We call `GetOpenInputQuery.in_db_mut(self).invalidate(input);`
    // in `Database.did_open_input(…)`, `.did_change_input(…)`, and
    // `.did_close_input(…)` which correctly forces Salsa to re-run this query
    // function the next time this input is used. However, even though the
    // return value changes, Salsa doesn't record an updated `changed_at` value
    // in its internal `ActiveQuery` struct. `Runtime.report_untracked_read()`
    // manually sets this to the current revision.
    db.salsa_runtime().report_untracked_read();

    let content = db.get_open_input_raw(&input)?;
    Some(Arc::new(content))
}

pub trait InputWatcher {
    fn get_open_input_raw(&self, input: &Input) -> Option<String>;
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
pub enum Input {
    /// Contains the path components from [PROJECT_DIRECTORY] to the file.
    ///
    /// `.` and `..` are not allowed.
    File(Vec<String>),
    /// A file not belonging to the current project.
    ///
    /// This is temporary and should become obsolete when we support packages.
    ExternalFile(PathBuf),
    Untitled(String),
}

impl From<PathBuf> for Input {
    fn from(path: PathBuf) -> Self {
        let project_dir = PROJECT_DIRECTORY.lock().unwrap().clone().unwrap();
        let path = match fs::canonicalize(&path)
            .expect("Path does not exist or is invalid.")
            .strip_prefix(fs::canonicalize(project_dir).unwrap().clone())
        {
            Ok(path) => path.to_owned(),
            Err(_) => return Input::ExternalFile(path),
        };

        let components = path
            .components()
            .into_iter()
            .map(|it| match it {
                std::path::Component::Prefix(_) => unreachable!(),
                std::path::Component::RootDir => unreachable!(),
                std::path::Component::CurDir => panic!("`.` is not allowed in an input path."),
                std::path::Component::ParentDir => {
                    panic!("`..` is not allowed in an input path.")
                }
                std::path::Component::Normal(it) => {
                    it.to_str().expect("Invalid UTF-8 in path.").to_owned()
                }
            })
            .collect();
        Input::File(components)
    }
}
impl Input {
    pub fn to_path(&self) -> Option<PathBuf> {
        match self {
            Input::File(components) => {
                let mut path = PROJECT_DIRECTORY.lock().unwrap().clone().unwrap().clone();
                for component in components {
                    path.push(component);
                }
                Some(path)
            }
            Input::ExternalFile(path) => Some(path.clone()),
            Input::Untitled(_) => None,
        }
    }
}
impl Display for Input {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Input::File(components) => {
                write!(f, "project-file:")?;
                if let Some(component) = components.first() {
                    write!(f, "{}", component)?;
                }
                for component in &components[1..] {
                    write!(f, "/{}", component)?;
                }
                Ok(())
            }
            Input::ExternalFile(path) => write!(f, "external-file:{}", path.display()),
            Input::Untitled(name) => write!(f, "untitled:{}", name),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{
        compiler::{
            cst::{self, Cst, CstKind},
            string_to_cst::StringToCst,
        },
        database::Database,
    };

    #[test]
    fn on_demand_input_works() {
        let mut db = Database::default();
        let input: Input = PathBuf::from("/foo.rs").into();

        db.did_open_input(&input, "123".to_owned());
        assert_eq!(
            db.get_input(input.clone()).unwrap().as_ref().to_owned(),
            "123"
        );
        assert_eq!(
            db.cst(input.clone()).unwrap().as_ref().to_owned(),
            vec![Cst {
                id: cst::Id(0),
                kind: CstKind::LeadingWhitespace {
                    value: "\n".to_owned(),
                    child: Box::new(Cst {
                        id: cst::Id(1),
                        kind: CstKind::Int {
                            offset: 0,
                            value: 123,
                            source: "123".to_owned(),
                        }
                    })
                }
            }],
        );

        db.did_change_input(&input, "456".to_owned());
        assert_eq!(
            db.get_input(input.clone()).unwrap().as_ref().to_owned(),
            "456"
        );
        assert_eq!(
            db.cst(input.clone()).unwrap().as_ref().to_owned(),
            vec![Cst {
                id: cst::Id(0),
                kind: CstKind::LeadingWhitespace {
                    value: "\n".to_owned(),
                    child: Box::new(Cst {
                        id: cst::Id(1),
                        kind: CstKind::Int {
                            offset: 0,
                            value: 456,
                            source: "456".to_owned(),
                        }
                    })
                }
            }],
        );

        db.did_close_input(&input);
    }
}
<commit_msg>refactor(compiler): remove unused import<commit_after>use std::{
    fmt::{self, Display, Formatter},
    fs::{self, read_to_string},
    path::PathBuf,
    sync::Arc,
};

use salsa::query_group;

use crate::database::PROJECT_DIRECTORY;

#[query_group(InputDbStorage)]
pub trait InputDb: InputWatcher {
    fn get_input(&self, input: Input) -> Option<Arc<String>>;
    fn get_open_input(&self, input: Input) -> Option<Arc<String>>;
}

fn get_input(db: &dyn InputDb, input: Input) -> Option<Arc<String>> {
    if let Some(content) = db.get_open_input(input.clone()) {
        return Some(content);
    };

    match input {
        Input::File(_) | Input::ExternalFile(_) => {
            let path = input.to_path().unwrap();
            match read_to_string(path.clone()) {
                Ok(content) => Some(Arc::new(content)),
                Err(error) if matches!(error.kind(), std::io::ErrorKind::NotFound) => None,
                _ => panic!("Unexpected error when reading file {:?}.", path),
            }
        }
        Input::Untitled(_) => None,
    }
}
fn get_open_input(db: &dyn InputDb, input: Input) -> Option<Arc<String>> {
    // The following line of code shouldn't be neccessary, but it is.
    //
    // We call `GetOpenInputQuery.in_db_mut(self).invalidate(input);`
    // in `Database.did_open_input(…)`, `.did_change_input(…)`, and
    // `.did_close_input(…)` which correctly forces Salsa to re-run this query
    // function the next time this input is used. However, even though the
    // return value changes, Salsa doesn't record an updated `changed_at` value
    // in its internal `ActiveQuery` struct. `Runtime.report_untracked_read()`
    // manually sets this to the current revision.
    db.salsa_runtime().report_untracked_read();

    let content = db.get_open_input_raw(&input)?;
    Some(Arc::new(content))
}

pub trait InputWatcher {
    fn get_open_input_raw(&self, input: &Input) -> Option<String>;
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
pub enum Input {
    /// Contains the path components from [PROJECT_DIRECTORY] to the file.
    ///
    /// `.` and `..` are not allowed.
    File(Vec<String>),
    /// A file not belonging to the current project.
    ///
    /// This is temporary and should become obsolete when we support packages.
    ExternalFile(PathBuf),
    Untitled(String),
}

impl From<PathBuf> for Input {
    fn from(path: PathBuf) -> Self {
        let project_dir = PROJECT_DIRECTORY.lock().unwrap().clone().unwrap();
        let path = match fs::canonicalize(&path)
            .expect("Path does not exist or is invalid.")
            .strip_prefix(fs::canonicalize(project_dir).unwrap().clone())
        {
            Ok(path) => path.to_owned(),
            Err(_) => return Input::ExternalFile(path),
        };

        let components = path
            .components()
            .into_iter()
            .map(|it| match it {
                std::path::Component::Prefix(_) => unreachable!(),
                std::path::Component::RootDir => unreachable!(),
                std::path::Component::CurDir => panic!("`.` is not allowed in an input path."),
                std::path::Component::ParentDir => {
                    panic!("`..` is not allowed in an input path.")
                }
                std::path::Component::Normal(it) => {
                    it.to_str().expect("Invalid UTF-8 in path.").to_owned()
                }
            })
            .collect();
        Input::File(components)
    }
}
impl Input {
    pub fn to_path(&self) -> Option<PathBuf> {
        match self {
            Input::File(components) => {
                let mut path = PROJECT_DIRECTORY.lock().unwrap().clone().unwrap().clone();
                for component in components {
                    path.push(component);
                }
                Some(path)
            }
            Input::ExternalFile(path) => Some(path.clone()),
            Input::Untitled(_) => None,
        }
    }
}
impl Display for Input {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Input::File(components) => {
                write!(f, "project-file:")?;
                if let Some(component) = components.first() {
                    write!(f, "{}", component)?;
                }
                for component in &components[1..] {
                    write!(f, "/{}", component)?;
                }
                Ok(())
            }
            Input::ExternalFile(path) => write!(f, "external-file:{}", path.display()),
            Input::Untitled(name) => write!(f, "untitled:{}", name),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{
        compiler::{
            cst::{self, Cst, CstKind},
            string_to_cst::StringToCst,
        },
        database::Database,
    };

    #[test]
    fn on_demand_input_works() {
        let mut db = Database::default();
        let input: Input = PathBuf::from("/foo.rs").into();

        db.did_open_input(&input, "123".to_owned());
        assert_eq!(
            db.get_input(input.clone()).unwrap().as_ref().to_owned(),
            "123"
        );
        assert_eq!(
            db.cst(input.clone()).unwrap().as_ref().to_owned(),
            vec![Cst {
                id: cst::Id(0),
                kind: CstKind::LeadingWhitespace {
                    value: "\n".to_owned(),
                    child: Box::new(Cst {
                        id: cst::Id(1),
                        kind: CstKind::Int {
                            offset: 0,
                            value: 123,
                            source: "123".to_owned(),
                        }
                    })
                }
            }],
        );

        db.did_change_input(&input, "456".to_owned());
        assert_eq!(
            db.get_input(input.clone()).unwrap().as_ref().to_owned(),
            "456"
        );
        assert_eq!(
            db.cst(input.clone()).unwrap().as_ref().to_owned(),
            vec![Cst {
                id: cst::Id(0),
                kind: CstKind::LeadingWhitespace {
                    value: "\n".to_owned(),
                    child: Box::new(Cst {
                        id: cst::Id(1),
                        kind: CstKind::Int {
                            offset: 0,
                            value: 456,
                            source: "456".to_owned(),
                        }
                    })
                }
            }],
        );

        db.did_close_input(&input);
    }
}
<|endoftext|>


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

//! Various subroutines for computing a distance between sequences.
//! Complexity: O(n) for strings of length n for the Hamming distance;
//! O(n * m) for strings of length n and m for the Levenshtein (or edit) distance.
//!
//! # Example
//!
//! ```
//! use bio::alignment::distance::*;
//!
//! let x = b"GTCTGCATGCG";
//! let y = b"TTTAGCTAGCG";
//! // GTCTGCATGCG
//! //  |  ||  |||
//! // TTTAGCTAGCG
//! match hamming(x, y) {
//!     Ok(s)  => println!("Score is: {}", s),  // Score is 5
//!     Err(e) => println!("Error: {}", e),     // No error in this example
//! }
//!
//! let x = b"ACCGTGGAT";
//! let y = b"AAAAACCGTTGAT";
//! // ----ACCGTGGAT
//! //     ||||| |||
//! // AAAAACCGTTGAT
//! let l_score = levenshtein(x, y);  // Score is 5
//! assert_eq!(l_score, 5);
//! ```

use itertools::multizip;
use std::cmp::min;
use std::result::Result;

use utils::TextSlice;

/// Compute the Hamming distance between two strings with `hamming`.
/// It returns the `Result<u32, &str>` type
/// with the first element corresponding to the distance between two strings
/// (a number of mismatches) and the second one to the error message
/// when two strings are not of equal sizes.
///
/// # Example
///
/// ```
/// use bio::alignment::distance::*;
///
/// let x = b"GTCTGCATGCG";
/// let y = b"TTTAGCTAGCG";
/// // GTCTGCATGCG
/// //  |  ||  |||
/// // TTTAGCTAGCG
/// match hamming(x, y) {
///     Ok(s)  => println!("Score is: {}", s),  // Score is 5
///     Err(e) => println!("Error: {}", e),     // No error in this example
/// }
/// assert!(hamming(x, y).is_ok());
/// assert_eq!(hamming(x, y).unwrap(), 5);
/// ```
///
/// In case of the error:
///
/// ```
/// use bio::alignment::distance::*;
///
/// let x = b"GACTATATCGA";
/// let y = b"TTTAGCTC";
/// match hamming(x, y) {
///     Ok(s)  => println!("Score is: {}", s),  // No score because strings are of unequal sizes.
///     Err(e) => println!("Error: {}", e),     // Will print "Error: hamming distance: strings are of unequal sizes!"
/// }
/// assert!(hamming(x, y).is_err());
/// ```
pub fn hamming(alpha: TextSlice, beta: TextSlice) -> Result<u32, &'static str> {
    if alpha.len() == beta.len() {
        let mut score: u32 = 0;
        for (a, b) in multizip((alpha, beta)) {
            if a != b {
                score += 1;
            }
        }
        Ok(score)
    } else {
        Err("hamming distance: strings are of unequal sizes!")
    }
}

/// Compute the Levenshtein (or Edit) distance between two strings with `levenshtein`. It returns a distance between two strings,
/// i.e. minimal number of mismatches, insertions and deletions between two strings.
///
/// # Example
///
/// ```
/// use bio::alignment::distance::*;
///
/// let x = b"ACCGTGGAT";
/// let y = b"AAAAACCGTTGAT";
/// // ----ACCGTGGAT
/// //     ||||| |||
/// // AAAAACCGTTGAT
/// let l_score = levenshtein(x, y);  // Score is 5
/// assert_eq!(l_score, 5);
/// ```
#[allow(unused_assignments)]
pub fn levenshtein(alpha: TextSlice, beta: TextSlice) -> u32 {
    let mut columns = [vec!(0u32; alpha.len() + 1), vec!(0u32; alpha.len() + 1)];
    let mut i_prev = 0;
    let mut i_cur = 1;

    for i in 0..columns[0].len() {
        columns[0][i] = i as u32;
    }

    for (j, item) in beta.iter().enumerate() {
        i_cur %= 2;
        i_prev = 1 - i_cur;

        columns[i_cur][0] = 1 + j as u32;
        for i in 1..columns[0].len() {
            columns[i_cur][i] = min(columns[i_prev][i - 1] +
                                    if alpha[i - 1] == *item { 0 } else { 1 },
                                    min(columns[i_cur][i - 1] + 1, columns[i_prev][i] + 1));
        }

        i_cur += 1;
    }

    columns[i_cur - 1][columns[0].len() - 1]
}

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

    #[test]
    fn test_hamming_dist_good() {
        let x = b"GTCTGCATGCG";
        let y = b"TTTAGCTAGCG";
        // GTCTGCATGCG
        //  |  ||  |||
        // TTTAGCTAGCG
        assert!(hamming(x, y).is_ok());
        assert_eq!(hamming(x, y).unwrap(), 5);
    }

    #[test]
    fn test_hamming_dist_bad() {
        let x = b"GACTATATCGA";
        let y = b"TTTAGCTC";
        assert!(hamming(x, y).is_err());
    }

    #[test]
    fn test_levenshtein_dist() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        // ----ACCGTGGAT
        //     ||||| |||
        // AAAAACCGTTGAT
        assert_eq!(levenshtein(x, y), 5);
        assert_eq!(levenshtein(x, y), levenshtein(y, x));
        assert_eq!(levenshtein(b"AAA", b"TTTT"), 4);
        assert_eq!(levenshtein(b"TTTT", b"AAA"), 4);
    }
}
<commit_msg>Improve distance API.<commit_after>// Copyright 2015-2017 Vadim Nazarov, Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various subroutines for computing a distance between sequences.

use itertools::multizip;
use std::cmp::min;

use utils::TextSlice;

/// Compute the Hamming distance between two strings. Complexity: O(n).
///
/// # Example
///
/// ```
/// use bio::alignment::distance::*;
///
/// let x = b"GTCTGCATGCG";
/// let y = b"TTTAGCTAGCG";
/// // GTCTGCATGCG
/// //  |  ||  |||
/// // TTTAGCTAGCG
/// assert_eq!(hamming(x, y), 5);
/// ```
pub fn hamming(alpha: TextSlice, beta: TextSlice) -> u64 {
    assert_eq!(
        alpha.len(), beta.len(),
        "hamming distance cannot be calculated for texts of different length ({}!={})",
        alpha.len(), beta.len()
    );
    let mut dist = 0;
    for (a, b) in multizip((alpha, beta)) {
        if a != b {
            dist += 1;
        }
    }
    dist
}

/// Compute the Levenshtein (or Edit) distance between two strings. Complexity: O(n * m) with
/// n and m being the length of the given texts.
///
/// # Example
///
/// ```
/// use bio::alignment::distance::*;
///
/// let x = b"ACCGTGGAT";
/// let y = b"AAAAACCGTTGAT";
/// // ----ACCGTGGAT
/// //     ||||| |||
/// // AAAAACCGTTGAT
/// let ldist = levenshtein(x, y);  // Distance is 5
/// assert_eq!(ldist, 5);
/// ```
#[allow(unused_assignments)]
pub fn levenshtein(alpha: TextSlice, beta: TextSlice) -> u32 {
    let mut columns = [vec!(0u32; alpha.len() + 1), vec!(0u32; alpha.len() + 1)];
    let mut i_prev = 0;
    let mut i_cur = 1;

    for i in 0..columns[0].len() {
        columns[0][i] = i as u32;
    }

    for (j, item) in beta.iter().enumerate() {
        i_cur %= 2;
        i_prev = 1 - i_cur;

        columns[i_cur][0] = 1 + j as u32;
        for i in 1..columns[0].len() {
            columns[i_cur][i] = min(columns[i_prev][i - 1] +
                                    if alpha[i - 1] == *item { 0 } else { 1 },
                                    min(columns[i_cur][i - 1] + 1, columns[i_prev][i] + 1));
        }

        i_cur += 1;
    }

    columns[i_cur - 1][columns[0].len() - 1]
}

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

    #[test]
    fn test_hamming_dist_good() {
        let x = b"GTCTGCATGCG";
        let y = b"TTTAGCTAGCG";
        // GTCTGCATGCG
        //  |  ||  |||
        // TTTAGCTAGCG
        assert_eq!(hamming(x, y), 5);
    }

    #[test]
    #[should_panic(expected = "hamming distance cannot be calculated for texts of different length (11!=8)")]
    fn test_hamming_dist_bad() {
        let x = b"GACTATATCGA";
        let y = b"TTTAGCTC";
        hamming(x, y);
    }

    #[test]
    fn test_levenshtein_dist() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        // ----ACCGTGGAT
        //     ||||| |||
        // AAAAACCGTTGAT
        assert_eq!(levenshtein(x, y), 5);
        assert_eq!(levenshtein(x, y), levenshtein(y, x));
        assert_eq!(levenshtein(b"AAA", b"TTTT"), 4);
        assert_eq!(levenshtein(b"TTTT", b"AAA"), 4);
    }
}
<|endoftext|>