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

use backend::StoreBackend;
use blob;
use capnp;
use errors::HatError;
use hash;
use hat::insert_path_handler::InsertPathHandler;
use hat::walker;
use key;
use root_capnp;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::str;
use util::{FileIterator, FnBox, PathHandler};
use filetime;

fn try_a_few_times_then_panic<F>(mut f: F, msg: &str)
    where F: FnMut() -> bool
{
    for _ in 1 as i32..5 {
        if f() {
            return;
        }
    }
    panic!(msg.to_owned());
}

pub mod recover {
    use hash;
    use hash::tree;
    use hat::walker;
    use std::collections::VecDeque;
    use std::mem;
    use super::parse_dir_data;

    #[derive(Clone)]
    pub struct Node {
        pub href: tree::HashRef,
        pub childs: Option<Vec<tree::HashRef>>,
    }

    pub struct FileVisitor {
        tops: Vec<hash::Hash>,
        nodes: VecDeque<Node>,
    }

    impl FileVisitor {
        pub fn new() -> FileVisitor {
            FileVisitor {
                tops: vec![],
                nodes: VecDeque::new(),
            }
        }
        pub fn tops(&mut self) -> Vec<hash::Hash> {
            mem::replace(&mut self.tops, vec![])
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl tree::Visitor for FileVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_enter(&mut self, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });

            // Do not proceed to read the actual file data.
            false
        }
        fn leaf_leave(&mut self, _chunk: Vec<u8>, _href: &tree::HashRef) -> bool {
            unreachable!();
        }
    }

    impl walker::LikesFiles for FileVisitor {
        fn include_file(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_some() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }

        fn include_dir(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_none() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }
    }

    pub struct DirVisitor {
        nodes: VecDeque<Node>,
        files: Vec<walker::FileEntry>,
    }

    impl DirVisitor {
        pub fn new() -> DirVisitor {
            DirVisitor {
                nodes: VecDeque::new(),
                files: vec![],
            }
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl walker::HasFiles for DirVisitor {
        fn files(&mut self) -> Vec<walker::FileEntry> {
            mem::replace(&mut self.files, vec![])
        }
    }

    impl tree::Visitor for DirVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_enter(&mut self, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });
            true
        }
        fn leaf_leave(&mut self, chunk: Vec<u8>, _href: &tree::HashRef) -> bool {
            parse_dir_data(&chunk[..], &mut self.files).unwrap();
            true
        }
    }
}

fn parse_dir_data(chunk: &[u8], mut out: &mut Vec<walker::FileEntry>) -> Result<(), HatError> {
    if chunk.is_empty() {
        return Ok(());
    }

    let reader = capnp::serialize_packed::read_message(&mut &chunk[..],
                                                       capnp::message::ReaderOptions::new())
        .unwrap();

    let list = reader.get_root::<root_capnp::file_list::Reader>().unwrap();
    for f in list.get_files().unwrap().iter() {
        if f.get_info()?.get_name().unwrap().len() == 0 {
            // Empty entry at end.
            // TODO(jos): Can we get rid of these?
            break;
        }
        let entry = key::Entry {
            id: Some(f.get_id()),
            info: key::Info::read(f.get_info()?.borrow())?,
            data_hash: match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    Some(r.unwrap().get_hash().unwrap().to_owned())
                }
                root_capnp::file::content::Directory(_) => None,
            },
            parent_id: None,
        };
        let hash_ref = match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    hash::tree::HashRef::read_msg(&r.expect("File has no data reference"))
                }
                root_capnp::file::content::Directory(d) => {
                    hash::tree::HashRef::read_msg(&d.expect("Directory has no listing reference"))
                }
            }
            .unwrap();

        out.push(walker::FileEntry {
            hash_ref: hash_ref,
            meta: entry,
        });
    }
    Ok(())
}

pub struct Family<B> {
    pub name: String,
    pub key_store: key::Store<B>,
    pub key_store_process: Vec<key::StoreProcess<FileIterator, B>>,
}
impl<B: StoreBackend> Clone for Family<B> {
    fn clone(&self) -> Family<B> {
        Family {
            name: self.name.clone(),
            key_store: self.key_store.clone(),
            key_store_process: self.key_store_process.clone(),
        }
    }
}

impl<B: StoreBackend> Family<B> {
    pub fn snapshot_dir(&self, dir: PathBuf) {
        let handler = InsertPathHandler::new(self.key_store_process.clone());
        handler.recurse(PathBuf::from(&dir), None);
    }

    pub fn snapshot_direct(&self,
                           file: key::Entry,
                           is_directory: bool,
                           contents: Option<FileIterator>)
                           -> Result<u64, HatError> {
        let f = if is_directory {
            None
        } else {
            Some(Box::new(move |()| contents) as Box<FnBox<(), _>>)
        };
        match self.key_store_process[0].send_reply(key::Msg::Insert(file, f))? {
            key::Reply::Id(id) => Ok(id),
            _ => Err(From::from("Unexpected reply from key store")),
        }
    }

    pub fn flush(&self) -> Result<(), HatError> {
        for ks in &self.key_store_process {
            if let key::Reply::FlushOk = ks.send_reply(key::Msg::Flush)? {
                continue;
            }
            return Err(From::from("Unexpected reply from key store"));
        }
        Ok(())
    }

  pub fn write_file_chunks<HTB: hash::tree::HashTreeBackend<Err=key::MsgError>>(
    &self, fd: &mut fs::File, tree: hash::tree::LeafIterator<HTB>)
  {
        for chunk in tree {
            try_a_few_times_then_panic(|| fd.write_all(&chunk[..]).is_ok(),
                                       "Could not write chunk.");
        }
        try_a_few_times_then_panic(|| fd.flush().is_ok(), "Could not flush file.");
    }

    // FIXME(jos): Merge with hat's checkout_in_dir which checks out snapshots.
    // (this checkout_in_dir checks out the family index)
    pub fn checkout_in_dir(&self,
                           output_dir: PathBuf,
                           dir_id: Option<u64>)
                           -> Result<(), HatError> {
        let mut path = output_dir;
        for (entry, _ref, read_fn_opt) in self.list_from_key_store(dir_id)? {
            // Extend directory with filename:
            path.push(str::from_utf8(&entry.info.name[..]).unwrap());

            match read_fn_opt {
                None => {
                    // This is a directory, recurse!
                    fs::create_dir_all(&path).unwrap();
                    self.checkout_in_dir(path.clone(), entry.id)?;
                }
                Some(read_fn) => {
                    // This is a file, write it
                    let mut fd = fs::File::create(&path).unwrap();
                    if let Some(tree) = read_fn.init()? {
                        self.write_file_chunks(&mut fd, tree);
                    }
                }
            }

            if let Some(perms) = entry.info.permissions {
                fs::set_permissions(&path, perms)?;
            }

            if let (Some(m), Some(a)) = (entry.info.modified_ts_secs, entry.info.accessed_ts_secs) {
                let atime = filetime::FileTime::from_seconds_since_1970(a, 0  /* nanos */);
                let mtime = filetime::FileTime::from_seconds_since_1970(m, 0  /* nanos */);
                filetime::set_file_times(&path, atime, mtime).unwrap();
            }

            // Prepare for next filename:
            path.pop();
        }

        Ok(())
    }

    pub fn list_from_key_store(&self,
                               dir_id: Option<u64>)
                               -> Result<Vec<key::DirElem<B>>, HatError> {
        match self.key_store_process[0].send_reply(key::Msg::ListDir(dir_id))? {
            key::Reply::ListResult(ls) => Ok(ls),
            _ => Err(From::from("Unexpected result from key store")),
        }
    }

    pub fn fetch_dir_data<HTB: hash::tree::HashTreeBackend<Err = key::MsgError>>
        (&self,
         dir_hash: hash::tree::HashRef,
         backend: HTB)
         -> Result<Vec<(key::Entry, hash::tree::HashRef)>, HatError> {
        let it = hash::tree::LeafIterator::new(backend, dir_hash)
            ?
            .expect("unable to open dir");

        let mut out = Vec::new();
        for chunk in it {
            if !chunk.is_empty() {
                parse_dir_data(&chunk[..], &mut out)?;
            }
        }

        Ok(out.into_iter().map(|f| (f.meta, f.hash_ref)).collect())
    }

    pub fn commit<F>(&mut self, top_hash_fn: &F) -> Result<hash::tree::HashRef, HatError>
        where F: Fn(&hash::Hash)
    {
        let mut top_tree = self.key_store.hash_tree_writer(blob::LeafType::TreeList);
        self.commit_to_tree(&mut top_tree, None, top_hash_fn)?;

        let info = key::Info::new(self.name.clone().into_bytes(), None, true);
        Ok(top_tree.hash(Some(&info))?)
    }

