<commit_before>// Copyright 2018 The xi-editor Authors.
//
// 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.

//! Interactions with the file system.

use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt;
use std::fs::{self, File, Permissions};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str;
use std::time::SystemTime;

use xi_rope::Rope;
use xi_rpc::RemoteError;

use crate::tabs::BufferId;

#[cfg(feature = "notify")]
use crate::tabs::OPEN_FILE_EVENT_TOKEN;
#[cfg(feature = "notify")]
use crate::watcher::FileWatcher;
#[cfg(target_family = "unix")]
use std::os::unix::fs::PermissionsExt;

const UTF8_BOM: &str = "\u{feff}";

/// Tracks all state related to open files.
pub struct FileManager {
    open_files: HashMap<PathBuf, BufferId>,
    file_info: HashMap<BufferId, FileInfo>,
    /// A monitor of filesystem events, for things like reloading changed files.
    #[cfg(feature = "notify")]
    watcher: FileWatcher,
}

#[derive(Debug)]
pub struct FileInfo {
    pub encoding: CharacterEncoding,
    pub path: PathBuf,
    pub mod_time: Option<SystemTime>,
    pub has_changed: bool,
    #[cfg(target_family = "unix")]
    pub permissions: Option<u32>,
}

pub enum FileError {
    Io(io::Error, PathBuf),
    UnknownEncoding(PathBuf),
    HasChanged(PathBuf),
}

#[derive(Debug, Clone, Copy)]
pub enum CharacterEncoding {
    Utf8,
    Utf8WithBom,
}

impl FileManager {
    #[cfg(feature = "notify")]
    pub fn new(watcher: FileWatcher) -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new(), watcher }
    }

    #[cfg(not(feature = "notify"))]
    pub fn new() -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new() }
    }

    #[cfg(feature = "notify")]
    pub fn watcher(&mut self) -> &mut FileWatcher {
        &mut self.watcher
    }

    pub fn get_info(&self, id: BufferId) -> Option<&FileInfo> {
        self.file_info.get(&id)
    }

    pub fn get_editor(&self, path: &Path) -> Option<BufferId> {
        self.open_files.get(path).cloned()
    }

    /// Returns `true` if this file is open and has changed on disk.
    /// This state is stashed.
    pub fn check_file(&mut self, path: &Path, id: BufferId) -> bool {
        if let Some(info) = self.file_info.get_mut(&id) {
            let mod_t = get_mod_time(path);
            if mod_t != info.mod_time {
                info.has_changed = true
            }
            return info.has_changed;
        }
        false
    }

    pub fn open(&mut self, path: &Path, id: BufferId) -> Result<Rope, FileError> {
        if !path.exists() {
            let _ = File::create(path).map_err(|e| FileError::Io(e, path.to_owned()))?;
        }

        let (rope, info) = try_load_file(path)?;

        self.open_files.insert(path.to_owned(), id);
        if self.file_info.insert(id, info).is_none() {
            #[cfg(feature = "notify")]
            self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        }
        Ok(rope)
    }

    pub fn close(&mut self, id: BufferId) {
        if let Some(info) = self.file_info.remove(&id) {
            self.open_files.remove(&info.path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&info.path, OPEN_FILE_EVENT_TOKEN);
        }
    }

    pub fn save(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let is_existing = self.file_info.contains_key(&id);
        if is_existing {
            self.save_existing(path, text, id)
        } else {
            self.save_new(path, text, id)
        }
    }

    fn save_new(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        try_save(path, text, CharacterEncoding::Utf8, self.get_info(id))
            .map_err(|e| FileError::Io(e, path.to_owned()))?;
        let info = FileInfo {
            encoding: CharacterEncoding::Utf8,
            path: path.to_owned(),
            mod_time: get_mod_time(path),
            has_changed: false,
            #[cfg(target_family = "unix")]
            permissions: get_permissions(path),
        };
        self.open_files.insert(path.to_owned(), id);
        self.file_info.insert(id, info);
        #[cfg(feature = "notify")]
        self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        Ok(())
    }

    fn save_existing(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let prev_path = self.file_info[&id].path.clone();
        if prev_path != path {
            self.save_new(path, text, id)?;
            self.open_files.remove(&prev_path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&prev_path, OPEN_FILE_EVENT_TOKEN);
        } else if self.file_info[&id].has_changed {
            return Err(FileError::HasChanged(path.to_owned()));
        } else {
            let encoding = self.file_info[&id].encoding;
            try_save(path, text, encoding, self.get_info(id))
                .map_err(|e| FileError::Io(e, path.to_owned()))?;
            self.file_info.get_mut(&id).unwrap().mod_time = get_mod_time(path);
        }
        Ok(())
    }
}

fn try_load_file<P>(path: P) -> Result<(Rope, FileInfo), FileError>
where
    P: AsRef<Path>,
{
    // TODO: support for non-utf8
    // it's arguable that the rope crate should have file loading functionality
    let mut f =
        File::open(path.as_ref()).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
    let mut bytes = Vec::new();
    f.read_to_end(&mut bytes).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;

    let encoding = CharacterEncoding::guess(&bytes);
    let rope = try_decode(bytes, encoding, path.as_ref())?;
    let info = FileInfo {
        encoding,
        mod_time: get_mod_time(&path),
        #[cfg(target_family = "unix")]
        permissions: get_permissions(&path),
        path: path.as_ref().to_owned(),
        has_changed: false,
    };
    Ok((rope, info))
}

fn try_save(
    path: &Path,
    text: &Rope,
    encoding: CharacterEncoding,
    file_info: Option<&FileInfo>,
) -> io::Result<()> {
    let tmp_extension = path.extension().map_or_else(
        || OsString::from("swp"),
        |ext| {
            let mut ext = ext.to_os_string();
            ext.push(".swp");
            ext
        },
    );
    let tmp_path = &path.with_extension(tmp_extension);

    let mut f = File::create(tmp_path)?;
    match encoding {
        CharacterEncoding::Utf8WithBom => f.write_all(UTF8_BOM.as_bytes())?,
        CharacterEncoding::Utf8 => (),
    }

    for chunk in text.iter_chunks(..text.len()) {
        f.write_all(chunk.as_bytes())?;
    }

    fs::rename(tmp_path, path)?;

    if let Some(info_unwrapped) = file_info {
        #[cfg(target_family = "unix")]
        fs::set_permissions(
            path,
            Permissions::from_mode(info_unwrapped.permissions.unwrap_or(0o644)),
        )?;
    }

    Ok(())
}

fn try_decode(bytes: Vec<u8>, encoding: CharacterEncoding, path: &Path) -> Result<Rope, FileError> {
    match encoding {
        CharacterEncoding::Utf8 => Ok(Rope::from(
            str::from_utf8(&bytes).map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?,
        )),
        CharacterEncoding::Utf8WithBom => {
            let s = String::from_utf8(bytes)
                .map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?;
            Ok(Rope::from(&s[UTF8_BOM.len()..]))
        }
    }
}

impl CharacterEncoding {
    fn guess(s: &[u8]) -> Self {
        if s.starts_with(UTF8_BOM.as_bytes()) {
            CharacterEncoding::Utf8WithBom
        } else {
            CharacterEncoding::Utf8
        }
    }
}

/// Returns the modification timestamp for the file at a given path,
/// if present.
fn get_mod_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
    File::open(path).and_then(|f| f.metadata()).and_then(|meta| meta.modified()).ok()
}

/// Returns the file permissions for the file at a given path on UNIXy systems,
/// if present.
#[cfg(target_family = "unix")]
fn get_permissions<P: AsRef<Path>>(path: P) -> Option<u32> {
    File::open(path).and_then(|f| f.metadata()).map(|meta| meta.permissions().mode()).ok()
}

impl From<FileError> for RemoteError {
    fn from(src: FileError) -> RemoteError {
        //TODO: when we migrate to using the failure crate for error handling,
        // this should return a better message
        let code = src.error_code();
        let message = src.to_string();
        RemoteError::custom(code, message, None)
    }
}

impl FileError {
    fn error_code(&self) -> i64 {
        match self {
            FileError::Io(_, _) => 5,
            FileError::UnknownEncoding(_) => 6,
            FileError::HasChanged(_) => 7,
        }
    }
}

impl fmt::Display for FileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            FileError::Io(ref e, ref p) => write!(f, "{}. File path: {:?}", e, p),
            FileError::UnknownEncoding(ref p) => write!(f, "Error decoding file: {:?}", p),
            FileError::HasChanged(ref p) => write!(
                f,
                "File has changed on disk. \
                 Please save elsewhere and reload the file. File path: {:?}",
                p
            ),
        }
    }
}
<commit_msg>fix warnings<commit_after>// Copyright 2018 The xi-editor Authors.
//
// 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.

//! Interactions with the file system.

use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str;
use std::time::SystemTime;

use xi_rope::Rope;
use xi_rpc::RemoteError;

use crate::tabs::BufferId;

#[cfg(feature = "notify")]
use crate::tabs::OPEN_FILE_EVENT_TOKEN;
#[cfg(feature = "notify")]
use crate::watcher::FileWatcher;
#[cfg(target_family = "unix")]
use std::{fs::Permissions, os::unix::fs::PermissionsExt};

const UTF8_BOM: &str = "\u{feff}";

/// Tracks all state related to open files.
pub struct FileManager {
    open_files: HashMap<PathBuf, BufferId>,
    file_info: HashMap<BufferId, FileInfo>,
    /// A monitor of filesystem events, for things like reloading changed files.
    #[cfg(feature = "notify")]
    watcher: FileWatcher,
}

#[derive(Debug)]
pub struct FileInfo {
    pub encoding: CharacterEncoding,
    pub path: PathBuf,
    pub mod_time: Option<SystemTime>,
    pub has_changed: bool,
    #[cfg(target_family = "unix")]
    pub permissions: Option<u32>,
}

pub enum FileError {
    Io(io::Error, PathBuf),
    UnknownEncoding(PathBuf),
    HasChanged(PathBuf),
}

#[derive(Debug, Clone, Copy)]
pub enum CharacterEncoding {
    Utf8,
    Utf8WithBom,
}