    pub fn commit_to_tree<F>(&mut self,
                          tree: &mut hash::tree::SimpleHashTreeWriter<key::HashStoreBackend<B>>,
                          dir_id: Option<u64>,
                          top_hash_fn: &F)
                          -> Result<(), HatError>
                          where F: Fn(&hash::Hash) {

        let files_at_a_time = 1024;
        let mut it = self.list_from_key_store(dir_id)?.into_iter();

        loop {
            let mut current_msg_is_empty = true;
            let mut file_block_msg = capnp::message::Builder::new_default();

            {
                let files_root = file_block_msg.init_root::<root_capnp::file_list::Builder>();
                let mut files = files_root.init_files(files_at_a_time as u32);

                for (idx, (entry, data_ref, _data_res_open)) in
                    it.by_ref()
                        .take(files_at_a_time)
                        .enumerate() {
                    assert!(idx < files_at_a_time);

                    current_msg_is_empty = false;
                    let mut file_msg = files.borrow().get(idx as u32);

                    file_msg.set_id(entry.id.unwrap_or(0));

                    {
                        entry.info.populate_msg(file_msg.borrow().init_info().borrow());
                    }

                    if let Some(hash_bytes) = entry.data_hash {
                        // This is a file, store its data hash:
                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate data hash and ChunkRef.
                        data_ref.expect("has data")
                            .populate_msg(hash_ref_root.borrow());
                        // Set as file content.
                        file_msg.borrow()
                            .init_content()
                            .set_data(hash_ref_root.as_reader())?;
                        top_hash_fn(&hash::Hash { bytes: hash_bytes });
                    } else {
                        drop(data_ref);  // May not use data reference without hash.

                        // This is a directory, recurse!
                        let mut inner_tree = self.key_store
                            .hash_tree_writer(blob::LeafType::TreeList);
                        self.commit_to_tree(&mut inner_tree, entry.id, top_hash_fn)?;
                        // Store a reference for the sub-tree in our tree:
                        let dir_hash_ref = inner_tree.hash(Some(&entry.info))?;

                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate directory hash and ChunkRef.
                        dir_hash_ref.populate_msg(hash_ref_root.borrow());
                        // Set as directory content.
                        file_msg.borrow()
                            .init_content()
                            .set_directory(hash_ref_root.as_reader())?;

                        top_hash_fn(&dir_hash_ref.hash);
                    }
                }
            }

            // Flush to our own tree when we have a decent amount.
            // The tree prevents large directories from clogging ram.
            if current_msg_is_empty {
                break;
            } else {
                let mut buf = vec![];
                capnp::serialize_packed::write_message(&mut buf, &file_block_msg)?;
                tree.append(&buf[..])?;
            }
        }

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

use backend::StoreBackend;
use blob;
use capnp;
use errors::HatError;
use hash;
use hat::insert_path_handler::InsertPathHandler;
use hat::walker;
use key;
use root_capnp;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::str;
use util::{FileIterator, FnBox, PathHandler};
use filetime;

fn try_a_few_times_then_panic<F>(mut f: F, msg: &str)
    where F: FnMut() -> bool
{
    for _ in 1 as i32..5 {
        if f() {
            return;
        }
    }
    panic!(msg.to_owned());
}

pub mod recover {
    use hash;
    use hash::tree;
    use hat::walker;
    use std::collections::VecDeque;
    use std::mem;
    use super::parse_dir_data;

    #[derive(Clone)]
    pub struct Node {
        pub href: tree::HashRef,
        pub childs: Option<Vec<tree::HashRef>>,
    }

    pub struct FileVisitor {
        tops: Vec<hash::Hash>,
        nodes: VecDeque<Node>,
    }

    impl FileVisitor {
        pub fn new() -> FileVisitor {
            FileVisitor {
                tops: vec![],
                nodes: VecDeque::new(),
            }
        }
        pub fn tops(&mut self) -> Vec<hash::Hash> {
            mem::replace(&mut self.tops, vec![])
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl tree::Visitor for FileVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_enter(&mut self, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });

            // Do not proceed to read the actual file data.
            false
        }
        fn leaf_leave(&mut self, _chunk: Vec<u8>, _href: &tree::HashRef) -> bool {
            unreachable!();
        }
    }

    impl walker::LikesFiles for FileVisitor {
        fn include_file(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_some() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }

        fn include_dir(&mut self, file: &walker::FileEntry) -> bool {
            if file.meta.data_hash.is_none() {
                self.tops.push(file.hash_ref.hash.clone());
                true
            } else {
                false
            }
        }
    }

    pub struct DirVisitor {
        nodes: VecDeque<Node>,
        files: Vec<walker::FileEntry>,
    }

    impl DirVisitor {
        pub fn new() -> DirVisitor {
            DirVisitor {
                nodes: VecDeque::new(),
                files: vec![],
            }
        }
        pub fn nodes(&mut self) -> VecDeque<Node> {
            mem::replace(&mut self.nodes, VecDeque::new())
        }
    }

    impl walker::HasFiles for DirVisitor {
        fn files(&mut self) -> Vec<walker::FileEntry> {
            mem::replace(&mut self.files, vec![])
        }
    }

    impl tree::Visitor for DirVisitor {
        fn branch_enter(&mut self, href: &tree::HashRef, childs: &Vec<tree::HashRef>) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: Some(childs.clone()),
            });
            true
        }
        fn leaf_enter(&mut self, href: &tree::HashRef) -> bool {
            self.nodes.push_back(Node {
                href: href.clone(),
                childs: None,
            });
            true
        }
        fn leaf_leave(&mut self, chunk: Vec<u8>, _href: &tree::HashRef) -> bool {
            parse_dir_data(&chunk[..], &mut self.files).unwrap();
            true
        }
    }
}

fn parse_dir_data(chunk: &[u8], mut out: &mut Vec<walker::FileEntry>) -> Result<(), HatError> {
    if chunk.is_empty() {
        return Ok(());
    }

    let reader = capnp::serialize_packed::read_message(&mut &chunk[..],
                                                       capnp::message::ReaderOptions::new())
        .unwrap();

    let list = reader.get_root::<root_capnp::file_list::Reader>().unwrap();
    for f in list.get_files().unwrap().iter() {
        if f.get_info()?.get_name().unwrap().len() == 0 {
            // Empty entry at end.
            // TODO(jos): Can we get rid of these?
            break;
        }
        let entry = key::Entry {
            id: Some(f.get_id()),
            info: key::Info::read(f.get_info()?.borrow())?,
            data_hash: match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    Some(r.unwrap().get_hash().unwrap().to_owned())
                }
                root_capnp::file::content::Directory(_) => None,
            },
            parent_id: None,
        };
        let hash_ref = match f.get_content().which().unwrap() {
                root_capnp::file::content::Data(r) => {
                    hash::tree::HashRef::read_msg(&r.expect("File has no data reference"))
                }
                root_capnp::file::content::Directory(d) => {
                    hash::tree::HashRef::read_msg(&d.expect("Directory has no listing reference"))
                }
            }
            .unwrap();

        out.push(walker::FileEntry {
            hash_ref: hash_ref,
            meta: entry,
        });
    }
    Ok(())
}

pub struct Family<B> {
    pub name: String,
    pub key_store: key::Store<B>,
    pub key_store_process: Vec<key::StoreProcess<FileIterator, B>>,
}
impl<B: StoreBackend> Clone for Family<B> {
    fn clone(&self) -> Family<B> {
        Family {
            name: self.name.clone(),
            key_store: self.key_store.clone(),
            key_store_process: self.key_store_process.clone(),
        }
    }
}

impl<B: StoreBackend> Family<B> {
    pub fn snapshot_dir(&self, dir: PathBuf) {
        let handler = InsertPathHandler::new(self.key_store_process.clone());

        let mut parent = None;
        let mut parent_path = PathBuf::from("/");

        let dir = fs::canonicalize(dir).unwrap();
        assert!(dir.is_absolute());

        for name in dir.iter().map(PathBuf::from).filter(|p| !p.has_root()) {
            parent_path.push(name);
            parent = handler.handle_path(&parent, &parent_path).unwrap();
        }

        if dir.is_dir() {
            handler.recurse(PathBuf::from(&dir), parent);
        }
    }

    pub fn snapshot_direct(&self,
                           file: key::Entry,
                           is_directory: bool,
                           contents: Option<FileIterator>)
                           -> Result<u64, HatError> {
        let f = if is_directory {
            None
        } else {
            Some(Box::new(move |()| contents) as Box<FnBox<(), _>>)
        };
        match self.key_store_process[0].send_reply(key::Msg::Insert(file, f))? {
            key::Reply::Id(id) => Ok(id),
            _ => Err(From::from("Unexpected reply from key store")),
        }
    }

    pub fn flush(&self) -> Result<(), HatError> {
        for ks in &self.key_store_process {
            if let key::Reply::FlushOk = ks.send_reply(key::Msg::Flush)? {
                continue;
            }
            return Err(From::from("Unexpected reply from key store"));
        }
        Ok(())
    }

  pub fn write_file_chunks<HTB: hash::tree::HashTreeBackend<Err=key::MsgError>>(
    &self, fd: &mut fs::File, tree: hash::tree::LeafIterator<HTB>)
  {
        for chunk in tree {
            try_a_few_times_then_panic(|| fd.write_all(&chunk[..]).is_ok(),
                                       "Could not write chunk.");
        }
        try_a_few_times_then_panic(|| fd.flush().is_ok(), "Could not flush file.");
    }

    // FIXME(jos): Merge with hat's checkout_in_dir which checks out snapshots.
    // (this checkout_in_dir checks out the family index)
    pub fn checkout_in_dir(&self,
                           output_dir: PathBuf,
                           dir_id: Option<u64>)
                           -> Result<(), HatError> {
        let mut path = output_dir;
        for (entry, _ref, read_fn_opt) in self.list_from_key_store(dir_id)? {
            // Extend directory with filename:
            path.push(str::from_utf8(&entry.info.name[..]).unwrap());

            match read_fn_opt {
                None => {
                    // This is a directory, recurse!
                    fs::create_dir_all(&path).unwrap();
                    self.checkout_in_dir(path.clone(), entry.id)?;
                }
                Some(read_fn) => {
                    // This is a file, write it
                    let mut fd = fs::File::create(&path).unwrap();
                    if let Some(tree) = read_fn.init()? {
                        self.write_file_chunks(&mut fd, tree);
                    }
                }
            }

            if let Some(perms) = entry.info.permissions {
                fs::set_permissions(&path, perms)?;
            }

            if let (Some(m), Some(a)) = (entry.info.modified_ts_secs, entry.info.accessed_ts_secs) {
                let atime = filetime::FileTime::from_seconds_since_1970(a, 0 /* nanos */);
                let mtime = filetime::FileTime::from_seconds_since_1970(m, 0 /* nanos */);
                filetime::set_file_times(&path, atime, mtime).unwrap();
            }

            // Prepare for next filename:
            path.pop();
        }

        Ok(())
    }

    pub fn list_from_key_store(&self,
                               dir_id: Option<u64>)
                               -> Result<Vec<key::DirElem<B>>, HatError> {
        match self.key_store_process[0].send_reply(key::Msg::ListDir(dir_id))? {
            key::Reply::ListResult(ls) => Ok(ls),
            _ => Err(From::from("Unexpected result from key store")),
        }
    }

    pub fn fetch_dir_data<HTB: hash::tree::HashTreeBackend<Err = key::MsgError>>
        (&self,
         dir_hash: hash::tree::HashRef,
         backend: HTB)
         -> Result<Vec<(key::Entry, hash::tree::HashRef)>, HatError> {
        let it = hash::tree::LeafIterator::new(backend, dir_hash)
            ?
            .expect("unable to open dir");

        let mut out = Vec::new();
        for chunk in it {
            if !chunk.is_empty() {
                parse_dir_data(&chunk[..], &mut out)?;
            }
        }

        Ok(out.into_iter().map(|f| (f.meta, f.hash_ref)).collect())
    }

    pub fn commit<F>(&mut self, top_hash_fn: &F) -> Result<hash::tree::HashRef, HatError>
        where F: Fn(&hash::Hash)
    {
        let mut top_tree = self.key_store.hash_tree_writer(blob::LeafType::TreeList);
        self.commit_to_tree(&mut top_tree, None, top_hash_fn)?;

        let info = key::Info::new(self.name.clone().into_bytes(), None, true);
        Ok(top_tree.hash(Some(&info))?)
    }

    pub fn commit_to_tree<F>(&mut self,
                          tree: &mut hash::tree::SimpleHashTreeWriter<key::HashStoreBackend<B>>,
                          dir_id: Option<u64>,
                          top_hash_fn: &F)
                          -> Result<(), HatError>
                          where F: Fn(&hash::Hash) {

        let files_at_a_time = 1024;
        let mut it = self.list_from_key_store(dir_id)?.into_iter();

        loop {
            let mut current_msg_is_empty = true;
            let mut file_block_msg = capnp::message::Builder::new_default();

            {
                let files_root = file_block_msg.init_root::<root_capnp::file_list::Builder>();
                let mut files = files_root.init_files(files_at_a_time as u32);

                for (idx, (entry, data_ref, _data_res_open)) in
                    it.by_ref()
                        .take(files_at_a_time)
                        .enumerate() {
                    assert!(idx < files_at_a_time);

                    current_msg_is_empty = false;
                    let mut file_msg = files.borrow().get(idx as u32);

                    file_msg.set_id(entry.id.unwrap_or(0));

                    {
                        entry.info.populate_msg(file_msg.borrow().init_info().borrow());
                    }

                    if let Some(hash_bytes) = entry.data_hash {
                        // This is a file, store its data hash:
                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate data hash and ChunkRef.
                        data_ref.expect("has data")
                            .populate_msg(hash_ref_root.borrow());
                        // Set as file content.
                        file_msg.borrow()
                            .init_content()
                            .set_data(hash_ref_root.as_reader())?;
                        top_hash_fn(&hash::Hash { bytes: hash_bytes });
                    } else {
                        drop(data_ref);  // May not use data reference without hash.

                        // This is a directory, recurse!
                        let mut inner_tree = self.key_store
                            .hash_tree_writer(blob::LeafType::TreeList);
                        self.commit_to_tree(&mut inner_tree, entry.id, top_hash_fn)?;
                        // Store a reference for the sub-tree in our tree:
                        let dir_hash_ref = inner_tree.hash(Some(&entry.info))?;

                        let mut hash_ref_msg = capnp::message::Builder::new_default();
                        let mut hash_ref_root =
                            hash_ref_msg.init_root::<root_capnp::hash_ref::Builder>();

                        // Populate directory hash and ChunkRef.
                        dir_hash_ref.populate_msg(hash_ref_root.borrow());
                        // Set as directory content.
                        file_msg.borrow()
                            .init_content()
                            .set_directory(hash_ref_root.as_reader())?;

                        top_hash_fn(&dir_hash_ref.hash);
                    }
                }
            }

            // Flush to our own tree when we have a decent amount.
            // The tree prevents large directories from clogging ram.
            if current_msg_is_empty {
                break;
            } else {
                let mut buf = vec![];
                capnp::serialize_packed::write_message(&mut buf, &file_block_msg)?;
                tree.append(&buf[..])?;
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std;

import std::task;

fn main() { log "===== SPAWNING and JOINING THREAD TASKS ====="; test00(); }

fn start(task_number: int) {
    log "Started task.";
    let i: int = 0;
    while i < 10000 { i = i + 1; }
    log "Finished task.";
}

fn test00() {
    let number_of_tasks: int = 8;

    let i: int = 0;
    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        tasks += [task::_spawn(bind start(i))];
    }

    for t: task::task_id in tasks { task::join_id(t); }

    log "Joined all task.";
}
<commit_msg>XFAIL task-comm-2. Doesn't work under windows<commit_after>// Broken under win
// xfail-stage1
// xfail-stage2
// xfail-stage3

use std;

import std::task;

fn main() { log "===== SPAWNING and JOINING THREAD TASKS ====="; test00(); }

fn start(task_number: int) {
    log "Started task.";
    let i: int = 0;
    while i < 10000 { i = i + 1; }
    log "Finished task.";
}

fn test00() {
    let number_of_tasks: int = 8;

    let i: int = 0;
    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        tasks += [task::_spawn(bind start(i))];
    }

    for t: task::task_id in tasks { task::join_id(t); }

    log "Joined all task.";
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

use std::iter::DoubleEndedIterator;

use data_structures::bwt::{Occ, Less, less, BWT};
use alphabets::Alphabet;

pub struct FMIndex<'a> {
    bwt: &'a BWT,
    less: Less,
    occ: Occ
}

impl<'a> FMIndex<'a> {
    pub fn new(bwt: &'a BWT, k: usize, alphabet: &Alphabet) -> Self {
        FMIndex { bwt: bwt, less: less(bwt, alphabet), occ: Occ::new(bwt, k, alphabet)}
    }

    /// Perform backward search, yielding suffix array
    /// interval denoting positions where the given pattern occurs.
    ///
    /// # Arguments
    ///
    /// * `pattern` - the pattern to search
    ///
    /// # Example
    ///
    /// ```
    /// use bio::data_structures::bwt::bwt;
    /// use bio::data_structures::fmindex::FMIndex;
    /// use bio::data_structures::suffix_array::suffix_array;
    /// use bio::alphabets::dna;
    /// let text = b"GCCTTAACATTATTACGCCTA$";
    /// let alphabet = dna::alphabet();
    /// let pos = suffix_array(text);
    /// let bwt = bwt(text, &pos);
    /// let fm = FMIndex::new(&bwt, 3, &alphabet);
    /// let pattern = b"TTA";
    /// let sai = fm.backward_search(pattern.iter());
    /// assert_eq!(sai, (19, 21));
    /// ```
    pub fn backward_search<'b, P: Iterator<Item=&'b u8> + DoubleEndedIterator>(&self, pattern: P) -> (usize, usize) {
        let (mut l, mut r) = (0, self.bwt.len() - 1);
        for &a in pattern.rev() {
            let less = self.less[a as usize];
            l = less + if l > 0 { self.occ.get(self.bwt, l - 1, a) } else { 0 };
            r = less + self.occ.get(self.bwt, r, a) - 1;
        }

        (l, r)
    }
}
<commit_msg>Docs.<commit_after>// Copyright 2014 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.

//! The Ferragina-Mancini Index for finding suffix array intervals matching a given pattern.

use std::iter::DoubleEndedIterator;

use data_structures::bwt::{Occ, Less, less, BWT};
use alphabets::Alphabet;

pub struct FMIndex<'a> {
    bwt: &'a BWT,
    less: Less,
    occ: Occ
}

impl<'a> FMIndex<'a> {
    /// Construct a new instance of the FM index.
    pub fn new(bwt: &'a BWT, k: usize, alphabet: &Alphabet) -> Self {
        FMIndex { bwt: bwt, less: less(bwt, alphabet), occ: Occ::new(bwt, k, alphabet)}
    }