impl FileManager {
    #[cfg(feature = "notify")]
    pub fn new(watcher: FileWatcher) -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new(), watcher }
    }

    #[cfg(not(feature = "notify"))]
    pub fn new() -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new() }
    }

    #[cfg(feature = "notify")]
    pub fn watcher(&mut self) -> &mut FileWatcher {
        &mut self.watcher
    }

    pub fn get_info(&self, id: BufferId) -> Option<&FileInfo> {
        self.file_info.get(&id)
    }

    pub fn get_editor(&self, path: &Path) -> Option<BufferId> {
        self.open_files.get(path).cloned()
    }

    /// Returns `true` if this file is open and has changed on disk.
    /// This state is stashed.
    pub fn check_file(&mut self, path: &Path, id: BufferId) -> bool {
        if let Some(info) = self.file_info.get_mut(&id) {
            let mod_t = get_mod_time(path);
            if mod_t != info.mod_time {
                info.has_changed = true
            }
            return info.has_changed;
        }
        false
    }

    pub fn open(&mut self, path: &Path, id: BufferId) -> Result<Rope, FileError> {
        if !path.exists() {
            let _ = File::create(path).map_err(|e| FileError::Io(e, path.to_owned()))?;
        }

        let (rope, info) = try_load_file(path)?;

        self.open_files.insert(path.to_owned(), id);
        if self.file_info.insert(id, info).is_none() {
            #[cfg(feature = "notify")]
            self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        }
        Ok(rope)
    }

    pub fn close(&mut self, id: BufferId) {
        if let Some(info) = self.file_info.remove(&id) {
            self.open_files.remove(&info.path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&info.path, OPEN_FILE_EVENT_TOKEN);
        }
    }

    pub fn save(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let is_existing = self.file_info.contains_key(&id);
        if is_existing {
            self.save_existing(path, text, id)
        } else {
            self.save_new(path, text, id)
        }
    }

    fn save_new(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        try_save(path, text, CharacterEncoding::Utf8, self.get_info(id))
            .map_err(|e| FileError::Io(e, path.to_owned()))?;
        let info = FileInfo {
            encoding: CharacterEncoding::Utf8,
            path: path.to_owned(),
            mod_time: get_mod_time(path),
            has_changed: false,
            #[cfg(target_family = "unix")]
            permissions: get_permissions(path),
        };
        self.open_files.insert(path.to_owned(), id);
        self.file_info.insert(id, info);
        #[cfg(feature = "notify")]
        self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        Ok(())
    }

    fn save_existing(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let prev_path = self.file_info[&id].path.clone();
        if prev_path != path {
            self.save_new(path, text, id)?;
            self.open_files.remove(&prev_path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&prev_path, OPEN_FILE_EVENT_TOKEN);
        } else if self.file_info[&id].has_changed {
            return Err(FileError::HasChanged(path.to_owned()));
        } else {
            let encoding = self.file_info[&id].encoding;
            try_save(path, text, encoding, self.get_info(id))
                .map_err(|e| FileError::Io(e, path.to_owned()))?;
            self.file_info.get_mut(&id).unwrap().mod_time = get_mod_time(path);
        }
        Ok(())
    }
}

fn try_load_file<P>(path: P) -> Result<(Rope, FileInfo), FileError>
where
    P: AsRef<Path>,
{
    // TODO: support for non-utf8
    // it's arguable that the rope crate should have file loading functionality
    let mut f =
        File::open(path.as_ref()).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
    let mut bytes = Vec::new();
    f.read_to_end(&mut bytes).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;

    let encoding = CharacterEncoding::guess(&bytes);
    let rope = try_decode(bytes, encoding, path.as_ref())?;
    let info = FileInfo {
        encoding,
        mod_time: get_mod_time(&path),
        #[cfg(target_family = "unix")]
        permissions: get_permissions(&path),
        path: path.as_ref().to_owned(),
        has_changed: false,
    };
    Ok((rope, info))
}

#[allow(unused)]
fn try_save(
    path: &Path,
    text: &Rope,
    encoding: CharacterEncoding,
    file_info: Option<&FileInfo>,
) -> io::Result<()> {
    let tmp_extension = path.extension().map_or_else(
        || OsString::from("swp"),
        |ext| {
            let mut ext = ext.to_os_string();
            ext.push(".swp");
            ext
        },
    );
    let tmp_path = &path.with_extension(tmp_extension);

    let mut f = File::create(tmp_path)?;
    match encoding {
        CharacterEncoding::Utf8WithBom => f.write_all(UTF8_BOM.as_bytes())?,
        CharacterEncoding::Utf8 => (),
    }

    for chunk in text.iter_chunks(..text.len()) {
        f.write_all(chunk.as_bytes())?;
    }

    fs::rename(tmp_path, path)?;

    #[cfg(target_family = "unix")]
    {
        if let Some(info) = file_info {
            fs::set_permissions(path, Permissions::from_mode(info.permissions.unwrap_or(0o644)))?;
        }
    }

    Ok(())
}

fn try_decode(bytes: Vec<u8>, encoding: CharacterEncoding, path: &Path) -> Result<Rope, FileError> {
    match encoding {
        CharacterEncoding::Utf8 => Ok(Rope::from(
            str::from_utf8(&bytes).map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?,
        )),
        CharacterEncoding::Utf8WithBom => {
            let s = String::from_utf8(bytes)
                .map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?;
            Ok(Rope::from(&s[UTF8_BOM.len()..]))
        }
    }
}

impl CharacterEncoding {
    fn guess(s: &[u8]) -> Self {
        if s.starts_with(UTF8_BOM.as_bytes()) {
            CharacterEncoding::Utf8WithBom
        } else {
            CharacterEncoding::Utf8
        }
    }
}

/// Returns the modification timestamp for the file at a given path,
/// if present.
fn get_mod_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
    File::open(path).and_then(|f| f.metadata()).and_then(|meta| meta.modified()).ok()
}

/// Returns the file permissions for the file at a given path on UNIXy systems,
/// if present.
#[cfg(target_family = "unix")]
fn get_permissions<P: AsRef<Path>>(path: P) -> Option<u32> {
    File::open(path).and_then(|f| f.metadata()).map(|meta| meta.permissions().mode()).ok()
}

impl From<FileError> for RemoteError {
    fn from(src: FileError) -> RemoteError {
        //TODO: when we migrate to using the failure crate for error handling,
        // this should return a better message
        let code = src.error_code();
        let message = src.to_string();
        RemoteError::custom(code, message, None)
    }
}

impl FileError {
    fn error_code(&self) -> i64 {
        match self {
            FileError::Io(_, _) => 5,
            FileError::UnknownEncoding(_) => 6,
            FileError::HasChanged(_) => 7,
        }
    }
}

impl fmt::Display for FileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            FileError::Io(ref e, ref p) => write!(f, "{}. File path: {:?}", e, p),
            FileError::UnknownEncoding(ref p) => write!(f, "Error decoding file: {:?}", p),
            FileError::HasChanged(ref p) => write!(
                f,
                "File has changed on disk. \
                 Please save elsewhere and reload the file. File path: {:?}",
                p
            ),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The xi-editor Authors.
//
// 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.

//! Module for searching text.

use std::cmp::{min,max};

use xi_rope::delta::{Delta, DeltaRegion};
use xi_rope::find::{find, is_multiline_regex, CaseMatching};
use xi_rope::rope::{Rope, LinesMetric, RopeInfo};
use xi_rope::tree::Cursor;
use xi_rope::interval::Interval;
use selection::{Selection, SelRegion};
use xi_rope::tree::Metric;
use regex::{RegexBuilder, Regex};
use word_boundaries::WordCursor;

const REGEX_SIZE_LIMIT: usize = 1000000;

/// Information about search queries and number of matches for find
#[derive(Serialize, Deserialize, Debug)]
pub struct FindStatus {
    /// Identifier for the current search query.
    id: usize,

    /// The current search query.
    chars: Option<String>,

    /// Whether the active search is case matching.
    case_sensitive: Option<bool>,

    /// Whether the search query is considered as regular expression.
    is_regex: Option<bool>,

    /// Query only matches whole words.
    whole_words: Option<bool>,

    /// Total number of matches.
    matches: usize
}

/// Contains logic to search text
pub struct Find {
    // Uniquely identifies this search query.
    id: usize,
    /// The occurrences, which determine the highlights, have been updated.
    hls_dirty: bool,
    /// The currently active search string.
    search_string: Option<String>,
    /// The case matching setting for the currently active search.
    case_matching: CaseMatching,
    /// The search query should be considered as regular expression.
    regex: Option<Regex>,
    /// Query matches only whole words.
    whole_words: bool,
    /// The set of all known find occurrences (highlights).
    occurrences: Selection,
}

impl Find {
    pub fn new(id: usize) -> Find {
        Find {
            id: id,
            hls_dirty: true,
            search_string: None,
            case_matching: CaseMatching::CaseInsensitive,
            regex: None,
            whole_words: false,
            occurrences: Selection::new(),
        }
    }

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

    pub fn occurrences(&self) -> &Selection {
        &self.occurrences
    }

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

    pub fn find_status(&self, matches_only: bool) -> FindStatus {
        if matches_only {
            FindStatus {
                id: self.id,
                chars: None,
                case_sensitive: None,
                is_regex: None,
                whole_words: None,
                matches: self.occurrences.len(),
            }
        } else {
            FindStatus {
                id: self.id,
                chars: self.search_string.clone(),
                case_sensitive: Some(self.case_matching == CaseMatching::Exact),
                is_regex: Some(self.regex.is_some()),
                whole_words: Some(self.whole_words),
                matches: self.occurrences.len(),
            }
        }
    }

    pub fn set_hls_dirty(&mut self, is_dirty: bool) {
        self.hls_dirty = is_dirty
    }

    pub fn update_highlights(&mut self, text: &Rope, delta: &Delta<RopeInfo>) {
        // update search highlights for changed regions
        if self.search_string.is_some() {
            // invalidate occurrences around deletion positions
            for DeltaRegion{ old_offset, new_offset: _, len } in delta.iter_deletions() {
                self.occurrences.delete_range(old_offset, old_offset + len, false);
            }

            self.occurrences = self.occurrences.apply_delta(delta, false, false);

            // invalidate occurrences around insert positions
            for DeltaRegion{ new_offset, len, .. } in delta.iter_inserts() {
                // also invalidate previous occurrence since it might expand after insertion
                // eg. for regex .* every insertion after match will be part of match
                self.occurrences.delete_range(new_offset.checked_sub(1).unwrap_or(0), new_offset + len, false);
            }

            // update find for the whole delta and everything after
            let (iv, _) = delta.summary();

            // get last valid occurrence that was unaffected by the delta
            let start = match self.occurrences.regions_in_range(0, iv.start()).last() {
                Some(reg) => reg.end,
                None => 0
            };

            // invalidate all search results from the point of the last valid search result until ...
            let is_multi_line = LinesMetric::next(self.search_string.as_ref().unwrap(), 0).is_some();
            let is_multi_line_regex = self.regex.is_some() && is_multiline_regex(self.search_string.as_ref().unwrap());

            if is_multi_line || is_multi_line_regex {
                // ... the end of the file
                self.occurrences.delete_range(iv.start(), text.len(), false);
                self.update_find(text, start, text.len(), false);
            } else {
                // ... the end of the line including line break
                let mut cursor = Cursor::new(&text, iv.end());

                let end_of_line = match cursor.next::<LinesMetric>() {
                    Some(end) => end,
                    None if cursor.pos() == text.len() => cursor.pos(),
                    _ => return
                };

                self.occurrences.delete_range(iv.start(), end_of_line, false);
                self.update_find(text, start, end_of_line, false);
            }
        }
    }