    /// Perform backward search, yielding suffix array
    /// interval denoting exact occurences of the given pattern of length m in the text.
    /// Complexity: O(m).
    ///
    /// # Arguments
    ///
    /// * `pattern` - the pattern to search
    ///
    /// # Example
    ///
    /// ```
    /// use bio::data_structures::bwt::bwt;
    /// use bio::data_structures::fmindex::FMIndex;
    /// use bio::data_structures::suffix_array::suffix_array;
    /// use bio::alphabets::dna;
    /// let text = b"GCCTTAACATTATTACGCCTA$";
    /// let alphabet = dna::alphabet();
    /// let pos = suffix_array(text);
    /// let bwt = bwt(text, &pos);
    /// let fm = FMIndex::new(&bwt, 3, &alphabet);
    /// let pattern = b"TTA";
    /// let sai = fm.backward_search(pattern.iter());
    /// assert_eq!(sai, (19, 21));
    /// ```
    pub fn backward_search<'b, P: Iterator<Item=&'b u8> + DoubleEndedIterator>(&self, pattern: P) -> (usize, usize) {
        let (mut l, mut r) = (0, self.bwt.len() - 1);
        for &a in pattern.rev() {
            let less = self.less[a as usize];
            l = less + if l > 0 { self.occ.get(self.bwt, l - 1, a) } else { 0 };
            r = less + self.occ.get(self.bwt, r, a) - 1;
        }

        (l, r)
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

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

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn divisor(a: u64, b: u64) -> bool {
            // Test that gcd(a, b) divides a and b
            let g = gcd(a, b);
            a % g == 0 && b % g == 0
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_mult(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<commit_msg>tests ~ (sub-crate/factor) fix `divisor(0,0)` test of factor::numeric::gcd() with early value check and return (fixes #1587)<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use std::cmp::min;
use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64 {
    // Stein's binary GCD algorithm
    // Base cases: gcd(n, 0) = gcd(0, n) = n
    if u == 0 {
        return v;
    } else if v == 0 {
        return u;
    }

    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
    // 2ᵏ is the greatest power of two that divides both u and v
    let k = {
        let i = u.trailing_zeros();
        let j = v.trailing_zeros();
        u >>= i;
        v >>= j;
        min(i, j)
    };

    loop {
        // Loop invariant: u and v are odd
        debug_assert!(u % 2 == 1, "u = {} is even", u);
        debug_assert!(v % 2 == 1, "v = {} is even", v);

        // gcd(u, v) = gcd(|u - v|, min(u, v))
        if u > v {
            swap(&mut u, &mut v);
        }
        v -= u;

        if v == 0 {
            // Reached the base case; gcd is 2ᵏ u
            return u << k;
        }

        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
        v >>= v.trailing_zeros();
    }
}

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

    quickcheck! {
        fn euclidean(a: u64, b: u64) -> bool {
            // Test against the Euclidean algorithm
            let g = {
                let (mut a, mut b) = (a, b);
                while b > 0 {
                    a %= b;
                    swap(&mut a, &mut b);
                }
                a
            };
            gcd(a, b) == g
        }

        fn one(a: u64) -> bool {
            gcd(1, a) == 1
        }

        fn divisor(a: u64, b: u64) -> bool {
            // Test that gcd(a, b) divides a and b
            let g = gcd(a, b);
            if g == 0 { return a == 0 && b == 0; }
            a % g == 0 && b % g == 0
        }

        fn commutative(a: u64, b: u64) -> bool {
            gcd(a, b) == gcd(b, a)
        }

        fn associative(a: u64, b: u64, c: u64) -> bool {
            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
        }

        fn scalar_mult(a: u64, b: u64, k: u64) -> bool {
            gcd(k * a, k * b) == k * gcd(a, b)
        }

        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
        }

        fn linearity(a: u64, b: u64, k: u64) -> bool {
            gcd(a + k * b, b) == gcd(a, b)
        }
    }
}
<|endoftext|>


<commit_before>use core::ops::{Add, Mul};
use core::num::Wrapping;

/// Defines an additive identity element for `Self`.
pub trait Zero: Sized + Add<Self, Output = Self> {
    /// Returns the additive identity element of `Self`, `0`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a + 0 = a       ∀ a ∈ Self
    /// 0 + a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn zero() -> Self;

    /// Returns `true` if `self` is equal to the additive identity.
    #[inline]
    fn is_zero(&self) -> bool;
}

macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            #[inline]
            fn zero() -> $t { $v }
            #[inline]
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}

zero_impl!(usize, 0usize);
zero_impl!(u8,    0u8);
zero_impl!(u16,   0u16);
zero_impl!(u32,   0u32);
zero_impl!(u64,   0u64);

zero_impl!(isize, 0isize);
zero_impl!(i8,    0i8);
zero_impl!(i16,   0i16);
zero_impl!(i32,   0i32);
zero_impl!(i64,   0i64);

zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

impl<T: Zero> Zero for Wrapping<T> where Wrapping<T>: Add<Output=Wrapping<T>> {
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }
    fn zero() -> Self {
        Wrapping(T::zero())
    }
}

/// Defines a multiplicative identity element for `Self`.
pub trait One: Sized + Mul<Self, Output = Self> {
    /// Returns the multiplicative identity element of `Self`, `1`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a * 1 = a       ∀ a ∈ Self
    /// 1 * a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn one() -> Self;

    /// Returns `true` if `self` is equal to the multiplicative identity.
    ///
    /// For performance reasons, it's best to implement this manually.
    /// After a semver bump, this method will be required, and the
    /// `where Self: PartialEq` bound will be removed.
    #[inline]
    fn is_one(&self) -> bool where Self: PartialEq {
        *self == Self::one()
    }
}

macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            #[inline]
            fn one() -> $t { $v }
        }
    }
}

one_impl!(usize, 1usize);
one_impl!(u8,    1u8);
one_impl!(u16,   1u16);
one_impl!(u32,   1u32);
one_impl!(u64,   1u64);

one_impl!(isize, 1isize);
one_impl!(i8,    1i8);
one_impl!(i16,   1i16);
one_impl!(i32,   1i32);
one_impl!(i64,   1i64);

one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);

impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
    fn one() -> Self {
        Wrapping(T::one())
    }
}

// Some helper functions provided for backwards compatibility.

/// Returns the additive identity, `0`.
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }

/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }

#[test]
fn wrapping_identities() {
    macro_rules! test_wrapping_identities {
        ($($t:ty)+) => {
            $(
                assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
                assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
                assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
                assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
            )+
        };
    }

    test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
}

#[test]
fn wrapping_is_zero() {
    fn require_zero<T: Zero>(_: &T) {}
    require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
    fn require_one<T: One>(_: &T) {}
    require_one(&Wrapping(42));
}
<commit_msg>Added impls of `Zero` and `One` for `i128` and `u128`<commit_after>use core::ops::{Add, Mul};
use core::num::Wrapping;

/// Defines an additive identity element for `Self`.
pub trait Zero: Sized + Add<Self, Output = Self> {
    /// Returns the additive identity element of `Self`, `0`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a + 0 = a       ∀ a ∈ Self
    /// 0 + a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn zero() -> Self;

    /// Returns `true` if `self` is equal to the additive identity.
    #[inline]
    fn is_zero(&self) -> bool;
}

macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            #[inline]
            fn zero() -> $t { $v }
            #[inline]
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}

zero_impl!(usize, 0usize);
zero_impl!(u8,    0u8);
zero_impl!(u16,   0u16);
zero_impl!(u32,   0u32);
zero_impl!(u64,   0u64);
#[cfg(feature = "i128")]
zero_impl!(u128,  0u128);

zero_impl!(isize, 0isize);
zero_impl!(i8,    0i8);
zero_impl!(i16,   0i16);
zero_impl!(i32,   0i32);
zero_impl!(i64,   0i64);
#[cfg(feature = "i128")]
zero_impl!(i128,  0i128);

zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

impl<T: Zero> Zero for Wrapping<T> where Wrapping<T>: Add<Output=Wrapping<T>> {
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }
    fn zero() -> Self {
        Wrapping(T::zero())
    }
}

/// Defines a multiplicative identity element for `Self`.
pub trait One: Sized + Mul<Self, Output = Self> {
    /// Returns the multiplicative identity element of `Self`, `1`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a * 1 = a       ∀ a ∈ Self
    /// 1 * a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn one() -> Self;

    /// Returns `true` if `self` is equal to the multiplicative identity.
    ///
    /// For performance reasons, it's best to implement this manually.
    /// After a semver bump, this method will be required, and the
    /// `where Self: PartialEq` bound will be removed.
    #[inline]
    fn is_one(&self) -> bool where Self: PartialEq {
        *self == Self::one()
    }
}

macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            #[inline]
            fn one() -> $t { $v }
        }
    }
}

one_impl!(usize, 1usize);
one_impl!(u8,    1u8);
one_impl!(u16,   1u16);
one_impl!(u32,   1u32);
one_impl!(u64,   1u64);
#[cfg(feature = "i128")]
one_impl!(u64,   1u128);

one_impl!(isize, 1isize);
one_impl!(i8,    1i8);
one_impl!(i16,   1i16);
one_impl!(i32,   1i32);
one_impl!(i64,   1i64);
#[cfg(feature = "i128")]
one_impl!(i64,   1i128);

one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);

impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
    fn one() -> Self {
        Wrapping(T::one())
    }
}

// Some helper functions provided for backwards compatibility.

/// Returns the additive identity, `0`.
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }

/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }

#[test]
fn wrapping_identities() {
    macro_rules! test_wrapping_identities {
        ($($t:ty)+) => {
            $(
                assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
                assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
                assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
                assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
            )+
        };
    }

    test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
}

#[test]
fn wrapping_is_zero() {
    fn require_zero<T: Zero>(_: &T) {}
    require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
    fn require_one<T: One>(_: &T) {}
    require_one(&Wrapping(42));
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::convert::TryInto;
use std::ops::Deref;
use std::path::Path;
use std::rc::Rc;

use super::super::super::target::bytecode;
use super::super::frame::Closure;
use super::{LoadedModule, WeakLoadedModule};

#[derive(Clone)]
struct InnerLoadedFunction {
    module: WeakLoadedModule,
    id: u16,
    bytecode: BytecodeFunction,
}

/// Handle to a loaded function.
#[derive(Clone)]
pub struct LoadedFunction(Rc<InnerLoadedFunction>);

impl LoadedFunction {
    pub fn new(module: WeakLoadedModule, function: bytecode::layout::Function) -> Self {
        Self(Rc::new(InnerLoadedFunction {
            module,
            id: function.id,
            bytecode: BytecodeFunction::new(function),
        }))
    }

    pub fn id(&self) -> u16 {
        self.0.id
    }

    /// Returns a string indicating the base-name of the module it was defined
    /// in and its own name.
    pub fn qualified_name(&self) -> String {
        let module_basename = Path::new(&self.module().name())
            .file_name()
            .and_then(|os_str| os_str.to_str())
            .unwrap_or("(unknown)")
            .to_owned();
        let own_name = self.0.bytecode.name();
        format!("{}:{}", module_basename, own_name)
    }

    pub fn bytecode(&self) -> BytecodeFunction {
        self.0.bytecode.clone()
    }

    /// Returns whether or not this function binds/captures its environment
    /// when it is created.
    pub fn binds_on_create(&self) -> bool {
        self.0.bytecode.parent_bindings()
    }

    /// Returns a closure suitable for calling the function.
    pub fn build_closure_for_call(&self, parent: Option<Closure>) -> Option<Closure> {
        let bindings = self.0.bytecode.bindings();
        // Whether or not it needs to create bindings (a closure) when called.
        let binds_on_call = !bindings.is_empty() || self.0.bytecode.parent_bindings();
        if binds_on_call {
            let bindings = if bindings.is_empty() {
                None
            } else {
                Some(bindings)
            };
            Some(Closure::new(bindings, parent))
        } else {
            None
        }
    }

    pub fn module(&self) -> LoadedModule {
        self.0
            .module
            .clone()
            .try_into()
            .expect("Module has been dropped")
    }
}

pub struct InnerBytecodeFunction {
    function: bytecode::layout::Function,
}

impl InnerBytecodeFunction {
    pub fn name(&self) -> &str {
        &self.function.name
    }

    #[inline]
    pub fn registers(&self) -> u8 {
        self.function.registers
    }

    #[inline]
    pub fn locals(&self) -> u8 {
        self.function.locals
    }

    #[inline]
    pub fn instruction(&self, instruction_address: usize) -> bytecode::layout::Instruction {
        self.function.instructions[instruction_address].clone()
    }

    pub fn locals_names(&self) -> Vec<String> {
        self.function.locals_names.clone()
    }

    pub fn has_bindings(&self) -> bool {
        !self.function.bindings.is_empty()
    }

    pub fn bindings(&self) -> HashSet<String> {
        self.function.bindings.clone()
    }

    pub fn parent_bindings(&self) -> bool {
        self.function.parent_bindings
    }
}

#[derive(Clone)]
pub struct BytecodeFunction(Rc<InnerBytecodeFunction>);

impl BytecodeFunction {
    pub fn new(function: bytecode::layout::Function) -> Self {
        Self(Rc::new(InnerBytecodeFunction { function }))
    }
}

impl Deref for BytecodeFunction {
    type Target = InnerBytecodeFunction;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<commit_msg>Use method rather than closure<commit_after>use std::collections::HashSet;
use std::convert::TryInto;
use std::ffi::OsStr;
use std::ops::Deref;
use std::path::Path;
use std::rc::Rc;

use super::super::super::target::bytecode;
use super::super::frame::Closure;
use super::{LoadedModule, WeakLoadedModule};

#[derive(Clone)]
struct InnerLoadedFunction {
    module: WeakLoadedModule,
    id: u16,
    bytecode: BytecodeFunction,
}

/// Handle to a loaded function.
#[derive(Clone)]
pub struct LoadedFunction(Rc<InnerLoadedFunction>);

impl LoadedFunction {
    pub fn new(module: WeakLoadedModule, function: bytecode::layout::Function) -> Self {
        Self(Rc::new(InnerLoadedFunction {
            module,
            id: function.id,
            bytecode: BytecodeFunction::new(function),
        }))
    }

    pub fn id(&self) -> u16 {
        self.0.id
    }

    /// Returns a string indicating the base-name of the module it was defined
    /// in and its own name.
    pub fn qualified_name(&self) -> String {
        let module_basename = Path::new(&self.module().name())
            .file_name()
            .and_then(OsStr::to_str)
            .unwrap_or("(unknown)")
            .to_owned();
        let own_name = self.0.bytecode.name();
        format!("{}:{}", module_basename, own_name)
    }

    pub fn bytecode(&self) -> BytecodeFunction {
        self.0.bytecode.clone()
    }

    /// Returns whether or not this function binds/captures its environment
    /// when it is created.
    pub fn binds_on_create(&self) -> bool {
        self.0.bytecode.parent_bindings()
    }

    /// Returns a closure suitable for calling the function.
    pub fn build_closure_for_call(&self, parent: Option<Closure>) -> Option<Closure> {
        let bindings = self.0.bytecode.bindings();
        // Whether or not it needs to create bindings (a closure) when called.
        let binds_on_call = !bindings.is_empty() || self.0.bytecode.parent_bindings();
        if binds_on_call {
            let bindings = if bindings.is_empty() {
                None
            } else {
                Some(bindings)
            };
            Some(Closure::new(bindings, parent))
        } else {
            None
        }
    }

    pub fn module(&self) -> LoadedModule {
        self.0
            .module
            .clone()
            .try_into()
            .expect("Module has been dropped")
    }
}

pub struct InnerBytecodeFunction {
    function: bytecode::layout::Function,
}

impl InnerBytecodeFunction {
    pub fn name(&self) -> &str {
        &self.function.name
    }

    #[inline]
    pub fn registers(&self) -> u8 {
        self.function.registers
    }

    #[inline]
    pub fn locals(&self) -> u8 {
        self.function.locals
    }

    #[inline]
    pub fn instruction(&self, instruction_address: usize) -> bytecode::layout::Instruction {
        self.function.instructions[instruction_address].clone()
    }

    pub fn locals_names(&self) -> Vec<String> {
        self.function.locals_names.clone()
    }

    pub fn has_bindings(&self) -> bool {
        !self.function.bindings.is_empty()
    }

    pub fn bindings(&self) -> HashSet<String> {
        self.function.bindings.clone()
    }

    pub fn parent_bindings(&self) -> bool {
        self.function.parent_bindings
    }
}

#[derive(Clone)]
pub struct BytecodeFunction(Rc<InnerBytecodeFunction>);

impl BytecodeFunction {
    pub fn new(function: bytecode::layout::Function) -> Self {
        Self(Rc::new(InnerBytecodeFunction { function }))
    }
}

impl Deref for BytecodeFunction {
    type Target = InnerBytecodeFunction;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<|endoftext|>


<commit_before>//! Lexer Module.
extern crate ansi_term;
use self::ansi_term::Color::*;
//use self::ansi_term::Style;
use std::fmt;
use std::collections::HashSet;
/// Module used for tracking read-head position in file.
pub mod position;
use lexer::position::*;
/// Module of functions for checking characters.
pub mod char_tests;
use lexer::char_tests::*;

#[derive(Debug, Clone)]
// todo: Docs
///
pub struct Lexer {
    current_position: Position,
    pub source: String,
    pub tokens: Vec<String>,
}

impl Lexer {
    /// Constant containing all Strings that can represent any symbol or operator.
    /// Length of every symbol is 2 characters at most.
    const SYMBOLS: [&'static str; 55] = [
        "!", "~", "^", "=",
        "&", "&&", "|", "||",
        "+", "+=", "++",
        "-", "-=", "--",
        "*", "*=",
        "/", "/=",
        "%", "%=",
        "//", "/*", "*/",
        "/!","/?","?/", // doc comments
        ":", "::", "->", ".",
        "..",
        ";",
        "(", ")", "[", "]", "{", "}",
        "=>",
        "@", "$", "#", "?",
        "?!", // for compiler builtin checks
        "==", "!=", ">", "<", ">=", "<=",
        ">>", "<<",
        "\"", "'",
        "`",
    ];
    /// Constructor
    pub fn new(content: String) -> Self {
        Lexer {
            current_position: Position::new(),
            source: content,
            tokens: vec![],
        }
    }
    /// Tokenizes `self.source` and stores to `self.tokens`.
    pub fn lex(&mut self) -> Result<(), LexerError> {
        let mut current_token = String::new();
        let mut current_line = String::new();
        let mut chars: Vec<char> = self.source.chars().collect();
        // Turns symbol list into workable vector of Vec<char>
        let symbol_char_pairs: Vec<Vec<char>> = Lexer::SYMBOLS
            .iter()
            .map(|x| x
                .to_string()
                .chars()
                .collect()
            ).collect();
        // reverse chars so that pop() and push() read L->R, Top->End
        chars.reverse();
        //println!("{:?}", symbol_char_pairs);
        // while there's another character
        'consumption : while let Some(character) = chars.pop() {
            self.current_position.increment_column();
            current_line.push(character);
            current_token.push(character);
            if is_symbol(character) {
                // todo: test and fix
                let mut possible_next_chars: HashSet<char> = HashSet::new();
                // go through every pair, and add the second character if it starts with `character`
                for pair in symbol_char_pairs.clone() {
                    if pair.len() == 2 && pair[0] == character {
                        if !possible_next_chars.contains(&pair[1]) {
                            possible_next_chars.insert(pair[1]);
                        }
                    }
                }
                // get the next character if possible
                if let Some(next_char) = chars.pop() {
                    if possible_next_chars.contains(&next_char) {
                        current_token.push(next_char);
                        current_line.push(next_char);
                        self.current_position.increment_column();
                        // special cases
                        // todo: finish special cases
                        match current_token.clone().as_str() {
                            "//" => {   // single line comment
                                // if EOF is reached, this will just stop and
                                // push the current token.
                                'take_comment : while let Some(comment_char) = chars.pop() {
                                    // until end of line
                                    // follow principals of true loss-less lexing;
                                    // the newline character will be put in the token,
                                    // since it's not worth the work of putting back on the stack.
                                    // todo: Wright Book on Single Line Comments
                                    if comment_char != '\n' {
                                        current_token.push(comment_char);
                                        current_line.push(comment_char);
                                        self.current_position.increment_column();
                                    } else {
                                        current_token.push(comment_char);
                                        current_line.push(comment_char);
                                        self.current_position.increment_line();
                                        current_line = String::new();
                                        break 'take_comment;
                                    }
                                }
                            },
                            _ => {},
                        }
                        self.tokens.push(current_token);
                        current_token = String::new();
                        // move to next iter
                    } else {
                        // put the next_char back on the char stack if it doesn't make a possible token
                        chars.push(next_char);
                        self.tokens.push(current_token);
                        current_token = String::new();
                    }
                } else {
                    self.tokens.push(current_token);
                    current_token = String::new();
                }
            }
            else if is_alpha(character) {
                // todo: Wright Book variable and identifier names
                //
                // take chars for an identifier. (a-z, 0-9, _)
                // is_alpha could also imply the start of a keyword
                // but that doesn't really matter at this point.
                'take_identifier : while let Some(next_char) = chars.pop() {
                    if is_alphanumeric(next_char) || next_char == '_' {
                        self.current_position.increment_column();
                        current_token.push(next_char);
                        current_line.push(next_char);
                    } else {
                        chars.push(next_char);
                        self.tokens.push(current_token);
                        current_token = String::new();
                        break 'take_identifier;
                    }
                }

            }
            else {
                // todo: (this is a temp-fix)
                self.tokens.push(current_token);
                current_token = String::new();
            }
        }
        return Ok(());
    }

}

#[derive(Debug, Clone)]
/// Structure for lexer errors.
pub struct LexerError {
    pub module_name: String,
    pub position: Position,
    pub info: String,
    pub line: String,
    // not pub; access only in this mod.
    arrow_str: String
}