    /// Set search parameters and executes the search.
    pub fn do_find(&mut self, text: &Rope, search_string: &str, case_sensitive: bool,
                   is_regex: bool, whole_words: bool) {
        if search_string.len() == 0 {
            self.unset();
        }

        self.set_find(search_string, case_sensitive, is_regex, whole_words);
        self.update_find(text, 0, text.len(), false);
    }

    /// Unsets the search and removes all highlights from the view.
    pub fn unset(&mut self) {
        self.search_string = None;
        self.occurrences = Selection::new();
        self.hls_dirty = true;
    }

    /// Sets find parameters and search query.
    fn set_find(&mut self, search_string: &str, case_sensitive: bool, is_regex: bool, whole_words: bool) {
        let case_matching = if case_sensitive {
            CaseMatching::Exact
        } else {
            CaseMatching::CaseInsensitive
        };

        if let Some(ref s) = self.search_string {
            if s == search_string && case_matching == self.case_matching &&
                self.regex.is_some() == is_regex && self.whole_words == whole_words {
                // search parameters did not change
                return;
            }
        }

        self.unset();

        self.search_string = Some(search_string.to_string());
        self.case_matching = case_matching;
        self.whole_words = whole_words;

        // create regex from untrusted input
        self.regex = match is_regex {
            false => None,
            true => {
                RegexBuilder::new(search_string)
                    .size_limit(REGEX_SIZE_LIMIT)
                    .case_insensitive(case_matching == CaseMatching::CaseInsensitive)
                    .build()
                    .ok()
            }
        };
    }

    /// Execute the search on the provided text in the range provided by `start` and `end`.
    pub fn update_find(&mut self, text: &Rope, start: usize, end: usize, include_slop: bool)
    {
        if self.search_string.is_none() {
            return;
        }

        // extend the search by twice the string length (twice, because case matching may increase
        // the length of an occurrence)
        let slop = if include_slop { self.search_string.as_ref().unwrap().len() * 2 } else { 0 };

        let search_string = self.search_string.as_ref().unwrap();

        // expand region to be able to find occurrences around the region's edges
        let from = max(start, slop) - slop;
        let to = min(end + slop, text.len());

        // TODO: this interval might cut a unicode codepoint, make sure it is
        // aligned to codepoint boundaries.
        let sub_text = text.subseq(Interval::new_closed_open(0, to));
        let mut find_cursor = Cursor::new(&sub_text, from);
        let mut raw_lines = text.lines_raw(from..to);

        while let Some(start) = find(&mut find_cursor, &mut raw_lines, self.case_matching,
                                     &search_string, &self.regex) {
            let end = find_cursor.pos();

            if self.whole_words && !self.is_matching_whole_words(text, start, end) {
                raw_lines = text.lines_raw(find_cursor.pos()..to);
                continue;
            }

            let region = SelRegion::new(start, end);
            let (_, e) = self.occurrences.add_range_distinct(region);
            // in case of ambiguous search results (e.g. search "aba" in "ababa"),
            // the search result closer to the beginning of the file wins
            if e != end {
                // Skip the search result and keep the occurrence that is closer to
                // the beginning of the file. Re-align the cursor to the kept
                // occurrence
                find_cursor.set(e);
                raw_lines = text.lines_raw(find_cursor.pos()..to);
                continue;
            }

            // in case current cursor matches search result (for example query a* matches)
            // all cursor positions, then cursor needs to be increased so that search
            // continues at next position. Otherwise, search will result in overflow since
            // search will always repeat at current cursor position.
            if start == end {
                // determine whether end of text is reached and stop search or increase
                // cursor manually
                if end + 1 >= text.len() {
                    break;
                } else {
                    find_cursor.set(end + 1);
                }
            }

            // update line iterator so that line starts at current cursor position
            raw_lines = text.lines_raw(find_cursor.pos()..to);
        }

        self.hls_dirty = true;
    }

    /// Return the occurrence closest to the provided selection `sel`. If searched is reversed then
    /// the occurrence closest to the start of the selection is returned. `wrapped` indicates that
    /// if the end of the text is reached the search continues from the start.
    pub fn next_occurrence(&self, text: &Rope, reverse: bool, wrapped: bool, sel: &Selection) -> Option<SelRegion> {
        if self.occurrences.len() == 0 {
            return None;
        }

        let (sel_start, sel_end) = match sel.last() {
            Some(last) if last.is_caret() =>
                // if last selection is caret then allow the current position to be part of the occurrence
                (last.min(), last.max()),
            Some(last) if !last.is_caret() =>
                // if the last selection is not a caret then continue searching after the caret
                (last.min(), last.max() + 1),
            _ => (0, 0)
        };

        if reverse {
            let next_occurrence = match sel_start.checked_sub(1) {
                Some(search_end) => self.occurrences.regions_in_range(0, search_end).last(),
                None => None
            };

            if next_occurrence.is_none() && !wrapped {
                // get previous unselected occurrence
                return self.occurrences.regions_in_range(0, text.len()).iter().cloned().filter(|o| {
                    sel.regions_in_range(o.min(), o.max()).is_empty()
                }).collect::<Vec<SelRegion>>().last().cloned();
            }

            next_occurrence.cloned()
        } else {
            let next_occurrence = self.occurrences.regions_in_range(sel_end, text.len()).first();

            if next_occurrence.is_none() && !wrapped {
                // get next unselected occurrence
                return self.occurrences.regions_in_range(0, text.len()).iter().cloned().filter(|o| {
                    sel.regions_in_range(o.min(), o.max()).is_empty()
                }).collect::<Vec<SelRegion>>().first().cloned();
            }

            next_occurrence.cloned()
        }
    }

    /// Checks if the start and end of a match is matching whole words.
    fn is_matching_whole_words(&self, text: &Rope, start: usize, end: usize) -> bool {
        let mut word_end_cursor = WordCursor::new(text, end - 1);
        let mut word_start_cursor = WordCursor::new(text, start + 1);

        if let Some(start_boundary) = word_start_cursor.prev_boundary() {
            if start_boundary != start {
                return false;
            }
        }

        if let Some(end_boundary) = word_end_cursor.next_boundary() {
            if end_boundary != end {
                return false;
            }
        }

        true
    }
}<commit_msg>Fix doc comment<commit_after>// Copyright 2018 The xi-editor Authors.
//
// 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.

//! Module for searching text.

use std::cmp::{min,max};

use xi_rope::delta::{Delta, DeltaRegion};
use xi_rope::find::{find, is_multiline_regex, CaseMatching};
use xi_rope::rope::{Rope, LinesMetric, RopeInfo};
use xi_rope::tree::Cursor;
use xi_rope::interval::Interval;
use selection::{Selection, SelRegion};
use xi_rope::tree::Metric;
use regex::{RegexBuilder, Regex};
use word_boundaries::WordCursor;

const REGEX_SIZE_LIMIT: usize = 1000000;

/// Information about search queries and number of matches for find
#[derive(Serialize, Deserialize, Debug)]
pub struct FindStatus {
    /// Identifier for the current search query.
    id: usize,

    /// The current search query.
    chars: Option<String>,

    /// Whether the active search is case matching.
    case_sensitive: Option<bool>,

    /// Whether the search query is considered as regular expression.
    is_regex: Option<bool>,

    /// Query only matches whole words.
    whole_words: Option<bool>,

    /// Total number of matches.
    matches: usize
}

/// Contains logic to search text
pub struct Find {
    /// Uniquely identifies this search query.
    id: usize,
    /// The occurrences, which determine the highlights, have been updated.
    hls_dirty: bool,
    /// The currently active search string.
    search_string: Option<String>,
    /// The case matching setting for the currently active search.
    case_matching: CaseMatching,
    /// The search query should be considered as regular expression.
    regex: Option<Regex>,
    /// Query matches only whole words.
    whole_words: bool,
    /// The set of all known find occurrences (highlights).
    occurrences: Selection,
}

impl Find {
    pub fn new(id: usize) -> Find {
        Find {
            id: id,
            hls_dirty: true,
            search_string: None,
            case_matching: CaseMatching::CaseInsensitive,
            regex: None,
            whole_words: false,
            occurrences: Selection::new(),
        }
    }

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

    pub fn occurrences(&self) -> &Selection {
        &self.occurrences
    }

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

    pub fn find_status(&self, matches_only: bool) -> FindStatus {
        if matches_only {
            FindStatus {
                id: self.id,
                chars: None,
                case_sensitive: None,
                is_regex: None,
                whole_words: None,
                matches: self.occurrences.len(),
            }
        } else {
            FindStatus {
                id: self.id,
                chars: self.search_string.clone(),
                case_sensitive: Some(self.case_matching == CaseMatching::Exact),
                is_regex: Some(self.regex.is_some()),
                whole_words: Some(self.whole_words),
                matches: self.occurrences.len(),
            }
        }
    }

    pub fn set_hls_dirty(&mut self, is_dirty: bool) {
        self.hls_dirty = is_dirty
    }