impl LexerError {
    /// Constructor.
    pub fn new(arg_position: Position, current_line: String) -> Self {
        LexerError {
            module_name: String::new(),
            position: arg_position,
            info: String::new(),
            line: current_line,
            arrow_str: String::new(),
        }
    }
    /// Sets info string based on an expected character and the character that was found.
    /// Auto-generates error message.
    pub fn set_info(&mut self, expected: char, found: Option<char>) {
        self.info = format!("Expected {} found {} character.", expected,
            // conversion from char -> String
            if let Some(n) = found {
                let mut temp_slice: [u8; 4] = [0;4];
                let n_as_str = n.encode_utf8(&mut temp_slice);
                n_as_str.to_string()
            } else {"<none>".to_string()});
        let current_line_borrow = self.line.clone();
        for c in current_line_borrow.chars().take(self.position.col-1) {
            match c {
                '\t' => self.arrow_str.push('\t'),
                _ =>  self.arrow_str.push(' '),
            }
        }
        self.arrow_str.push('^');
    }
    /// Very similar to `set_info` however this method takes a `Vec<char>` argument,
    /// specifying that any of those characters would have been acceptable coming next.
    pub fn set_info_as_vec(&mut self, expected: Vec<char>, found: Option<char>) {
        // formats the error message properly.
        let mut expected_string = "( ".to_string();
        for e in expected {
            expected_string.push(e);
            expected_string.push_str(" | ");
        }
        // remove extra '| '
        expected_string.pop();
        expected_string.pop();
        // close with ')'
        expected_string.push(')');
        self.info = format!("Expected {} found {} character.", expected_string,
            // conversion from char -> String
            if let Some(n) = found {
                let mut temp_slice: [u8; 4] = [0;4];
                let n_as_str = n.encode_utf8(&mut temp_slice);
                n_as_str.to_string()
            } else {"<none>".to_string()});
        let current_line_borrow = self.line.clone();
        for c in current_line_borrow.chars().take(self.position.col-1) {
            match c {
                '\t' => self.arrow_str.push('\t'),
                _ =>  self.arrow_str.push(' '),
            }
        }
        self.arrow_str.push('^');
    }
}

/// Display formatting for LexerError.
impl fmt::Display for LexerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{name}: {module}:{line}:{col}:\n{five}{i}\n{five} {b}\n{line:>width$} {b} {l}\n{five} {b} {a}\n",
            name = Red.paint("LexerError"),
            line = self.position.line,
            width = 5,
            module = Cyan.paint(self.module_name.clone()),
            col = self.position.col,
            five = " ".repeat(5),
            i = Blue.paint(self.info.clone()),
            l = Green.paint(self.line.clone()),
            b = Blue.paint("|"),
            a = Red.bold().paint(self.arrow_str.clone()))
    }
}<commit_msg>Docs and quick updates<commit_after>//! Lexer Module.
extern crate ansi_term;
use self::ansi_term::Color::*;
//use self::ansi_term::Style;
use std::fmt;
use std::collections::HashSet;
/// Module used for tracking read-head position in file.
pub mod position;
use lexer::position::*;
/// Module of functions for checking characters.
pub mod char_tests;
use lexer::char_tests::*;

#[derive(Debug, Clone)]
/// Lexer struct, which stores publicly a `tokens` field
/// which is generated using the `lex` method.  Tokens will be an internal
/// representation of source code, sliced in to parsable "lexemes" or "tokens".
pub struct Lexer {
    current_position: Position,
    // source doesn't need pub right?
    source: String,
    pub tokens: Vec<String>,
}

impl Lexer {
    /// Constant containing all Strings that can represent any symbol or operator.
    /// Length of every symbol is 2 characters at most.
    const SYMBOLS: [&'static str; 55] = [
        "!", "~", "^", "=",
        "&", "&&", "|", "||",
        "+", "+=", "++",
        "-", "-=", "--",
        "*", "*=",
        "/", "/=",
        "%", "%=",
        "//", "/*", "*/",
        "/!","/?","?/", // doc comments
        ":", "::", "->", ".",
        "..",
        ";",
        "(", ")", "[", "]", "{", "}",
        "=>",
        "@", "$", "#", "?",
        "?!", // for compiler builtin checks
        "==", "!=", ">", "<", ">=", "<=",
        ">>", "<<",
        "\"", "'",
        "`",
    ];
    /// Constructor.
    /// Content argument is source code written in wright.
    pub fn new(content: String) -> Self {
        Lexer {
            current_position: Position::new(),
            source: content,
            tokens: vec![],
        }
    }
    /// Tokenizes `self.source` and stores to `self.tokens`.
    /// Should operate at O(n). (n being the length of the wright file)
    /// #### Is completely loss-less.
    /// No source-code is lost in this conversion, it's all just split into parsable tokens.
    /// #### Has special cases.
    /// Tokens have these rules:
    /// * If a symbol in the `SYMBOLS` constant can be matched, it will be.
    ///     * If that symbol is a `//`, the rest of the line will be lexed into the same token.
    /// * If a token starts with a letter, it may have any combination of alphanumerics
    ///     and underscroes for the rest of it.
    /// * All others are turned into single-char tokens.
    /// ### These rules will change in future releases.
    pub fn lex(&mut self) -> Result<(), LexerError> {
        let mut current_token = String::new();
        let mut current_line = String::new();
        let mut chars: Vec<char> = self.source.chars().collect();
        // Turns symbol list into workable vector of Vec<char>
        let symbol_char_pairs: Vec<Vec<char>> = Lexer::SYMBOLS
            .iter()
            .map(|x| x
                .to_string()
                .chars()
                .collect()
            ).collect();
        // reverse chars so that pop() and push() read L->R, Top->End
        chars.reverse();
        //println!("{:?}", symbol_char_pairs);
        // while there's another character
        'consumption : while let Some(character) = chars.pop() {
            self.current_position.increment_column();
            current_line.push(character);
            current_token.push(character);
            if is_symbol(character) {
                // todo: test and fix
                let mut possible_next_chars: HashSet<char> = HashSet::new();
                // go through every pair, and add the second character if it starts with `character`
                for pair in symbol_char_pairs.clone() {
                    if pair.len() == 2 && pair[0] == character {
                        if !possible_next_chars.contains(&pair[1]) {
                            possible_next_chars.insert(pair[1]);
                        }
                    }
                }
                // get the next character if possible
                if let Some(next_char) = chars.pop() {
                    if possible_next_chars.contains(&next_char) {
                        current_token.push(next_char);
                        current_line.push(next_char);
                        self.current_position.increment_column();
                        // special cases
                        // todo: finish special cases
                        match current_token.clone().as_str() {
                            "//" => {   // single line comment
                                // if EOF is reached, this will just stop and
                                // push the current token.
                                'take_comment : while let Some(comment_char) = chars.pop() {
                                    // until end of line
                                    // follow principals of true loss-less lexing;
                                    // the newline character will be put in the token,
                                    // since it's not worth the work of putting back on the stack.
                                    // todo: Wright Book on Single Line Comments
                                    if comment_char != '\n' {
                                        current_token.push(comment_char);
                                        current_line.push(comment_char);
                                        self.current_position.increment_column();
                                    } else {
                                        current_token.push(comment_char);
                                        current_line.push(comment_char);
                                        self.current_position.increment_line();
                                        current_line = String::new();
                                        break 'take_comment;
                                    }
                                }
                            },
                            _ => {},
                        }
                        self.tokens.push(current_token);
                        current_token = String::new();
                        // move to next iter
                    } else {
                        // put the next_char back on the char stack if it doesn't make a possible token
                        chars.push(next_char);
                        self.tokens.push(current_token);
                        current_token = String::new();
                    }
                } else {
                    self.tokens.push(current_token);
                    current_token = String::new();
                }
            }
            else if is_alpha(character) {
                // todo: Wright Book variable and identifier names
                //
                // take chars for an identifier. (a-z, 0-9, _)
                // is_alpha could also imply the start of a keyword
                // but that doesn't really matter at this point.
                'take_identifier : while let Some(next_char) = chars.pop() {
                    if is_alphanumeric(next_char) || next_char == '_' {
                        self.current_position.increment_column();
                        current_token.push(next_char);
                        current_line.push(next_char);
                    } else {
                        chars.push(next_char);
                        self.tokens.push(current_token);
                        current_token = String::new();
                        break 'take_identifier;
                    }
                }

            }
            else {
                // todo: (this is a temp-fix)
                self.tokens.push(current_token);
                current_token = String::new();
            }
        }
        return Ok(());
    }

}

#[derive(Debug, Clone)]
/// Structure for lexer errors.
pub struct LexerError {
    pub module_name: String,
    pub position: Position,
    pub info: String,
    pub line: String,
    // not pub; access only in this mod.
    arrow_str: String
}

impl LexerError {
    /// Constructor.
    pub fn new(arg_position: Position, current_line: String) -> Self {
        LexerError {
            module_name: String::new(),
            position: arg_position,
            info: String::new(),
            line: current_line,
            arrow_str: String::new(),
        }
    }
    /// Sets info string based on an expected character and the character that was found.
    /// Auto-generates error message.
    pub fn set_info(&mut self, expected: char, found: Option<char>) {
        self.info = format!("Expected {} found {} character.", expected,
            // conversion from char -> String
            if let Some(n) = found {
                let mut temp_slice: [u8; 4] = [0;4];
                let n_as_str = n.encode_utf8(&mut temp_slice);
                n_as_str.to_string()
            } else {"<none>".to_string()});
        let current_line_borrow = self.line.clone();
        for c in current_line_borrow.chars().take(self.position.col-1) {
            match c {
                '\t' => self.arrow_str.push('\t'),
                _ =>  self.arrow_str.push(' '),
            }
        }
        self.arrow_str.push('^');
    }
    /// Very similar to `set_info` however this method takes a `Vec<char>` argument,
    /// specifying that any of those characters would have been acceptable coming next.
    pub fn set_info_as_vec(&mut self, expected: Vec<char>, found: Option<char>) {
        // formats the error message properly.
        let mut expected_string = "( ".to_string();
        for e in expected {
            expected_string.push(e);
            expected_string.push_str(" | ");
        }
        // remove extra '| '
        expected_string.pop();
        expected_string.pop();
        // close with ')'
        expected_string.push(')');
        self.info = format!("Expected {} found {} character.", expected_string,
            // conversion from char -> String
            if let Some(n) = found {
                let mut temp_slice: [u8; 4] = [0;4];
                let n_as_str = n.encode_utf8(&mut temp_slice);
                n_as_str.to_string()
            } else {"<none>".to_string()});
        let current_line_borrow = self.line.clone();
        for c in current_line_borrow.chars().take(self.position.col-1) {
            match c {
                '\t' => self.arrow_str.push('\t'),
                _ =>  self.arrow_str.push(' '),
            }
        }
        self.arrow_str.push('^');
    }
}

/// Display formatting for LexerError.
impl fmt::Display for LexerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{name}: {module}:{line}:{col}:\n{five}{i}\n{five} {b}\n{line:>width$} {b} {l}\n{five} {b} {a}\n",
            name = Red.paint("LexerError"),
            line = self.position.line,
            width = 5,
            module = Cyan.paint(self.module_name.clone()),
            col = self.position.col,
            five = " ".repeat(5),
            i = Blue.paint(self.info.clone()),
            l = Green.paint(self.line.clone()),
            b = Blue.paint("|"),
            a = Red.bold().paint(self.arrow_str.clone()))
    }
}<|endoftext|>


<commit_before>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

mod scalar;
mod vector;

// Concrete eval types without a nullable wrapper.
pub type Int = i64;
pub type Real = ordered_float::NotNan<f64>;
pub type Bytes = Vec<u8>;
pub use crate::codec::mysql::{Decimal, Duration, Json, JsonType, Time as DateTime};

// Dynamic eval types.
pub use self::scalar::{ScalarValue, ScalarValueRef};
pub use self::vector::{VectorValue, VectorValueExt};

use crate::{EvalType, FieldTypeTp};

use crate::codec::convert::ToInt;
use crate::expr::EvalContext;
use tidb_query_common::error::Result;

/// A trait of evaluating current concrete eval type into a MySQL logic value, represented by
/// Rust's `bool` type.
pub trait AsMySQLBool {
    /// Evaluates into a MySQL logic value.
    fn as_mysql_bool(&self, context: &mut EvalContext) -> Result<bool>;
}

impl AsMySQLBool for Int {
    #[inline]
    fn as_mysql_bool(&self, _context: &mut EvalContext) -> Result<bool> {
        Ok(*self != 0)
    }
}

impl AsMySQLBool for Real {
    #[inline]
    fn as_mysql_bool(&self, _context: &mut EvalContext) -> Result<bool> {
        Ok(self.round() != 0f64)
    }
}

impl AsMySQLBool for Bytes {
    #[inline]
    fn as_mysql_bool(&self, context: &mut EvalContext) -> Result<bool> {
        Ok(!self.is_empty() && self.to_int(context, FieldTypeTp::LongLong)? != 0)
    }
}

impl<T> AsMySQLBool for Option<T>
where
    T: AsMySQLBool,
{
    fn as_mysql_bool(&self, context: &mut EvalContext) -> Result<bool> {
        match self {
            None => Ok(false),
            Some(ref v) => v.as_mysql_bool(context),
        }
    }
}

pub macro match_template_evaluable($t:tt, $($tail:tt)*) {
    match_template::match_template! {
        $t = [Int, Real, Decimal, Bytes, DateTime, Duration, Json],
        $($tail)*
    }
}

/// A trait of all types that can be used during evaluation (eval type).
pub trait Evaluable: Clone + std::fmt::Debug + Send + Sync + 'static {
    const EVAL_TYPE: EvalType;

    /// Borrows this concrete type from a `ScalarValue` in the same type;
    /// panics if the varient mismatches.
    fn borrow_scalar_value(v: &ScalarValue) -> &Option<Self>;

    /// Borrows this concrete type from a `ScalarValueRef` in the same type;
    /// panics if the varient mismatches.
    fn borrow_scalar_value_ref<'a>(v: &'a ScalarValueRef<'a>) -> &'a Option<Self>;

    /// Borrows a slice of this concrete type from a `VectorValue` in the same type;
    /// panics if the varient mismatches.
    fn borrow_vector_value(v: &VectorValue) -> &[Option<Self>];

    /// Converts a vector of this concrete type into a `VectorValue` in the same type;
    /// panics if the varient mismatches.
    fn into_vector_value(vec: Vec<Option<Self>>) -> VectorValue;
}

macro_rules! impl_evaluable_type {
    ($ty:tt) => {
        impl Evaluable for $ty {
            const EVAL_TYPE: EvalType = EvalType::$ty;

            #[inline]
            fn borrow_scalar_value(v: &ScalarValue) -> &Option<Self> {
                v.as_ref()
            }

            #[inline]
            fn borrow_scalar_value_ref<'a>(v: &'a ScalarValueRef<'a>) -> &'a Option<Self> {
                v.as_ref()
            }

            #[inline]
            fn borrow_vector_value(v: &VectorValue) -> &[Option<Self>] {
                v.as_ref()
            }

            #[inline]
            fn into_vector_value(vec: Vec<Option<Self>>) -> VectorValue {
                VectorValue::from(vec)
            }
        }
    };
}

impl_evaluable_type! { Int }
impl_evaluable_type! { Real }
impl_evaluable_type! { Decimal }
impl_evaluable_type! { Bytes }
impl_evaluable_type! { DateTime }
impl_evaluable_type! { Duration }
impl_evaluable_type! { Json }
<commit_msg>tidb_query: fix converting bytes to bool (#7486)<commit_after>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

mod scalar;
mod vector;

// Concrete eval types without a nullable wrapper.
pub type Int = i64;
pub type Real = ordered_float::NotNan<f64>;
pub type Bytes = Vec<u8>;
pub use crate::codec::mysql::{Decimal, Duration, Json, JsonType, Time as DateTime};

// Dynamic eval types.
pub use self::scalar::{ScalarValue, ScalarValueRef};
pub use self::vector::{VectorValue, VectorValueExt};

use crate::EvalType;

use crate::codec::convert::ConvertTo;
use crate::expr::EvalContext;
use tidb_query_common::error::Result;

/// A trait of evaluating current concrete eval type into a MySQL logic value, represented by
/// Rust's `bool` type.
pub trait AsMySQLBool {
    /// Evaluates into a MySQL logic value.
    fn as_mysql_bool(&self, context: &mut EvalContext) -> Result<bool>;
}

impl AsMySQLBool for Int {
    #[inline]
    fn as_mysql_bool(&self, _context: &mut EvalContext) -> Result<bool> {
        Ok(*self != 0)
    }
}

impl AsMySQLBool for Real {
    #[inline]
    fn as_mysql_bool(&self, _context: &mut EvalContext) -> Result<bool> {
        Ok(self.round() != 0f64)
    }
}

impl AsMySQLBool for Bytes {
    #[inline]
    fn as_mysql_bool(&self, context: &mut EvalContext) -> Result<bool> {
        Ok(!self.is_empty() && ConvertTo::<f64>::convert(self, context)? != 0f64)
    }
}

impl<T> AsMySQLBool for Option<T>
where
    T: AsMySQLBool,
{
    fn as_mysql_bool(&self, context: &mut EvalContext) -> Result<bool> {
        match self {
            None => Ok(false),
            Some(ref v) => v.as_mysql_bool(context),
        }
    }
}

pub macro match_template_evaluable($t:tt, $($tail:tt)*) {
    match_template::match_template! {
        $t = [Int, Real, Decimal, Bytes, DateTime, Duration, Json],
        $($tail)*
    }
}

/// A trait of all types that can be used during evaluation (eval type).
pub trait Evaluable: Clone + std::fmt::Debug + Send + Sync + 'static {
    const EVAL_TYPE: EvalType;

    /// Borrows this concrete type from a `ScalarValue` in the same type;
    /// panics if the varient mismatches.
    fn borrow_scalar_value(v: &ScalarValue) -> &Option<Self>;

    /// Borrows this concrete type from a `ScalarValueRef` in the same type;
    /// panics if the varient mismatches.
    fn borrow_scalar_value_ref<'a>(v: &'a ScalarValueRef<'a>) -> &'a Option<Self>;

    /// Borrows a slice of this concrete type from a `VectorValue` in the same type;
    /// panics if the varient mismatches.
    fn borrow_vector_value(v: &VectorValue) -> &[Option<Self>];

    /// Converts a vector of this concrete type into a `VectorValue` in the same type;
    /// panics if the varient mismatches.
    fn into_vector_value(vec: Vec<Option<Self>>) -> VectorValue;
}

macro_rules! impl_evaluable_type {
    ($ty:tt) => {
        impl Evaluable for $ty {
            const EVAL_TYPE: EvalType = EvalType::$ty;

            #[inline]
            fn borrow_scalar_value(v: &ScalarValue) -> &Option<Self> {
                v.as_ref()
            }

            #[inline]
            fn borrow_scalar_value_ref<'a>(v: &'a ScalarValueRef<'a>) -> &'a Option<Self> {
                v.as_ref()
            }

            #[inline]
            fn borrow_vector_value(v: &VectorValue) -> &[Option<Self>] {
                v.as_ref()
            }

            #[inline]
            fn into_vector_value(vec: Vec<Option<Self>>) -> VectorValue {
                VectorValue::from(vec)
            }
        }
    };
}

impl_evaluable_type! { Int }
impl_evaluable_type! { Real }
impl_evaluable_type! { Decimal }
impl_evaluable_type! { Bytes }
impl_evaluable_type! { DateTime }
impl_evaluable_type! { Duration }
impl_evaluable_type! { Json }

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

    #[test]
    fn test_bytes_to_bool() {
        let tests: Vec<(&'static [u8], Option<bool>)> = vec![
            (b"", Some(false)),
            (b" 23", Some(true)),
            (b"-1", Some(true)),
            (b"1.11", Some(true)),
            (b"1.11.00", None),
            (b"xx", None),
            (b"0x00", None),
            (b"11.xx", None),
            (b"xx.11", None),
            (
                b".0000000000000000000000000000000000000000000000000000001",
                Some(true),
            ),
        ];

        let mut ctx = EvalContext::default();
        for (i, (v, expect)) in tests.into_iter().enumerate() {
            let rb: Result<bool> = v.to_vec().as_mysql_bool(&mut ctx);
            match expect {
                Some(val) => {
                    assert_eq!(rb.unwrap(), val);
                }
                None => {
                    assert!(
                        rb.is_err(),
                        "index: {}, {:?} should not be converted, but got: {:?}",
                        i,
                        v,
                        rb
                    );
                }
            }
        }

        // test overflow
        let mut ctx = EvalContext::default();
        let val: Result<bool> = f64::INFINITY
            .to_string()
            .as_bytes()
            .to_vec()
            .as_mysql_bool(&mut ctx);
        assert!(val.is_err());

        let mut ctx = EvalContext::default();
        let val: Result<bool> = f64::NEG_INFINITY
            .to_string()
            .as_bytes()
            .to_vec()
            .as_mysql_bool(&mut ctx);
        assert!(val.is_err());
    }
}
<|endoftext|>