    pub fn update_highlights(&mut self, text: &Rope, delta: &Delta<RopeInfo>) {
        // update search highlights for changed regions
        if self.search_string.is_some() {
            // invalidate occurrences around deletion positions
            for DeltaRegion{ old_offset, new_offset: _, len } in delta.iter_deletions() {
                self.occurrences.delete_range(old_offset, old_offset + len, false);
            }

            self.occurrences = self.occurrences.apply_delta(delta, false, false);

            // invalidate occurrences around insert positions
            for DeltaRegion{ new_offset, len, .. } in delta.iter_inserts() {
                // also invalidate previous occurrence since it might expand after insertion
                // eg. for regex .* every insertion after match will be part of match
                self.occurrences.delete_range(new_offset.checked_sub(1).unwrap_or(0), new_offset + len, false);
            }

            // update find for the whole delta and everything after
            let (iv, _) = delta.summary();

            // get last valid occurrence that was unaffected by the delta
            let start = match self.occurrences.regions_in_range(0, iv.start()).last() {
                Some(reg) => reg.end,
                None => 0
            };

            // invalidate all search results from the point of the last valid search result until ...
            let is_multi_line = LinesMetric::next(self.search_string.as_ref().unwrap(), 0).is_some();
            let is_multi_line_regex = self.regex.is_some() && is_multiline_regex(self.search_string.as_ref().unwrap());

            if is_multi_line || is_multi_line_regex {
                // ... the end of the file
                self.occurrences.delete_range(iv.start(), text.len(), false);
                self.update_find(text, start, text.len(), false);
            } else {
                // ... the end of the line including line break
                let mut cursor = Cursor::new(&text, iv.end());

                let end_of_line = match cursor.next::<LinesMetric>() {
                    Some(end) => end,
                    None if cursor.pos() == text.len() => cursor.pos(),
                    _ => return
                };

                self.occurrences.delete_range(iv.start(), end_of_line, false);
                self.update_find(text, start, end_of_line, false);
            }
        }
    }

    /// Set search parameters and executes the search.
    pub fn do_find(&mut self, text: &Rope, search_string: &str, case_sensitive: bool,
                   is_regex: bool, whole_words: bool) {
        if search_string.len() == 0 {
            self.unset();
        }

        self.set_find(search_string, case_sensitive, is_regex, whole_words);
        self.update_find(text, 0, text.len(), false);
    }

    /// Unsets the search and removes all highlights from the view.
    pub fn unset(&mut self) {
        self.search_string = None;
        self.occurrences = Selection::new();
        self.hls_dirty = true;
    }

    /// Sets find parameters and search query.
    fn set_find(&mut self, search_string: &str, case_sensitive: bool, is_regex: bool, whole_words: bool) {
        let case_matching = if case_sensitive {
            CaseMatching::Exact
        } else {
            CaseMatching::CaseInsensitive
        };

        if let Some(ref s) = self.search_string {
            if s == search_string && case_matching == self.case_matching &&
                self.regex.is_some() == is_regex && self.whole_words == whole_words {
                // search parameters did not change
                return;
            }
        }

        self.unset();

        self.search_string = Some(search_string.to_string());
        self.case_matching = case_matching;
        self.whole_words = whole_words;

        // create regex from untrusted input
        self.regex = match is_regex {
            false => None,
            true => {
                RegexBuilder::new(search_string)
                    .size_limit(REGEX_SIZE_LIMIT)
                    .case_insensitive(case_matching == CaseMatching::CaseInsensitive)
                    .build()
                    .ok()
            }
        };
    }

    /// Execute the search on the provided text in the range provided by `start` and `end`.
    pub fn update_find(&mut self, text: &Rope, start: usize, end: usize, include_slop: bool)
    {
        if self.search_string.is_none() {
            return;
        }

        // extend the search by twice the string length (twice, because case matching may increase
        // the length of an occurrence)
        let slop = if include_slop { self.search_string.as_ref().unwrap().len() * 2 } else { 0 };

        let search_string = self.search_string.as_ref().unwrap();

        // expand region to be able to find occurrences around the region's edges
        let from = max(start, slop) - slop;
        let to = min(end + slop, text.len());

        // TODO: this interval might cut a unicode codepoint, make sure it is
        // aligned to codepoint boundaries.
        let sub_text = text.subseq(Interval::new_closed_open(0, to));
        let mut find_cursor = Cursor::new(&sub_text, from);
        let mut raw_lines = text.lines_raw(from..to);

        while let Some(start) = find(&mut find_cursor, &mut raw_lines, self.case_matching,
                                     &search_string, &self.regex) {
            let end = find_cursor.pos();

            if self.whole_words && !self.is_matching_whole_words(text, start, end) {
                raw_lines = text.lines_raw(find_cursor.pos()..to);
                continue;
            }

            let region = SelRegion::new(start, end);
            let (_, e) = self.occurrences.add_range_distinct(region);
            // in case of ambiguous search results (e.g. search "aba" in "ababa"),
            // the search result closer to the beginning of the file wins
            if e != end {
                // Skip the search result and keep the occurrence that is closer to
                // the beginning of the file. Re-align the cursor to the kept
                // occurrence
                find_cursor.set(e);
                raw_lines = text.lines_raw(find_cursor.pos()..to);
                continue;
            }

            // in case current cursor matches search result (for example query a* matches)
            // all cursor positions, then cursor needs to be increased so that search
            // continues at next position. Otherwise, search will result in overflow since
            // search will always repeat at current cursor position.
            if start == end {
                // determine whether end of text is reached and stop search or increase
                // cursor manually
                if end + 1 >= text.len() {
                    break;
                } else {
                    find_cursor.set(end + 1);
                }
            }

            // update line iterator so that line starts at current cursor position
            raw_lines = text.lines_raw(find_cursor.pos()..to);
        }

        self.hls_dirty = true;
    }

    /// Return the occurrence closest to the provided selection `sel`. If searched is reversed then
    /// the occurrence closest to the start of the selection is returned. `wrapped` indicates that
    /// if the end of the text is reached the search continues from the start.
    pub fn next_occurrence(&self, text: &Rope, reverse: bool, wrapped: bool, sel: &Selection) -> Option<SelRegion> {
        if self.occurrences.len() == 0 {
            return None;
        }

        let (sel_start, sel_end) = match sel.last() {
            Some(last) if last.is_caret() =>
                // if last selection is caret then allow the current position to be part of the occurrence
                (last.min(), last.max()),
            Some(last) if !last.is_caret() =>
                // if the last selection is not a caret then continue searching after the caret
                (last.min(), last.max() + 1),
            _ => (0, 0)
        };

        if reverse {
            let next_occurrence = match sel_start.checked_sub(1) {
                Some(search_end) => self.occurrences.regions_in_range(0, search_end).last(),
                None => None
            };

            if next_occurrence.is_none() && !wrapped {
                // get previous unselected occurrence
                return self.occurrences.regions_in_range(0, text.len()).iter().cloned().filter(|o| {
                    sel.regions_in_range(o.min(), o.max()).is_empty()
                }).collect::<Vec<SelRegion>>().last().cloned();
            }

            next_occurrence.cloned()
        } else {
            let next_occurrence = self.occurrences.regions_in_range(sel_end, text.len()).first();

            if next_occurrence.is_none() && !wrapped {
                // get next unselected occurrence
                return self.occurrences.regions_in_range(0, text.len()).iter().cloned().filter(|o| {
                    sel.regions_in_range(o.min(), o.max()).is_empty()
                }).collect::<Vec<SelRegion>>().first().cloned();
            }

            next_occurrence.cloned()
        }
    }

    /// Checks if the start and end of a match is matching whole words.
    fn is_matching_whole_words(&self, text: &Rope, start: usize, end: usize) -> bool {
        let mut word_end_cursor = WordCursor::new(text, end - 1);
        let mut word_start_cursor = WordCursor::new(text, start + 1);

        if let Some(start_boundary) = word_start_cursor.prev_boundary() {
            if start_boundary != start {
                return false;
            }
        }

        if let Some(end_boundary) = word_end_cursor.next_boundary() {
            if end_boundary != end {
                return false;
            }
        }

        true
    }
}<|endoftext|>


<commit_before>const P: i64 = 1_000_000_007;

/// Calcuates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

#[cfg(test)]
mod tests {
    use super::{pow, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }
}
<commit_msg>feat: Add 'Finite'<commit_after>use std::ops::*;

const P: i64 = 1_000_000_007;

/// Calculates `x^n`. O(log n) time.
/// By Fermat's little theorem, `x^(-1) = pow(x, P - 2)`.
pub fn pow(x: i64, n: i64) -> i64 {
    let (mut x, mut y, mut n) = (x % P, 1_i64, n);
    while n > 0 {
        if n % 2 != 0 {
            y = (y * x) % P;
            n -= 1;
        }

        x = (x * x) % P;
        n /= 2;
    }
    y
}

/// Represents an element of finite field.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
struct Finite<T>(T);

trait Normalize {
    fn normalize(&mut self);
}

impl<T> From<T> for Finite<T>
where
    Finite<T>: Normalize,
{
    fn from(value: T) -> Self {
        let mut it = Finite(value);
        it.normalize();
        it
    }
}

// Derive binary operation trait from the `FooAssign` impl.
// Define `x + y` as `{ let mut x = x.clone(); x += y; x }`.
macro_rules! impl_binary_op_for_finite {
    ($op_trait:ident, $op:ident, $assign_trait:ident, $assign:ident) => {
        impl<T: $op_trait<T, Output = T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<T>,
        {
            type Output = Self;

            fn $op(self, other: T) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }

        impl<T: $op_trait<T, Output = T>> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: Clone + $assign_trait<Finite<T>>,
        {
            type Output = Self;

            fn $op(self, other: Self) -> Self {
                let mut it = self.clone();
                it.$assign(other);
                it
            }
        }
    };
}

// Derive assign operation trait by unwrapping the right hand side.
macro_rules! impl_binary_op_assign_with_finite_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T> $op_trait<Finite<T>> for Finite<T>
        where
            Finite<T>: $op_trait<T>,
        {
            fn $op(&mut self, other: Self) {
                self.$op(other.0);
            }
        }
    };
}

// Derive assign operation trait from impl for inner type.
macro_rules! impl_binary_op_assign_with_inner_for_finite {
    ($op_trait:ident, $op:ident) => {
        impl<T: $op_trait<T>> $op_trait<T> for Finite<T>
        where
            Finite<T>: Normalize,
        {
            fn $op(&mut self, other: T) {
                let mut other = Finite::from(other);
                other.normalize();
                (self.0).$op(other.0);
                self.normalize();
            }
        }
    };
}

impl_binary_op_for_finite! {Add, add, AddAssign, add_assign}
impl_binary_op_for_finite! {Sub, sub, SubAssign, sub_assign}
impl_binary_op_for_finite! {Mul, mul, MulAssign, mul_assign}
impl_binary_op_for_finite! {Div, div, DivAssign, div_assign}
impl_binary_op_assign_with_inner_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_inner_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_inner_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {AddAssign, add_assign}
impl_binary_op_assign_with_finite_for_finite! {SubAssign, sub_assign}
impl_binary_op_assign_with_finite_for_finite! {MulAssign, mul_assign}
impl_binary_op_assign_with_finite_for_finite! {DivAssign, div_assign}