<commit_before>//! The linalg module provides some basic linear algebra functionality for
//! transforming 3D geometry

use std::f32;
use std::ops::{Index, Mul, Add};

// Re-export the linalg types from the internal modules
pub use self::vector::Vector;
pub use self::normal::Normal;
pub use self::point::Point;
pub use self::ray::Ray;
pub use self::matrix4::Matrix4;
pub use self::transform::Transform;
pub use self::quaternion::Quaternion;
pub use self::keyframe::Keyframe;
pub use self::animated_transform::AnimatedTransform;

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;
pub mod quaternion;
pub mod keyframe;
pub mod animated_transform;

/// Enum representing on of the 3 spatial axes
#[derive(Copy, Clone, Debug)]
pub enum Axis { X, Y, Z }

/// Convert value in degrees to radians
/// TODO: See where `f32::to_radians` ends up, if it gets stabilized into Rust switch back to it
pub fn to_radians(d: f32) -> f32 {
    f32::consts::PI / 180.0 * d
}
/// Compute the cross product of two vectors
pub fn cross<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> vector::Vector {
    Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/// Lerp between `a` and `b` at some distance `t` where t is in [0, 1]
/// and t = 0 returns `a` and t = 1 returns `b`
pub fn lerp<T: Mul<f32, Output = T> + Add<Output = T> + Copy>(t: f32, a: &T, b: &T) -> T {
    *a * (1.0 - t) + *b * t
}
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> Vector {
    Vector::new(sin_theta * f32::cos(phi), sin_theta * f32::sin(phi),
                cos_theta)
}
/// Compute the direction specified by `theta` and `phi` in the coordinate system
/// formed by `x`, `y` and `z`
pub fn spherical_dir_coords(sin_theta: f32, cos_theta: f32, phi: f32, x: &Vector, y: &Vector, z: &Vector)
                    -> Vector {
    sin_theta * f32::cos(phi) * *x + sin_theta * f32::sin(phi) * *y + cos_theta * *z
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    f32::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match f32::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI * 2.0,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim_sqr = b * b - 4.0 * a * c;
    if discrim_sqr < 0.0 {
        None
    } else {
        let discrim = f32::sqrt(discrim_sqr);
        let q = if b < 0.0 {
            -0.5 * (b - discrim)
        } else {
            -0.5 * (b + discrim)
        };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}
/// Compute a local ortho-normal coordinate system from a single vector.
pub fn coordinate_system(e1: &Vector) -> (Vector, Vector) {
	let e2 =
        if f32::abs(e1.x) > f32::abs(e1.y) {
            let inv_len = 1.0 / f32::sqrt(e1.x * e1.x + e1.z * e1.z);
            Vector::new(-e1.z * inv_len, 0.0, e1.x * inv_len)
        }
        else {
            let inv_len = 1.0 / f32::sqrt(e1.y * e1.y + e1.z * e1.z);
            Vector::new(0.0, e1.z * inv_len, -e1.y * inv_len)
        };
    let e3 = cross(e1, &e2);
	(e2, e3)
}
/// Compute the reflection of `w` about `v`, both vectors should be normalized
pub fn reflect(w: &Vector, v: &Vector) -> Vector {
    2.0 * dot(w, v) * *v - *w
}
/// Compute the refraction of `w` entering surface with normal `n` where
/// the refractive index in the incident material is `eta_1` and the refractive
/// index of the entered material is `eta_2`. In the case of total internal
/// refraction this will return None.
pub fn refract(w: &Vector, n: &Vector, eta_1: f32, eta_2: f32) -> Option<Vector> {
    let eta = eta_1 / eta_2;
    let cos_t1 = -dot(n, w);
    let sin_t2 = eta * f32::sqrt(1.0 - f32::powf(cos_t1, 2.0));
    if sin_t2 >= 1.0 {
        None
    } else {
        let cos_t2 = f32::sqrt(1.0 - f32::powf(sin_t2, 2.0));
        Some(eta * *w + (eta * cos_t1 - cos_t2) * *n)
    }
}

#[test]
fn test_cross() {
    let a = Vector::new(1f32, 0f32, 0f32);
    let b = Vector::new(0f32, 1f32, 0f32);
    let c = cross(&a, &b);
    assert!(c == Vector::new(0f32, 0f32, 1f32));
}

#[test]
fn test_dot() {
    let a = Vector::new(1f32, 2f32, 3f32);
    let b = Vector::new(4f32, 5f32, 6f32);
    assert!(dot(&a, &b) == 1f32 * 4f32 + 2f32 * 5f32 + 3f32 * 6f32);
}

<commit_msg>Fix refract and some indentation<commit_after>//! The linalg module provides some basic linear algebra functionality for
//! transforming 3D geometry

use std::f32;
use std::ops::{Index, Mul, Add};

// Re-export the linalg types from the internal modules
pub use self::vector::Vector;
pub use self::normal::Normal;
pub use self::point::Point;
pub use self::ray::Ray;
pub use self::matrix4::Matrix4;
pub use self::transform::Transform;
pub use self::quaternion::Quaternion;
pub use self::keyframe::Keyframe;
pub use self::animated_transform::AnimatedTransform;

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;
pub mod quaternion;
pub mod keyframe;
pub mod animated_transform;

/// Enum representing on of the 3 spatial axes
#[derive(Copy, Clone, Debug)]
pub enum Axis { X, Y, Z }

/// Convert value in degrees to radians
/// TODO: See where `f32::to_radians` ends up, if it gets stabilized into Rust switch back to it
pub fn to_radians(d: f32) -> f32 {
    f32::consts::PI / 180.0 * d
}
/// Compute the cross product of two vectors
pub fn cross<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> vector::Vector {
    Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<usize, Output = f32>, B: Index<usize, Output = f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/// Lerp between `a` and `b` at some distance `t` where t is in [0, 1]
/// and t = 0 returns `a` and t = 1 returns `b`
pub fn lerp<T: Mul<f32, Output = T> + Add<Output = T> + Copy>(t: f32, a: &T, b: &T) -> T {
    *a * (1.0 - t) + *b * t
}
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> Vector {
    Vector::new(sin_theta * f32::cos(phi), sin_theta * f32::sin(phi),
                cos_theta)
}
/// Compute the direction specified by `theta` and `phi` in the coordinate system
/// formed by `x`, `y` and `z`
pub fn spherical_dir_coords(sin_theta: f32, cos_theta: f32, phi: f32, x: &Vector, y: &Vector, z: &Vector)
                    -> Vector {
    sin_theta * f32::cos(phi) * *x + sin_theta * f32::sin(phi) * *y + cos_theta * *z
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    f32::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match f32::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI * 2.0,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim_sqr = b * b - 4.0 * a * c;
    if discrim_sqr < 0.0 {
        None
    } else {
        let discrim = f32::sqrt(discrim_sqr);
        let q = if b < 0.0 {
            -0.5 * (b - discrim)
        } else {
            -0.5 * (b + discrim)
        };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}
/// Compute a local ortho-normal coordinate system from a single vector.
pub fn coordinate_system(e1: &Vector) -> (Vector, Vector) {
    let e2 =
        if f32::abs(e1.x) > f32::abs(e1.y) {
            let inv_len = 1.0 / f32::sqrt(e1.x * e1.x + e1.z * e1.z);
            Vector::new(-e1.z * inv_len, 0.0, e1.x * inv_len)
        }
        else {
            let inv_len = 1.0 / f32::sqrt(e1.y * e1.y + e1.z * e1.z);
            Vector::new(0.0, e1.z * inv_len, -e1.y * inv_len)
        };
    let e3 = cross(e1, &e2);
    (e2, e3)
}
/// Compute the reflection of `w` about `v`, both vectors should be normalized
pub fn reflect(w: &Vector, v: &Vector) -> Vector {
    2.0 * dot(w, v) * *v - *w
}
/// Compute the refraction of `w` entering surface with normal `n` where
/// the refractive index in the incident material is `eta_1` and the refractive
/// index of the entered material is `eta_2`. In the case of total internal
/// refraction this will return None.
pub fn refract(w: &Vector, n: &Vector, eta_1: f32, eta_2: f32) -> Option<Vector> {
    let eta = eta_1 / eta_2;
    let cos_t1 = dot(n, w);
    let sin_t1_sqr = f32::max(0.0, 1.0 - f32::powf(cos_t1, 2.0));
    let sin_t2_sqr = f32::powf(eta, 2.0) * sin_t1_sqr;
    if sin_t2_sqr >= 1.0 {
        None
    } else {
        let cos_t2 = f32::sqrt(1.0 - sin_t2_sqr);
        Some(eta * -*w + (eta * cos_t1 - cos_t2) * *n)
    }
}

#[test]
fn test_cross() {
    let a = Vector::new(1f32, 0f32, 0f32);
    let b = Vector::new(0f32, 1f32, 0f32);
    let c = cross(&a, &b);
    assert!(c == Vector::new(0f32, 0f32, 1f32));
}

#[test]
fn test_dot() {
    let a = Vector::new(1f32, 2f32, 3f32);
    let b = Vector::new(4f32, 5f32, 6f32);
    assert!(dot(&a, &b) == 1f32 * 4f32 + 2f32 * 5f32 + 3f32 * 6f32);
}

<|endoftext|>