impl Finite<i64> {
    fn pow(self, e: i64) -> Self {
        pow(self.0, e).into()
    }
}

impl Normalize for Finite<i64> {
    fn normalize(&mut self) {
        self.0 %= P;
        self.0 += P;
        self.0 %= P;
    }
}

impl DivAssign<i64> for Finite<i64> {
    fn div_assign(&mut self, other: i64) {
        *self *= Self::from(other).pow(P - 2);
    }
}

#[cfg(test)]
mod tests {
    use super::{pow, Finite, P};
    use std;

    #[test]
    fn test_pow_edges() {
        assert_eq!(pow(0, 0), 1);
        assert_eq!(pow(2, 0), 1);
        assert_eq!(pow(3, 1), 3);
        assert_eq!(pow(5, 6), (5 * 5 * 5) * (5 * 5 * 5));
        assert_eq!(pow(std::i64::MAX % P, std::i64::MAX), 856225998);
    }

    #[test]
    fn test_pow_small() {
        for x in 0..100_i64 {
            for n in 0..100_i64 {
                let actual = pow(x, n);
                let expected = (0..n).fold(1_i64, |acc, _| (acc * x) % P);
                assert_eq!(actual, expected, "{}^{}", x, n);
            }
        }
    }

    #[test]
    fn test_finite() {
        let x = Finite::from(P + 2);

        // `from` should normalize the value.
        assert_eq!(x.0, 2);

        // Operations.
        assert_eq!(x + 7, (2 + 7).into());
        assert_eq!(x - 7, (P + (2 - 7)).into());
        assert_eq!(x * 3, (2 * 3).into());
        assert_eq!((x / 11) * 11, 2.into());

        assert_eq!(x + Finite::from(7), (2 + 7).into());
        assert_eq!(x - Finite::from(7), (P + (2 - 7)).into());
        assert_eq!(x * Finite::from(3), (2 * 3).into());
        assert_eq!((x / Finite::from(11)) * 11, 2.into());

        let mut x = x;
        x += 7;
        assert_eq!(x, 9.into());
        x -= 5;
        assert_eq!(x, 4.into());
        x *= 6;
        assert_eq!(x, 24.into());
        x /= 3;
        assert_eq!(x, 8.into());
    }
}
<|endoftext|>


<commit_before>#[allow(ctypes)];
#[no_std];
#[no_core];

mod zero;

enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: &fn(uint)) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

unsafe fn clear_screen(background: Color) {
    range(0, 80*25, |i| {
        *((0xb8000 + i * 2) as *mut u16) = (background as u16) << 12;
    });
}

#[no_mangle]
pub unsafe fn main() {
    clear_screen(LightRed);
}
<commit_msg>Update for new closure syntax<commit_after>#[allow(ctypes)];
#[no_std];
#[no_core];

mod zero;

enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: |uint| -> ()) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

unsafe fn clear_screen(background: Color) {
    range(0, 80*25, |i| {
        *((0xb8000 + i * 2) as *mut u16) = (background as u16) << 12;
    });
}

#[no_mangle]
pub unsafe fn main() {
    clear_screen(LightRed);
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::convert::From;

/**
 * Kind of store error
 */
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StoreErrorKind {
    FileError,
    IdLocked,
    IdNotFound,
    OutOfMemory,
    FileNotFound,
    FileNotCreated,
    IoError,
    StorePathExists,
    StorePathCreate,
    LockPoisoned,
    EntryAlreadyBorrowed,
    EntryAlreadyExists,
    MalformedEntry,
    HeaderPathSyntaxError,
    HeaderPathTypeFailure,
    HeaderKeyNotFound,
    HeaderTypeFailure,
    HookRegisterError,
    PreHookExecuteError,
    PostHookExecuteError,
        // maybe more
}

fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str {
    match e {
        &StoreErrorKind::FileError       => "File Error",
        &StoreErrorKind::IdLocked        => "ID locked",
        &StoreErrorKind::IdNotFound      => "ID not found",
        &StoreErrorKind::OutOfMemory     => "Out of Memory",
        &StoreErrorKind::FileNotFound    => "File corresponding to ID not found",
        &StoreErrorKind::FileNotCreated  => "File corresponding to ID could not be created",
        &StoreErrorKind::IoError         => "File Error",
        &StoreErrorKind::StorePathExists => "Store path exists",
        &StoreErrorKind::StorePathCreate => "Store path create",
        &StoreErrorKind::LockPoisoned
            => "The internal Store Lock has been poisoned",
        &StoreErrorKind::EntryAlreadyBorrowed => "Entry is already borrowed",
        &StoreErrorKind::EntryAlreadyExists   => "Entry already exists",
        &StoreErrorKind::MalformedEntry => "Entry has invalid formatting, missing header",
        &StoreErrorKind::HeaderPathSyntaxError => "Syntax error in accessor string",
        &StoreErrorKind::HeaderPathTypeFailure => "Header has wrong type for path",
        &StoreErrorKind::HeaderKeyNotFound     => "Header Key not found",
        &StoreErrorKind::HeaderTypeFailure     => "Header type is wrong",
        &StoreErrorKind::HookRegisterError     => "Hook register error",
        &StoreErrorKind::PreHookExecuteError   => "Pre-Hook execution error",
        &StoreErrorKind::PostHookExecuteError  => "Post-Hook execution error",
    }
}

impl Display for StoreErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", store_error_type_as_str(self)));
        Ok(())
    }

}

/**
 * Store error type
 */
#[derive(Debug)]
pub struct StoreError {
    err_type: StoreErrorKind,
    cause: Option<Box<Error>>,
}

impl StoreError {

    /**
     * Build a new StoreError from an StoreErrorKind, optionally with cause
     */
    pub fn new(errtype: StoreErrorKind, cause: Option<Box<Error>>)
        -> StoreError
        {
            StoreError {
                err_type: errtype,
                cause: cause,
            }
        }

    /**
     * Get the error type of this StoreError
     */
    pub fn err_type(&self) -> StoreErrorKind {
        self.err_type.clone()
    }

}

impl Display for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", store_error_type_as_str(&self.err_type.clone())));
        Ok(())
    }

}

impl Error for StoreError {

    fn description(&self) -> &str {
        store_error_type_as_str(&self.err_type.clone())
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
        }
    }
}

#[derive(Clone)]
pub enum ParserErrorKind {
    TOMLParserErrors,
    MissingMainSection,
    MissingVersionInfo,
    NonTableInBaseTable,
    HeaderInconsistency,
}

pub struct ParserError {
    kind: ParserErrorKind,
    cause: Option<Box<Error>>,
}

impl ParserError {

    pub fn new(k: ParserErrorKind, cause: Option<Box<Error>>) -> ParserError {
        ParserError {
            kind: k,
            cause: cause,
        }
    }

}

impl Debug for ParserError {

    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{:?}", self.description()));
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{}", self.description()));
        Ok(())
    }

}

impl Error for ParserError {

    fn description(&self) -> &str {
        match self.kind {
            ParserErrorKind::TOMLParserErrors   => "Several TOML-Parser-Errors",
            ParserErrorKind::MissingMainSection => "Missing main section",
            ParserErrorKind::MissingVersionInfo => "Missing version information in main section",
            ParserErrorKind::NonTableInBaseTable => "A non-table was found in the base table",
            ParserErrorKind::HeaderInconsistency => "The header is inconsistent",
        }
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

<commit_msg>Add HookExecutionError error kind<commit_after>use std::error::Error;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::convert::From;

/**
 * Kind of store error
 */
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StoreErrorKind {
    FileError,
    IdLocked,
    IdNotFound,
    OutOfMemory,
    FileNotFound,
    FileNotCreated,
    IoError,
    StorePathExists,
    StorePathCreate,
    LockPoisoned,
    EntryAlreadyBorrowed,
    EntryAlreadyExists,
    MalformedEntry,
    HeaderPathSyntaxError,
    HeaderPathTypeFailure,
    HeaderKeyNotFound,
    HeaderTypeFailure,
    HookRegisterError,
    HookExecuteError,
    PreHookExecuteError,
    PostHookExecuteError,
        // maybe more
}

fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str {
    match e {
        &StoreErrorKind::FileError       => "File Error",
        &StoreErrorKind::IdLocked        => "ID locked",
        &StoreErrorKind::IdNotFound      => "ID not found",
        &StoreErrorKind::OutOfMemory     => "Out of Memory",
        &StoreErrorKind::FileNotFound    => "File corresponding to ID not found",
        &StoreErrorKind::FileNotCreated  => "File corresponding to ID could not be created",
        &StoreErrorKind::IoError         => "File Error",
        &StoreErrorKind::StorePathExists => "Store path exists",
        &StoreErrorKind::StorePathCreate => "Store path create",
        &StoreErrorKind::LockPoisoned
            => "The internal Store Lock has been poisoned",
        &StoreErrorKind::EntryAlreadyBorrowed => "Entry is already borrowed",
        &StoreErrorKind::EntryAlreadyExists   => "Entry already exists",
        &StoreErrorKind::MalformedEntry => "Entry has invalid formatting, missing header",
        &StoreErrorKind::HeaderPathSyntaxError => "Syntax error in accessor string",
        &StoreErrorKind::HeaderPathTypeFailure => "Header has wrong type for path",
        &StoreErrorKind::HeaderKeyNotFound     => "Header Key not found",
        &StoreErrorKind::HeaderTypeFailure     => "Header type is wrong",
        &StoreErrorKind::HookRegisterError     => "Hook register error",
        &StoreErrorKind::HookExecutionError    => "Hook execution error",
        &StoreErrorKind::PreHookExecuteError   => "Pre-Hook execution error",
        &StoreErrorKind::PostHookExecuteError  => "Post-Hook execution error",
    }
}

impl Display for StoreErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", store_error_type_as_str(self)));
        Ok(())
    }

}

/**
 * Store error type
 */
#[derive(Debug)]
pub struct StoreError {
    err_type: StoreErrorKind,
    cause: Option<Box<Error>>,
}

impl StoreError {

    /**
     * Build a new StoreError from an StoreErrorKind, optionally with cause
     */
    pub fn new(errtype: StoreErrorKind, cause: Option<Box<Error>>)
        -> StoreError
        {
            StoreError {
                err_type: errtype,
                cause: cause,
            }
        }

    /**
     * Get the error type of this StoreError
     */
    pub fn err_type(&self) -> StoreErrorKind {
        self.err_type.clone()
    }

}

impl Display for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", store_error_type_as_str(&self.err_type.clone())));
        Ok(())
    }

}

impl Error for StoreError {

    fn description(&self) -> &str {
        store_error_type_as_str(&self.err_type.clone())
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
        }
    }
}

#[derive(Clone)]
pub enum ParserErrorKind {
    TOMLParserErrors,
    MissingMainSection,
    MissingVersionInfo,
    NonTableInBaseTable,
    HeaderInconsistency,
}

pub struct ParserError {
    kind: ParserErrorKind,
    cause: Option<Box<Error>>,
}

impl ParserError {

    pub fn new(k: ParserErrorKind, cause: Option<Box<Error>>) -> ParserError {
        ParserError {
            kind: k,
            cause: cause,
        }
    }

}

impl Debug for ParserError {

    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{:?}", self.description()));
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{}", self.description()));
        Ok(())
    }

}

impl Error for ParserError {

    fn description(&self) -> &str {
        match self.kind {
            ParserErrorKind::TOMLParserErrors   => "Several TOML-Parser-Errors",
            ParserErrorKind::MissingMainSection => "Missing main section",
            ParserErrorKind::MissingVersionInfo => "Missing version information in main section",
            ParserErrorKind::NonTableInBaseTable => "A non-table was found in the base table",
            ParserErrorKind::HeaderInconsistency => "The header is inconsistent",
        }
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

<|endoftext|>


<commit_before>use std::result::Result as RResult;
use std::string;

pub use entry::Entry;
pub use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;
pub type LockedEntry = SingleUseLock<Entry>;

pub trait Store {
    fn create(&self, entry : Entry) -> Result<()>;
    fn retrieve(&self, id : string) -> Result<LockedEntry>;
    fn retrieve_copy(&self, id : string) -> Result<Entry>;
    fn update(&self, LockedEntry) -> Result<()>;
    fn delete(&self, id : string) -> Result<()>;
}

<commit_msg>Add missing inclusion of SingeUseLock type<commit_after>use std::result::Result as RResult;
use std::string;

pub use entry::Entry;
pub use error::StoreError;
pub use single_use_lock::SingleUseLock;

pub type Result<T> = RResult<T, StoreError>;
pub type LockedEntry = SingleUseLock<Entry>;

pub trait Store {
    fn create(&self, entry : Entry) -> Result<()>;
    fn retrieve(&self, id : string) -> Result<LockedEntry>;
    fn retrieve_copy(&self, id : string) -> Result<Entry>;
    fn update(&self, LockedEntry) -> Result<()>;
    fn delete(&self, id : string) -> Result<()>;
}

<|endoftext|>


<commit_before>extern crate neli;
#[cfg(feature = "stream")]
extern crate tokio;

use std::env;

use neli::consts;
use neli::genl::Genlmsghdr;
use neli::socket;
#[cfg(feature = "stream")]
use tokio::prelude::{Future,Stream};

#[cfg(feature = "stream")]
fn debug_stream() -> Result<(), neli::err::NlError> {
    let mut args = env::args();
    let _ = args.next();
    let first_arg = args.next();
    let second_arg = args.next();
    let (family_name, mc_group_name) = match (first_arg, second_arg) {
        (Some(fam_name), Some(mc_name)) => (fam_name, mc_name),
        (_, _) => {
            println!("USAGE: genl_stream FAMILY_NAME MULTICAST_GROUP_NAME");
            std::process::exit(1)
        },
    };
    let mut s = socket::NlSocket::connect(consts::NlFamily::Generic,
                                          None, None, true)?;
    let id = s.resolve_nl_mcast_group(&family_name, &mc_group_name)?;
    s.set_mcast_groups(vec![id])?;
    let ss = neli::socket::tokio::NlSocket::<u16, Genlmsghdr<u8, u16, Vec<u8>>>::new(s)?;
    tokio::run(ss.for_each(|next| {
        println!("{:?}", next);
        Ok(())
    }).map(|_| ()).map_err(|_| ()));
    Ok(())
}

#[cfg(not(feature = "stream"))]
fn debug_stream() -> Result<(), neli::err::NlError> {
    let mut args = env::args();
    let _ = args.next();
    let first_arg = args.next();
    let second_arg = args.next();
    let (family_name, mc_group_name) = match (first_arg, second_arg) {
        (Some(fam_name), Some(mc_name)) => (fam_name, mc_name),
        (_, _) => {
            println!("USAGE: genl_stream FAMILY_NAME MULTICAST_GROUP_NAME");
            std::process::exit(1)
        },
    };
    let mut s = socket::NlSocket::connect(consts::NlFamily::Generic,
                                          None, None, true)?;
    let id = s.resolve_nl_mcast_group(&family_name, &mc_group_name)?;
    s.set_mcast_groups(vec![id])?;
    for next in s.iter::<u16, Genlmsghdr<u8, u16>>() {
        println!("{:?}", next?);
    }
    Ok(())
}

pub fn main() {
    #[cfg(feature = "stream")]
    match debug_stream() {
        Ok(_) => (),
        Err(e) => {
            println!("{}", e);
        }
    };
    #[cfg(not(feature = "stream"))]
    match debug_stream() {
        Ok(_) => (),
        Err(e) => {
            println!("{}", e);
        }
    };
}
<commit_msg>Fix examples/genl_stream.rs for features=stream<commit_after>extern crate neli;
#[cfg(feature = "stream")]
extern crate tokio;

use std::env;

use neli::consts;
use neli::genl::Genlmsghdr;
use neli::socket;
#[cfg(feature = "stream")]
use tokio::prelude::{Future,Stream};

#[cfg(feature = "stream")]
fn debug_stream() -> Result<(), neli::err::NlError> {
    let mut args = env::args();
    let _ = args.next();
    let first_arg = args.next();
    let second_arg = args.next();
    let (family_name, mc_group_name) = match (first_arg, second_arg) {
        (Some(fam_name), Some(mc_name)) => (fam_name, mc_name),
        (_, _) => {
            println!("USAGE: genl_stream FAMILY_NAME MULTICAST_GROUP_NAME");
            std::process::exit(1)
        },
    };
    let mut s = socket::NlSocket::connect(consts::NlFamily::Generic,
                                          None, None, true)?;
    let id = s.resolve_nl_mcast_group(&family_name, &mc_group_name)?;
    s.set_mcast_groups(vec![id])?;
    let ss = neli::socket::tokio::NlSocket::<u16, Genlmsghdr<u8, u16>>::new(s)?;
    tokio::run(ss.for_each(|next| {
        println!("{:?}", next);
        Ok(())
    }).map(|_| ()).map_err(|_| ()));
    Ok(())
}

#[cfg(not(feature = "stream"))]
fn debug_stream() -> Result<(), neli::err::NlError> {
    let mut args = env::args();
    let _ = args.next();
    let first_arg = args.next();
    let second_arg = args.next();
    let (family_name, mc_group_name) = match (first_arg, second_arg) {
        (Some(fam_name), Some(mc_name)) => (fam_name, mc_name),
        (_, _) => {
            println!("USAGE: genl_stream FAMILY_NAME MULTICAST_GROUP_NAME");
            std::process::exit(1)
        },
    };
    let mut s = socket::NlSocket::connect(consts::NlFamily::Generic,
                                          None, None, true)?;
    let id = s.resolve_nl_mcast_group(&family_name, &mc_group_name)?;
    s.set_mcast_groups(vec![id])?;
    for next in s.iter::<u16, Genlmsghdr<u8, u16>>() {
        println!("{:?}", next?);
    }
    Ok(())
}

pub fn main() {
    #[cfg(feature = "stream")]
    match debug_stream() {
        Ok(_) => (),
        Err(e) => {
            println!("{}", e);
        }
    };
    #[cfg(not(feature = "stream"))]
    match debug_stream() {
        Ok(_) => (),
        Err(e) => {
            println!("{}", e);
        }
    };
}
<|endoftext|>


<commit_before>extern crate time;
#[cfg(test)]
extern crate quickcheck;

use std::cmp;
use std::fmt;

// Implementation of Hybrid Logical Clocks, based on the paper "Logical Physical Clocks
// and Consistent Snapshots in Globally Distributed Databases".
//

trait ClockSource {
    type Time : Ord + Copy + fmt::Debug;
    fn now(&mut self) -> Self::Time;
}

#[derive(Debug,Clone,Copy,PartialEq,Eq,PartialOrd,Ord)]
struct Timestamp<T>(T, u32);

struct Clock<S: ClockSource> {
    src: S,
    latest: Timestamp<S::Time>,
}

impl<S: ClockSource> Clock<S> {
    pub fn new(mut src: S) -> Self {
        let init = src.now();
        Clock {
            src: src,
            latest: Timestamp(init, 0),
        }
    }

    pub fn on_send(&mut self) -> Timestamp<S::Time> {
        let pt = self.src.now();
        let lp = self.latest.clone();
        self.latest.0 = cmp::max(lp.0, pt);
        self.latest.1 = if lp.0 == self.latest.0 {
            lp.1 + 1
        } else {
            0
        };

        println!("recv@{:?} → {:?}", pt, self.latest);
        self.latest
    }
    pub fn on_recv(&mut self, msg: &Timestamp<S::Time>) -> Timestamp<S::Time> {
        let pt = self.src.now();
        let lp = self.latest.clone();
        println!("recv@{:?}: {:?}: ← {:?}", pt, lp, msg);

        self.latest.0 = cmp::max(lp.0, msg.0);
        self.latest.1 = match (self.latest.0 == lp.0, self.latest.0 == msg.0) {
            (true, true) => cmp::max(self.latest.1, msg.1) + 1,
            (true, false) => self.latest.1 + 1,
            (false, true) => msg.1 + 1,
            (false, false) => 0,
        };

        println!("recv@{:?}: {:?} → {:?}", pt, lp, self.latest);
        self.latest.clone()
    }
}

#[cfg(test)]
mod tests {
    use super::{Clock, ClockSource, Timestamp};
    use std::cell::Cell;
    use std::cmp::{Ord, Ordering};
    use quickcheck;

    struct ManualClock(Cell<u64>);

    impl<'a> ClockSource for &'a ManualClock {
        type Time = u64;
        fn now(&mut self) -> Self::Time {
            self.0.get()
        }
    }

    #[test]
    fn fig_6_proc_0_a() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        src.0.set(10);
        assert_eq!(clock.on_send(), Timestamp(10, 0))
    }

    #[test]
    fn fig_6_proc_1_a() {
        let src = ManualClock(Cell::new(1));
        let mut clock = Clock::new(&src);
        assert_eq!(clock.on_recv(&Timestamp(10, 0)), Timestamp(10, 1))
    }

    #[test]
    fn fig_6_proc_1_b() {
        let src = ManualClock(Cell::new(1));
        let mut clock = Clock::new(&src);
        let _ = clock.on_recv(&Timestamp(10, 0));
        src.0.set(2);
        assert_eq!(clock.on_send(), Timestamp(10, 2))
    }

    #[test]
    fn fig_6_proc_2_b() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        clock.latest = Timestamp(1, 0);
        src.0.set(2);
        assert_eq!(clock.on_recv(&Timestamp(10, 2)), Timestamp(10, 3))
    }

    #[test]
    fn fig_6_proc_2_c() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        src.0.set(2);
        let _ = clock.on_recv(&Timestamp(10, 2));
        src.0.set(3);
        assert_eq!(clock.on_send(), Timestamp(10, 4))
    }

    #[test]
    fn all_sources_same() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        assert_eq!(clock.on_recv(&Timestamp(0, 5)), Timestamp(0, 6))
    }

    #[test]
    fn handles_time_going_backwards_on_send() {
        let src = ManualClock(Cell::new(10));
        let mut clock = Clock::new(&src);
        let _ = clock.on_send();
        src.0.set(9);
        assert_eq!(clock.on_send(), Timestamp(10, 2))
    }

    #[test]
    fn handles_time_going_backwards_on_recv() {
        let src = ManualClock(Cell::new(10));
        let mut clock = Clock::new(&src);
        let _ = clock.on_send();
        src.0.set(9);
        assert_eq!(clock.on_recv(&Timestamp(0, 0)), Timestamp(10, 2))
    }
}
<commit_msg>Remove debug.<commit_after>extern crate time;
#[cfg(test)]
extern crate quickcheck;

use std::cmp;
use std::fmt;

// Implementation of Hybrid Logical Clocks, based on the paper "Logical Physical Clocks
// and Consistent Snapshots in Globally Distributed Databases".
//

trait ClockSource {
    type Time : Ord + Copy;
    fn now(&mut self) -> Self::Time;
}

#[derive(Debug,Clone,Copy,PartialEq,Eq,PartialOrd,Ord)]
struct Timestamp<T>(T, u32);

struct Clock<S: ClockSource> {
    src: S,
    latest: Timestamp<S::Time>,
}

impl<S: ClockSource> Clock<S> {
    pub fn new(mut src: S) -> Self {
        let init = src.now();
        Clock {
            src: src,
            latest: Timestamp(init, 0),
        }
    }

    pub fn on_send(&mut self) -> Timestamp<S::Time> {
        let pt = self.src.now();
        let lp = self.latest.clone();
        self.latest.0 = cmp::max(lp.0, pt);
        self.latest.1 = if lp.0 == self.latest.0 {
            lp.1 + 1
        } else {
            0
        };

        self.latest
    }
    pub fn on_recv(&mut self, msg: &Timestamp<S::Time>) -> Timestamp<S::Time> {
        let pt = self.src.now();
        let lp = self.latest.clone();

        self.latest.0 = cmp::max(lp.0, msg.0);
        self.latest.1 = match (self.latest.0 == lp.0, self.latest.0 == msg.0) {
            (true, true) => cmp::max(self.latest.1, msg.1) + 1,
            (true, false) => self.latest.1 + 1,
            (false, true) => msg.1 + 1,
            (false, false) => 0,
        };

        self.latest.clone()
    }
}

#[cfg(test)]
mod tests {
    use super::{Clock, ClockSource, Timestamp};
    use std::cell::Cell;
    use std::cmp::{Ord, Ordering};
    use quickcheck;

    struct ManualClock(Cell<u64>);

    impl<'a> ClockSource for &'a ManualClock {
        type Time = u64;
        fn now(&mut self) -> Self::Time {
            self.0.get()
        }
    }

    #[test]
    fn fig_6_proc_0_a() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        src.0.set(10);
        assert_eq!(clock.on_send(), Timestamp(10, 0))
    }

    #[test]
    fn fig_6_proc_1_a() {
        let src = ManualClock(Cell::new(1));
        let mut clock = Clock::new(&src);
        assert_eq!(clock.on_recv(&Timestamp(10, 0)), Timestamp(10, 1))
    }

    #[test]
    fn fig_6_proc_1_b() {
        let src = ManualClock(Cell::new(1));
        let mut clock = Clock::new(&src);
        let _ = clock.on_recv(&Timestamp(10, 0));
        src.0.set(2);
        assert_eq!(clock.on_send(), Timestamp(10, 2))
    }

    #[test]
    fn fig_6_proc_2_b() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        clock.latest = Timestamp(1, 0);
        src.0.set(2);
        assert_eq!(clock.on_recv(&Timestamp(10, 2)), Timestamp(10, 3))
    }

    #[test]
    fn fig_6_proc_2_c() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        src.0.set(2);
        let _ = clock.on_recv(&Timestamp(10, 2));
        src.0.set(3);
        assert_eq!(clock.on_send(), Timestamp(10, 4))
    }

    #[test]
    fn all_sources_same() {
        let src = ManualClock(Cell::new(0));
        let mut clock = Clock::new(&src);
        assert_eq!(clock.on_recv(&Timestamp(0, 5)), Timestamp(0, 6))
    }

    #[test]
    fn handles_time_going_backwards_on_send() {
        let src = ManualClock(Cell::new(10));
        let mut clock = Clock::new(&src);
        let _ = clock.on_send();
        src.0.set(9);
        assert_eq!(clock.on_send(), Timestamp(10, 2))
    }

    #[test]
    fn handles_time_going_backwards_on_recv() {
        let src = ManualClock(Cell::new(10));
        let mut clock = Clock::new(&src);
        let _ = clock.on_send();
        src.0.set(9);
        assert_eq!(clock.on_recv(&Timestamp(0, 0)), Timestamp(10, 2))
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/hw/mapper_mbr.rs
/// Master Boot Record logical volume mapper
use prelude::*;
use lib::byteorder::{ReadBytesExt,LittleEndian};

module_define!{MapperMBR, [Storage], init}

static S_MAPPER: Mapper = Mapper;

fn init()
{
	::metadevs::storage::register_mapper(&S_MAPPER);
}

struct Mapper;

#[derive(Debug)]
struct Entry
{
	bootable: bool,
	system_id: u8,
	lba_start: u64,
	lba_count: u64,
}

impl ::metadevs::storage::Mapper for Mapper
{
	fn name(&self) -> &str { "mbr" }

	fn handles_pv(&self, pv: &::metadevs::storage::PhysicalVolume) -> usize {
		if pv.blocksize() != 512 {
			todo!("Support non 512 byte sectors in MBR mapper (got {})", pv.blocksize());
		}

		let mut block: [u8; 512] = unsafe { ::core::mem::zeroed() };
		pv.read(0, 0, 1, &mut block).unwrap().wait();

		log_debug!("PV '{}' boot sig {:02x} {:02x}", pv.name(), block[0x1FE], block[0x1FF]);
		if block[0x1FE] == 0x55 && block[0x1FE+1] == 0xAA {
			1
		}
		else {
			0
		}
	}

	fn enum_volumes(&self, pv: &::metadevs::storage::PhysicalVolume, new_volume_cb: &mut FnMut(String, u64, u64)) {
		assert!(pv.blocksize() == 512);

		let mut block: [u8; 512] = unsafe { ::core::mem::zeroed() };
		pv.read(0, 0, 1, &mut block).unwrap().wait();
		assert!(block[510] == 0x55 && block[511] == 0xAA);

		// the "unique ID" (according to the osdev.org wiki) might just be the tail of the MBR code
		//let uid = &block[0x1b4 .. 0x1be];

		for i in (0 .. 4) {
			let ofs = 0x1BE + i*16;

			if let Some(info) = Entry::read( &block[ofs .. ofs + 16] )
			{
				log_debug!("{:?}", info);
				if info.system_id == 0x5 || info.system_id == 0xF {
					todo!("Extended partition");
				}
				else {
					new_volume_cb( format!("{}p{}", pv.name(), i), info.lba_start, info.lba_count );
				}
			}
		}
	}
}

impl Entry
{
	fn read(data: &[u8]) -> Option<Entry>
	{
		assert!(data.len() >= 16);
		if data[4] == 0 {
			return None;
		}

		if data[0] & 0x7E != 0 {
			log_warning!("Partition entry has reserved bits set in byte 0 {:#x}", data[0]);
			return None;
		}

		let (base, len) = if data[0] & 1 != 0 {
				todo!("non-standard 48-bit LBA");
			}
			else {
				let base = (&data[8..]).read_u32::<LittleEndian>().unwrap() as u64;
				let len = (&data[12..]).read_u32::<LittleEndian>().unwrap() as u64;
				(base, len)
			};

		Some(Entry {
			bootable: (data[0] & 0x80) != 0,
			system_id: data[4],
			lba_start: base,
			lba_count: len,
			})
	}
}

<commit_msg>Core/MBR - Handle non-512 sectors better<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/hw/mapper_mbr.rs
/// Master Boot Record logical volume mapper
use prelude::*;
use lib::byteorder::{ReadBytesExt,LittleEndian};

module_define!{MapperMBR, [Storage], init}

static S_MAPPER: Mapper = Mapper;

fn init()
{
	::metadevs::storage::register_mapper(&S_MAPPER);
}

struct Mapper;

#[derive(Debug)]
struct Entry
{
	bootable: bool,
	system_id: u8,
	lba_start: u64,
	lba_count: u64,
}

impl ::metadevs::storage::Mapper for Mapper
{
	fn name(&self) -> &str { "mbr" }

	fn handles_pv(&self, pv: &::metadevs::storage::PhysicalVolume) -> usize {
		if pv.blocksize() != 512 {
			log_log!("Support non 512 byte sectors in MBR mapper (got {})", pv.blocksize());
			return 0;
		}

		let mut block: [u8; 512] = unsafe { ::core::mem::zeroed() };
		pv.read(0, 0, 1, &mut block).unwrap().wait();

		log_debug!("PV '{}' boot sig {:02x} {:02x}", pv.name(), block[0x1FE], block[0x1FF]);
		if block[0x1FE] == 0x55 && block[0x1FE+1] == 0xAA {
			1
		}
		else {
			0
		}
	}

	fn enum_volumes(&self, pv: &::metadevs::storage::PhysicalVolume, new_volume_cb: &mut FnMut(String, u64, u64)) {
		assert!(pv.blocksize() == 512);

		let mut block: [u8; 512] = unsafe { ::core::mem::zeroed() };
		pv.read(0, 0, 1, &mut block).unwrap().wait();
		assert!(block[510] == 0x55 && block[511] == 0xAA);

		// the "unique ID" (according to the osdev.org wiki) might just be the tail of the MBR code
		//let uid = &block[0x1b4 .. 0x1be];

		for i in (0 .. 4) {
			let ofs = 0x1BE + i*16;

			if let Some(info) = Entry::read( &block[ofs .. ofs + 16] )
			{
				log_debug!("{:?}", info);
				if info.system_id == 0x5 || info.system_id == 0xF {
					todo!("Extended partition");
				}
				else {
					new_volume_cb( format!("{}p{}", pv.name(), i), info.lba_start, info.lba_count );
				}
			}
		}
	}
}

impl Entry
{
	fn read(data: &[u8]) -> Option<Entry>
	{
		assert!(data.len() >= 16);
		if data[4] == 0 {
			return None;
		}

		if data[0] & 0x7E != 0 {
			log_warning!("Partition entry has reserved bits set in byte 0 {:#x}", data[0]);
			return None;
		}

		let (base, len) = if data[0] & 1 != 0 {
				todo!("non-standard 48-bit LBA");
			}
			else {
				let base = (&data[8..]).read_u32::<LittleEndian>().unwrap() as u64;
				let len = (&data[12..]).read_u32::<LittleEndian>().unwrap() as u64;
				(base, len)
			};

		Some(Entry {
			bootable: (data[0] & 0x80) != 0,
			system_id: data[4],
			lba_start: base,
			lba_count: len,
			})
	}
}

<|endoftext|>


<commit_before>use crate::source_map::SourceMap;
use crate::{BytePos, SourceFile};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;

#[derive(Clone)]
struct CacheEntry {
    time_stamp: usize,
    line_number: usize,
    // The line's byte position range in the `SourceMap`. This range will fail to contain a valid
    // position in certain edge cases. Spans often start/end one past something, and when that
    // something is the last character of a file (this can happen when a file doesn't end in a
    // newline, for example), we'd still like for the position to be considered within the last
    // line. However, it isn't according to the exclusive upper bound of this range. We cannot
    // change the upper bound to be inclusive, because for most lines, the upper bound is the same
    // as the lower bound of the next line, so there would be an ambiguity.
    //
    // Since the containment aspect of this range is only used to see whether or not the cache
    // entry contains a position, the only ramification of the above is that we will get cache
    // misses for these rare positions. A line lookup for the position via `SourceMap::lookup_line`
    // after a cache miss will produce the last line number, as desired.
    line: Range<BytePos>,
    file: Lrc<SourceFile>,
    file_index: usize,
}

#[derive(Clone)]
pub struct CachingSourceMapView<'sm> {
    source_map: &'sm SourceMap,
    line_cache: [CacheEntry; 3],
    time_stamp: usize,
}

impl<'sm> CachingSourceMapView<'sm> {
    pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
        let files = source_map.files();
        let first_file = files[0].clone();
        let entry = CacheEntry {
            time_stamp: 0,
            line_number: 0,
            line: BytePos(0)..BytePos(0),
            file: first_file,
            file_index: 0,
        };

        CachingSourceMapView {
            source_map,
            line_cache: [entry.clone(), entry.clone(), entry],
            time_stamp: 0,
        }
    }

    pub fn byte_pos_to_line_and_col(
        &mut self,
        pos: BytePos,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if the position is in one of the cached lines
        for cache_entry in self.line_cache.iter_mut() {
            if cache_entry.line.contains(&pos) {
                cache_entry.time_stamp = self.time_stamp;

                return Some((
                    cache_entry.file.clone(),
                    cache_entry.line_number,
                    pos - cache_entry.line.start,
                ));
            }
        }

        // No cache hit ...
        let mut oldest = 0;
        for index in 1..self.line_cache.len() {
            if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp {
                oldest = index;
            }
        }

        let cache_entry = &mut self.line_cache[oldest];

        // If the entry doesn't point to the correct file, fix it up
        if !file_contains(&cache_entry.file, pos) {
            let file_valid;
            if self.source_map.files().len() > 0 {
                let file_index = self.source_map.lookup_source_file_idx(pos);
                let file = &self.source_map.files()[file_index];

                if file_contains(&file, pos) {
                    cache_entry.file = file.clone();
                    cache_entry.file_index = file_index;
                    file_valid = true;
                } else {
                    file_valid = false;
                }
            } else {
                file_valid = false;
            }

            if !file_valid {
                return None;
            }
        }

        let line_index = cache_entry.file.lookup_line(pos).unwrap();
        let line_bounds = cache_entry.file.line_bounds(line_index);

        cache_entry.line_number = line_index + 1;
        cache_entry.line = line_bounds;
        cache_entry.time_stamp = self.time_stamp;

        Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
    }
}

#[inline]
fn file_contains(file: &SourceFile, pos: BytePos) -> bool {
    // `SourceMap::lookup_source_file_idx` and `SourceFile::contains` both consider the position
    // one past the end of a file to belong to it. Normally, that's what we want. But for the
    // purposes of converting a byte position to a line and column number, we can't come up with a
    // line and column number if the file is empty, because an empty file doesn't contain any
    // lines. So for our purposes, we don't consider empty files to contain any byte position.
    file.contains(pos) && !file.is_empty()
}
<commit_msg>rustc_span: refactor byte_pos_to_line_and_col<commit_after>use crate::source_map::SourceMap;
use crate::{BytePos, SourceFile};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;

#[derive(Clone)]
struct CacheEntry {
    time_stamp: usize,
    line_number: usize,
    // The line's byte position range in the `SourceMap`. This range will fail to contain a valid
    // position in certain edge cases. Spans often start/end one past something, and when that
    // something is the last character of a file (this can happen when a file doesn't end in a
    // newline, for example), we'd still like for the position to be considered within the last
    // line. However, it isn't according to the exclusive upper bound of this range. We cannot
    // change the upper bound to be inclusive, because for most lines, the upper bound is the same
    // as the lower bound of the next line, so there would be an ambiguity.
    //
    // Since the containment aspect of this range is only used to see whether or not the cache
    // entry contains a position, the only ramification of the above is that we will get cache
    // misses for these rare positions. A line lookup for the position via `SourceMap::lookup_line`
    // after a cache miss will produce the last line number, as desired.
    line: Range<BytePos>,
    file: Lrc<SourceFile>,
    file_index: usize,
}

#[derive(Clone)]
pub struct CachingSourceMapView<'sm> {
    source_map: &'sm SourceMap,
    line_cache: [CacheEntry; 3],
    time_stamp: usize,
}

impl<'sm> CachingSourceMapView<'sm> {
    pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
        let files = source_map.files();
        let first_file = files[0].clone();
        let entry = CacheEntry {
            time_stamp: 0,
            line_number: 0,
            line: BytePos(0)..BytePos(0),
            file: first_file,
            file_index: 0,
        };

        CachingSourceMapView {
            source_map,
            line_cache: [entry.clone(), entry.clone(), entry],
            time_stamp: 0,
        }
    }

    pub fn byte_pos_to_line_and_col(
        &mut self,
        pos: BytePos,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if the position is in one of the cached lines
        for cache_entry in self.line_cache.iter_mut() {
            if cache_entry.line.contains(&pos) {
                cache_entry.time_stamp = self.time_stamp;

                return Some((
                    cache_entry.file.clone(),
                    cache_entry.line_number,
                    pos - cache_entry.line.start,
                ));
            }
        }

        // No cache hit ...
        let oldest = self.oldest_cache_entry_index();

        // If the entry doesn't point to the correct file, fix it up
        if !file_contains(&self.line_cache[oldest].file, pos) {
            let (file, file_index) = self.file_for_position(pos)?;
            self.line_cache[oldest].file = file;
            self.line_cache[oldest].file_index = file_index;
        }

        let cache_entry = &mut self.line_cache[oldest];
        let line_index = cache_entry.file.lookup_line(pos).unwrap();
        let line_bounds = cache_entry.file.line_bounds(line_index);

        cache_entry.line_number = line_index + 1;
        cache_entry.line = line_bounds;
        cache_entry.time_stamp = self.time_stamp;

        Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
    }

    fn oldest_cache_entry_index(&self) -> usize {
        let mut oldest = 0;

        for idx in 1..self.line_cache.len() {
            if self.line_cache[idx].time_stamp < self.line_cache[oldest].time_stamp {
                oldest = idx;
            }
        }

        oldest
    }

    fn file_for_position(&self, pos: BytePos) -> Option<(Lrc<SourceFile>, usize)> {
        if !self.source_map.files().is_empty() {
            let file_idx = self.source_map.lookup_source_file_idx(pos);
            let file = &self.source_map.files()[file_idx];

            if file_contains(file, pos) {
                return Some((file.clone(), file_idx));
            }
        }

        None
    }
}

#[inline]
fn file_contains(file: &SourceFile, pos: BytePos) -> bool {
    // `SourceMap::lookup_source_file_idx` and `SourceFile::contains` both consider the position
    // one past the end of a file to belong to it. Normally, that's what we want. But for the
    // purposes of converting a byte position to a line and column number, we can't come up with a
    // line and column number if the file is empty, because an empty file doesn't contain any
    // lines. So for our purposes, we don't consider empty files to contain any byte position.
    file.contains(pos) && !file.is_empty()
}
<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate enum_map;

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if key == false {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}
<commit_msg>bool test can use !key instead of key == false<commit_after>#![no_std]

#[macro_use]
extern crate enum_map;

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}
<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate enum_map;

use enum_map::EnumMap;

#[derive(EnumMap)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map!{};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    enum_map! { _ => unreachable!() };
}
<commit_msg>Revert "Avoid assigning a value in an empty value test"<commit_after>#![no_std]

#[macro_use]
extern crate enum_map;

use enum_map::EnumMap;

#[derive(EnumMap)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map!{};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}
<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate enum_map;

use enum_map::EnumMap;

#[derive(EnumMap)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map!{};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}
<commit_msg>Avoid assigning a value in an empty value test<commit_after>#![no_std]

#[macro_use]
extern crate enum_map;

use enum_map::EnumMap;

#[derive(EnumMap)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map!{};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    enum_map! { _ => unreachable!() };
}
<|endoftext|>