<commit_before>use crate::{
    compiler::error::{CompilerError, CompilerErrorPayload},
    database::Database,
    input::{Input, InputDb},
};
use itertools::Itertools;
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Url};
use std::{ops::Range, sync::Arc};

impl CompilerError {
    pub fn to_diagnostic(self, db: &Database, input: Input) -> Diagnostic {
        Diagnostic {
            range: lsp_types::Range {
                start: db
                    .offset_to_lsp(input.clone(), self.span.start)
                    .to_position(),
                end: db.offset_to_lsp(input, self.span.end).to_position(),
            },
            severity: Some(DiagnosticSeverity::ERROR),
            code: None,
            code_description: None,
            source: Some("🍭 Candy".to_owned()),
            message: match self.payload {
                CompilerErrorPayload::InvalidUtf8 => format!("Invalid UTF8"),
                CompilerErrorPayload::Rcst(rcst) => format!("RCST: {rcst:?}"),
                CompilerErrorPayload::Ast(ast) => format!("AST: {ast:?}"),
                CompilerErrorPayload::Hir(hir) => format!("HIR: {hir:?}"),
            },
            related_information: None,
            tags: None,
            data: None,
        }
    }
}

impl From<Url> for Input {
    fn from(uri: Url) -> Self {
        match uri.scheme() {
            "file" => uri.to_file_path().unwrap().into(),
            "untitled" => Input::Untitled(uri.to_string()["untitled:".len()..].to_owned()),
            _ => panic!("Unsupported URI scheme: {}", uri.scheme()),
        }
    }
}

impl From<Input> for Url {
    fn from(input: Input) -> Url {
        match input {
            Input::File(_) | Input::ExternalFile(_) => {
                Url::from_file_path(input.to_path().unwrap()).unwrap()
            }
            Input::Untitled(id) => Url::parse(&format!("untitled:{id}")).unwrap(),
        }
    }
}

// UTF-8 Byte Offset ↔ LSP Position/Range

impl Database {
    pub fn range_to_lsp(&self, input: Input, range: Range<usize>) -> lsp_types::Range {
        lsp_types::Range {
            start: self.offset_to_lsp(input.clone(), range.start).to_position(),
            end: self.offset_to_lsp(input, range.end).to_position(),
        }
    }
}

#[salsa::query_group(LspPositionConversionStorage)]
pub trait LspPositionConversion: InputDb {
    // `lsp_types::Range` and `::Position` don't implement `Hash`, so they can't
    // be used as query keys directly.
    //
    // As its unlikely that a conversion is called multiple times with the same
    // key, we shouldn't loose much performance by not caching the individual
    // results.
    #[salsa::transparent]
    fn offset_from_lsp(&self, input: Input, line: u32, character: u32) -> usize;
    #[salsa::transparent]
    fn offset_to_lsp(&self, input: Input, position: usize) -> (u32, u32);

    fn line_start_utf8_byte_offsets(&self, input: Input) -> Arc<Vec<usize>>;
}

fn offset_from_lsp(
    db: &dyn LspPositionConversion,
    input: Input,
    line: u32,
    character: u32,
) -> usize {
    let text = db.get_string_input(input.clone()).unwrap();
    let line_start_offsets = db.line_start_utf8_byte_offsets(input);
    offset_from_lsp_raw(
        text.as_ref(),
        line_start_offsets.as_ref(),
        Position { line, character },
    )
}
pub fn offset_from_lsp_raw(text: &str, line_start_offsets: &[usize], position: Position) -> usize {
    let line_offset = line_start_offsets[position.line as usize];
    let line_length = if position.line as usize == line_start_offsets.len() - 1 {
        text.len() - line_offset
    } else {
        line_start_offsets[(position.line + 1) as usize] - line_offset
    };

    let line = &text[line_offset..line_offset + line_length];

    let words = line.encode_utf16().collect::<Vec<_>>();
    let char_offset = if position.character as usize >= words.len() {
        line_length
    } else {
        String::from_utf16(&words[0..position.character as usize])
            .unwrap()
            .len()
    };

    line_offset + char_offset
}

fn offset_to_lsp(db: &dyn LspPositionConversion, input: Input, offset: usize) -> (u32, u32) {
    let text = db.get_string_input(input.clone()).unwrap();
    let line_start_offsets = db.line_start_utf8_byte_offsets(input);

    let line = line_start_offsets
        .binary_search(&offset)
        .unwrap_or_else(|i| i - 1);

    let line_start = line_start_offsets[line];
    let character_utf16_offset = text[line_start..offset.to_owned()].encode_utf16().count();
    (line as u32, character_utf16_offset as u32)
}

pub trait TupleToPosition {
    fn to_position(&self) -> Position;
}
impl TupleToPosition for (u32, u32) {
    fn to_position(&self) -> Position {
        Position {
            line: self.0,
            character: self.1,
        }
    }
}

fn line_start_utf8_byte_offsets(db: &dyn LspPositionConversion, input: Input) -> Arc<Vec<usize>> {
    let text = db.get_string_input(input).unwrap();
    Arc::new(line_start_utf8_byte_offsets_raw(&text))
}
pub fn line_start_utf8_byte_offsets_raw(text: &str) -> Vec<usize> {
    let mut offsets = vec![0];
    offsets.append(
        &mut text
            .bytes()
            .enumerate()
            .filter(|(_, it)| it == &b'\n')
            .map(|(index, _)| index + 1)
            .collect(),
    );
    offsets
}

pub trait JoinWithCommasAndAnd {
    fn join_with_commas_and_and(self) -> String;
}
impl JoinWithCommasAndAnd for Vec<String> {
    fn join_with_commas_and_and(mut self) -> String {
        match &self[..] {
            [] => panic!("Joining no parts."),
            [part] => part.to_string(),
            [first, second] => format!("{first} and {second}"),
            _ => {
                let last = self.pop().unwrap();
                format!("{}, and {last}", self.into_iter().join(", "))
            }
        }
    }
}
<commit_msg>Clamp offsets after the last character to the end of the file<commit_after>use crate::{
    compiler::error::{CompilerError, CompilerErrorPayload},
    database::Database,
    input::{Input, InputDb},
};
use itertools::Itertools;
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Url};
use std::{ops::Range, sync::Arc};

impl CompilerError {
    pub fn to_diagnostic(self, db: &Database, input: Input) -> Diagnostic {
        Diagnostic {
            range: lsp_types::Range {
                start: db
                    .offset_to_lsp(input.clone(), self.span.start)
                    .to_position(),
                end: db.offset_to_lsp(input, self.span.end).to_position(),
            },
            severity: Some(DiagnosticSeverity::ERROR),
            code: None,
            code_description: None,
            source: Some("🍭 Candy".to_owned()),
            message: match self.payload {
                CompilerErrorPayload::InvalidUtf8 => format!("Invalid UTF8"),
                CompilerErrorPayload::Rcst(rcst) => format!("RCST: {rcst:?}"),
                CompilerErrorPayload::Ast(ast) => format!("AST: {ast:?}"),
                CompilerErrorPayload::Hir(hir) => format!("HIR: {hir:?}"),
            },
            related_information: None,
            tags: None,
            data: None,
        }
    }
}

impl From<Url> for Input {
    fn from(uri: Url) -> Self {
        match uri.scheme() {
            "file" => uri.to_file_path().unwrap().into(),
            "untitled" => Input::Untitled(uri.to_string()["untitled:".len()..].to_owned()),
            _ => panic!("Unsupported URI scheme: {}", uri.scheme()),
        }
    }
}

impl From<Input> for Url {
    fn from(input: Input) -> Url {
        match input {
            Input::File(_) | Input::ExternalFile(_) => {
                Url::from_file_path(input.to_path().unwrap()).unwrap()
            }
            Input::Untitled(id) => Url::parse(&format!("untitled:{id}")).unwrap(),
        }
    }
}

// UTF-8 Byte Offset ↔ LSP Position/Range

impl Database {
    pub fn range_to_lsp(&self, input: Input, range: Range<usize>) -> lsp_types::Range {
        lsp_types::Range {
            start: self.offset_to_lsp(input.clone(), range.start).to_position(),
            end: self.offset_to_lsp(input, range.end).to_position(),
        }
    }
}

#[salsa::query_group(LspPositionConversionStorage)]
pub trait LspPositionConversion: InputDb {
    // `lsp_types::Range` and `::Position` don't implement `Hash`, so they can't
    // be used as query keys directly.
    //
    // As its unlikely that a conversion is called multiple times with the same
    // key, we shouldn't loose much performance by not caching the individual
    // results.
    #[salsa::transparent]
    fn offset_from_lsp(&self, input: Input, line: u32, character: u32) -> usize;
    #[salsa::transparent]
    fn offset_to_lsp(&self, input: Input, position: usize) -> (u32, u32);

    fn line_start_utf8_byte_offsets(&self, input: Input) -> Arc<Vec<usize>>;
}

fn offset_from_lsp(
    db: &dyn LspPositionConversion,
    input: Input,
    line: u32,
    character: u32,
) -> usize {
    let text = db.get_string_input(input.clone()).unwrap();
    let line_start_offsets = db.line_start_utf8_byte_offsets(input);
    offset_from_lsp_raw(
        text.as_ref(),
        line_start_offsets.as_ref(),
        Position { line, character },
    )
}
pub fn offset_from_lsp_raw(text: &str, line_start_offsets: &[usize], position: Position) -> usize {
    let line_offset = line_start_offsets[position.line as usize];
    let line_length = if position.line as usize == line_start_offsets.len() - 1 {
        text.len() - line_offset
    } else {
        line_start_offsets[(position.line + 1) as usize] - line_offset
    };

    let line = &text[line_offset..line_offset + line_length];

    let words = line.encode_utf16().collect::<Vec<_>>();
    let char_offset = if position.character as usize >= words.len() {
        line_length
    } else {
        String::from_utf16(&words[0..position.character as usize])
            .unwrap()
            .len()
    };

    line_offset + char_offset
}

fn offset_to_lsp(db: &dyn LspPositionConversion, input: Input, mut offset: usize) -> (u32, u32) {
    let text = db.get_string_input(input.clone()).unwrap();
    if offset > text.len() {
        offset = text.len();
    }
    let line_start_offsets = db.line_start_utf8_byte_offsets(input);

    let line = line_start_offsets
        .binary_search(&offset)
        .unwrap_or_else(|i| i - 1);

    let line_start = line_start_offsets[line];
    let character_utf16_offset = text[line_start..offset.to_owned()].encode_utf16().count();
    (line as u32, character_utf16_offset as u32)
}

pub trait TupleToPosition {
    fn to_position(&self) -> Position;
}
impl TupleToPosition for (u32, u32) {
    fn to_position(&self) -> Position {
        Position {
            line: self.0,
            character: self.1,
        }
    }
}

fn line_start_utf8_byte_offsets(db: &dyn LspPositionConversion, input: Input) -> Arc<Vec<usize>> {
    let text = db.get_string_input(input).unwrap();
    Arc::new(line_start_utf8_byte_offsets_raw(&text))
}
pub fn line_start_utf8_byte_offsets_raw(text: &str) -> Vec<usize> {
    let mut offsets = vec![0];
    offsets.append(
        &mut text
            .bytes()
            .enumerate()
            .filter(|(_, it)| it == &b'\n')
            .map(|(index, _)| index + 1)
            .collect(),
    );
    offsets
}

pub trait JoinWithCommasAndAnd {
    fn join_with_commas_and_and(self) -> String;
}
impl JoinWithCommasAndAnd for Vec<String> {
    fn join_with_commas_and_and(mut self) -> String {
        match &self[..] {
            [] => panic!("Joining no parts."),
            [part] => part.to_string(),
            [first, second] => format!("{first} and {second}"),
            _ => {
                let last = self.pop().unwrap();
                format!("{}, and {last}", self.into_iter().join(", "))
            }
        }
    }
}
<|endoftext|>


<commit_before>use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::write_unchecked;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::LEVEL_PAGE_DIFF_MULTIPLIER;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

enum PruningSearch {
    DeepestInnode,
    Innode(NodeCellRef),
}

struct NodeRemoval<'a> {
    empty_pages: Vec<&'a EntryKey>,
    split: Vec<(NodeCellRef, EntryKey)>,
}

impl<'a> NodeRemoval<'a> {
    fn new() -> Self {
        Self {
            empty_pages: vec![],
            split: vec![],
        }
    }
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let mut collected = vec![write_node(node)];
            while collected.len() < LEVEL_PAGE_DIFF_MULTIPLIER {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn merge_innode_remnant<'a, KS, PS>(
    current_node: &mut NodeWriteGuard<KS, PS>,
    prev_key: &'a EntryKey,
    removal: &mut NodeRemoval<'a>,
) where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let curr_right_ref = current_node.right_ref_mut_no_empty().unwrap().clone();
    let curr_innode = current_node.innode_mut();
    let curr_right_bound = &curr_innode.right_bound;
    let curr_last_child = mem::replace(&mut curr_innode.ptrs.as_slice()[0], NodeCellRef::default());
    debug_assert_eq!(curr_innode.len, 0);
    removal.empty_pages.push(prev_key);
    if curr_last_child.is_default() {
        return;
    }
    let mut next_node = write_targeted(write_node::<KS, PS>(&curr_right_ref), curr_right_bound);
    let pos = next_node.search(curr_right_bound);
    let next_innode = next_node.innode_mut();
    next_innode.debug_check_integrity();
    if next_innode.len == KS::slice_len() {
        removal.split.push(next_innode.split_insert(
            curr_right_bound.clone(),
            curr_last_child,
            pos,
            false,
        ))
    } else {
        next_innode.insert_in_place(curr_right_bound.clone(), curr_last_child, pos, false);
    }
}

fn apply_removal<'a, KS, PS>(
    cursor_guard: &mut NodeWriteGuard<KS, PS>,
    poses: &mut BTreeSet<usize>,
    node_removal: &mut NodeRemoval<'a>,
    prev_key: &Option<&'a EntryKey>,
    remove_children_right_nodes: bool,
) where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if poses.is_empty() {
        return;
    }
    debug!(
        "Applying removal, guard key {:?}, poses {:?}",
        cursor_guard.first_key(),
        poses
    );
    {
        let innode = cursor_guard.innode_mut();
        let mut new_keys = KS::init();
        let mut new_ptrs = PS::init();
        {
            if remove_children_right_nodes {
                // A node will be reclaimed if and only if it have zero references
                // If there is any sequential empty nodes, they have to be unlinked each other
                // The upper level will do the rest to unlink it from the tree
                innode.ptrs.as_slice()[..innode.len + 1]
                    .iter()
                    .enumerate()
                    .filter(|(i, _)| poses.contains(i))
                    .for_each(|(_, r)| {
                        write_node::<KS, PS>(r).right_ref_mut_no_empty();
                    });
            }
            let ptrs: Vec<&mut _> = innode.ptrs.as_slice()[..innode.len + 1]
                .iter_mut()
                .enumerate()
                .filter(|(i, _)| !poses.contains(i))
                .map(|(_, p)| p)
                .collect();

            let keys: Vec<&mut _> = innode.keys.as_slice()[..innode.len]
                .iter_mut()
                .enumerate()
                .filter(|(i, _)| !poses.contains(i))
                .take(if ptrs.len() == 0 { 0 } else { ptrs.len() - 1 })
                .map(|(_, k)| k)
                .collect();
            innode.len = keys.len();
            debug!("Prune filtered page have keys {:?}", &keys);
            for (i, key) in keys.into_iter().enumerate() {
                debug_assert!(key > &mut smallvec!(0));
                mem::swap(&mut new_keys.as_slice()[i], key);
            }
            for (i, ptr) in ptrs.into_iter().enumerate() {
                debug_assert!(!ptr.is_default());
                mem::swap(&mut new_ptrs.as_slice()[i], ptr);
            }
        }
        innode.keys = new_keys;
        innode.ptrs = new_ptrs;
        innode.debug_check_integrity();

        debug!(
            "Pruned page have keys {:?}",
            &innode.keys.as_slice_immute()[..innode.len]
        );
    }

    if cursor_guard.is_empty() {
        if let &Some(k) = prev_key {
            debug_assert!(!cursor_guard.is_ext());
            merge_innode_remnant(cursor_guard, k, node_removal);
        }
        debug!("Pruned page is empty: {:?}", prev_key);
        cursor_guard.make_empty_node();
    }
    poses.clear();
}

fn prune_selected<'a, KS, PS>(
    node: &NodeCellRef,
    mut removal: Box<NodeRemoval<'a>>,
    level: usize,
) -> Box<NodeRemoval<'a>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, removal.empty_pages.first().unwrap());
    let pruning = match first_search {
        MutSearchResult::Internal(sub_node) => {
            if read_unchecked::<KS, PS>(&NodeData::<KS, PS>::get_non_empty_node(&sub_node)).is_ext()
            {
                PruningSearch::DeepestInnode
            } else {
                PruningSearch::Innode(sub_node)
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut deepest = false;
    match pruning {
        PruningSearch::DeepestInnode => {
            debug!(
                "Removing in deepest nodes keys {:?}, level {}",
                &removal.empty_pages, level
            );
            deepest = true;
        }
        PruningSearch::Innode(sub_node) => {
            removal = prune_selected::<KS, PS>(&sub_node, removal, level + 1);
        }
    }
    // empty page references that will dealt with by upper level
    let mut upper_removal = NodeRemoval::new();
    if !removal.empty_pages.is_empty() {
        debug!(
            "Pruning page containing keys {:?}, level {}",
            &removal.empty_pages, level
        );
        // start delete
        let mut cursor_guard = write_non_empty(write_node::<KS, PS>(node));
        let mut guard_removing_poses = BTreeSet::new();
        let mut prev_key = None;
        debug!(
            "Prune deepest node starting key: {:?}, level {}",
            cursor_guard.first_key(),
            level
        );
        // iterate over all removal empty nodes
        // in the beginning cursor_guard contains the first key
        // if the empty node go out of the right bound of current cursor guard,
        // it will `apply_removal` and switch to the next right page
        for (_i, &key_to_del) in removal.empty_pages.iter().enumerate() {
            if key_to_del >= cursor_guard.right_bound() {
                debug!(
                    "Applying removal for overflow current page ({}/{}) key: {:?} >= bound: {:?}. guard keys: {:?}, level {}",
                    guard_removing_poses.len(),
                    cursor_guard.len() + 1,
                    key_to_del,
                    cursor_guard.right_bound(),
                    &cursor_guard.keys()[..cursor_guard.len()],
                    level
                );
                apply_removal(
                    &mut cursor_guard,
                    &mut guard_removing_poses,
                    &mut upper_removal,
                    &prev_key,
                    !deepest,
                );
                cursor_guard = write_targeted(cursor_guard, key_to_del);
                debug_assert!(!cursor_guard.is_empty_node());
                debug!(
                    "Applied removal for overflow current page ({}), level {}",
                    cursor_guard.len(),
                    level
                );
            }
            let pos = cursor_guard.search(key_to_del);
            debug!(
                "Key to delete have position {}, key: {:?}, level {}",
                pos, key_to_del, level
            );
            guard_removing_poses.insert(pos);
            prev_key = Some(key_to_del)
        }
        if !guard_removing_poses.is_empty() {
            debug!(
                "Applying removal for last keys {:?}, level {}",
                &guard_removing_poses, level
            );
            apply_removal(
                &mut cursor_guard,
                &mut guard_removing_poses,
                &mut upper_removal,
                &prev_key,
                !deepest,
            );
        }
    }
    if !removal.split.is_empty() {
        let mut cursor_guard = write_node::<KS, PS>(node);
        for (node, pivot) in &removal.split {
            cursor_guard = write_targeted(cursor_guard, &pivot);
            let pos = cursor_guard.search(&pivot);
            let innode = cursor_guard.innode_mut();
            let pivot = pivot.clone();
            let node = node.clone();
            if innode.len >= KS::slice_len() {
                upper_removal
                    .split
                    .push(innode.split_insert(pivot, node, pos, true));
            } else {
                innode.insert_in_place(pivot, node, pos, true)
            }
        }
    }
    debug!(
        "Have empty nodes {:?}, level {:?}",
        &upper_removal.empty_pages, level
    );
    box upper_removal
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    debug!("Merge selected {} pages", left_most_leaf_guards.len());

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // cleanup upper level references
    {
        let page_keys = left_most_leaf_guards
            .iter()
            .filter(|g| !g.is_empty())
            .map(|g| g.first_key())
            .collect_vec();
        let mut removal = NodeRemoval::new();
        removal.empty_pages = page_keys;
        prune_selected::<KS, PS>(&src_tree.get_root(), box removal, 0);
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = {
            let left_most = left_most_leaf_guards.first().unwrap();
            if left_most.is_none() {
                left_most.node_ref().clone()
            } else {
                left_most.left_ref().unwrap().clone()
            }
        };

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());

        let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();
        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = left_most_id;
        new_first_node_ext.prev = left_left_most;

        debug_assert_eq!(new_first_node_ext.id, src_tree.head_page_id);

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<commit_msg>put verification for first page<commit_after>use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::write_unchecked;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::LEVEL_PAGE_DIFF_MULTIPLIER;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

enum PruningSearch {
    DeepestInnode,
    Innode(NodeCellRef),
}

struct NodeRemoval<'a> {
    empty_pages: Vec<&'a EntryKey>,
    split: Vec<(NodeCellRef, EntryKey)>,
}

impl<'a> NodeRemoval<'a> {
    fn new() -> Self {
        Self {
            empty_pages: vec![],
            split: vec![],
        }
    }
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let mut collected = vec![write_node(node)];
            while collected.len() < LEVEL_PAGE_DIFF_MULTIPLIER {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn merge_innode_remnant<'a, KS, PS>(
    current_node: &mut NodeWriteGuard<KS, PS>,
    prev_key: &'a EntryKey,
    removal: &mut NodeRemoval<'a>,
) where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let curr_right_ref = current_node.right_ref_mut_no_empty().unwrap().clone();
    let curr_innode = current_node.innode_mut();
    let curr_right_bound = &curr_innode.right_bound;
    let curr_last_child = mem::replace(&mut curr_innode.ptrs.as_slice()[0], NodeCellRef::default());
    debug_assert_eq!(curr_innode.len, 0);
    removal.empty_pages.push(prev_key);
    if curr_last_child.is_default() {
        return;
    }
    let mut next_node = write_targeted(write_node::<KS, PS>(&curr_right_ref), curr_right_bound);
    let pos = next_node.search(curr_right_bound);
    let next_innode = next_node.innode_mut();
    next_innode.debug_check_integrity();
    if next_innode.len == KS::slice_len() {
        removal.split.push(next_innode.split_insert(
            curr_right_bound.clone(),
            curr_last_child,
            pos,
            false,
        ))
    } else {
        next_innode.insert_in_place(curr_right_bound.clone(), curr_last_child, pos, false);
    }
}

fn apply_removal<'a, KS, PS>(
    cursor_guard: &mut NodeWriteGuard<KS, PS>,
    poses: &mut BTreeSet<usize>,
    node_removal: &mut NodeRemoval<'a>,
    prev_key: &Option<&'a EntryKey>,
    remove_children_right_nodes: bool,
) where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if poses.is_empty() {
        return;
    }
    debug!(
        "Applying removal, guard key {:?}, poses {:?}",
        cursor_guard.first_key(),
        poses
    );
    {
        let innode = cursor_guard.innode_mut();
        let mut new_keys = KS::init();
        let mut new_ptrs = PS::init();
        {
            if remove_children_right_nodes {
                // A node will be reclaimed if and only if it have zero references
                // If there is any sequential empty nodes, they have to be unlinked each other
                // The upper level will do the rest to unlink it from the tree
                innode.ptrs.as_slice()[..innode.len + 1]
                    .iter()
                    .enumerate()
                    .filter(|(i, _)| poses.contains(i))
                    .for_each(|(_, r)| {
                        write_node::<KS, PS>(r).right_ref_mut_no_empty();
                    });
            }
            let ptrs: Vec<&mut _> = innode.ptrs.as_slice()[..innode.len + 1]
                .iter_mut()
                .enumerate()
                .filter(|(i, _)| !poses.contains(i))
                .map(|(_, p)| p)
                .collect();

            let keys: Vec<&mut _> = innode.keys.as_slice()[..innode.len]
                .iter_mut()
                .enumerate()
                .filter(|(i, _)| !poses.contains(i))
                .take(if ptrs.len() == 0 { 0 } else { ptrs.len() - 1 })
                .map(|(_, k)| k)
                .collect();
            innode.len = keys.len();
            debug!("Prune filtered page have keys {:?}", &keys);
            for (i, key) in keys.into_iter().enumerate() {
                debug_assert!(key > &mut smallvec!(0));
                mem::swap(&mut new_keys.as_slice()[i], key);
            }
            for (i, ptr) in ptrs.into_iter().enumerate() {
                debug_assert!(!ptr.is_default());
                mem::swap(&mut new_ptrs.as_slice()[i], ptr);
            }
        }
        innode.keys = new_keys;
        innode.ptrs = new_ptrs;
        innode.debug_check_integrity();

        debug!(
            "Pruned page have keys {:?}",
            &innode.keys.as_slice_immute()[..innode.len]
        );
    }

    if cursor_guard.is_empty() {
        if let &Some(k) = prev_key {
            debug_assert!(!cursor_guard.is_ext());
            merge_innode_remnant(cursor_guard, k, node_removal);
        }
        debug!("Pruned page is empty: {:?}", prev_key);
        cursor_guard.make_empty_node();
    }
    poses.clear();
}

fn prune_selected<'a, KS, PS>(
    node: &NodeCellRef,
    mut removal: Box<NodeRemoval<'a>>,
    level: usize,
) -> Box<NodeRemoval<'a>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, removal.empty_pages.first().unwrap());
    let pruning = match first_search {
        MutSearchResult::Internal(sub_node) => {
            if read_unchecked::<KS, PS>(&NodeData::<KS, PS>::get_non_empty_node(&sub_node)).is_ext()
            {
                PruningSearch::DeepestInnode
            } else {
                PruningSearch::Innode(sub_node)
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut deepest = false;
    match pruning {
        PruningSearch::DeepestInnode => {
            debug!(
                "Removing in deepest nodes keys {:?}, level {}",
                &removal.empty_pages, level
            );
            deepest = true;
        }
        PruningSearch::Innode(sub_node) => {
            removal = prune_selected::<KS, PS>(&sub_node, removal, level + 1);
        }
    }
    // empty page references that will dealt with by upper level
    let mut upper_removal = NodeRemoval::new();
    if !removal.empty_pages.is_empty() {
        debug!(
            "Pruning page containing keys {:?}, level {}",
            &removal.empty_pages, level
        );
        // start delete
        let mut cursor_guard = write_non_empty(write_node::<KS, PS>(node));
        let mut guard_removing_poses = BTreeSet::new();
        let mut prev_key = None;
        debug!(
            "Prune deepest node starting key: {:?}, level {}",
            cursor_guard.first_key(),
            level
        );
        // iterate over all removal empty nodes
        // in the beginning cursor_guard contains the first key
        // if the empty node go out of the right bound of current cursor guard,
        // it will `apply_removal` and switch to the next right page
        for (_i, &key_to_del) in removal.empty_pages.iter().enumerate() {
            if key_to_del >= cursor_guard.right_bound() {
                debug!(
                    "Applying removal for overflow current page ({}/{}) key: {:?} >= bound: {:?}. guard keys: {:?}, level {}",
                    guard_removing_poses.len(),
                    cursor_guard.len() + 1,
                    key_to_del,
                    cursor_guard.right_bound(),
                    &cursor_guard.keys()[..cursor_guard.len()],
                    level
                );
                apply_removal(
                    &mut cursor_guard,
                    &mut guard_removing_poses,
                    &mut upper_removal,
                    &prev_key,
                    !deepest,
                );
                cursor_guard = write_targeted(cursor_guard, key_to_del);
                debug_assert!(!cursor_guard.is_empty_node());
                debug!(
                    "Applied removal for overflow current page ({}), level {}",
                    cursor_guard.len(),
                    level
                );
            }
            let pos = cursor_guard.search(key_to_del);
            debug!(
                "Key to delete have position {}, key: {:?}, level {}",
                pos, key_to_del, level
            );
            guard_removing_poses.insert(pos);
            prev_key = Some(key_to_del)
        }
        if !guard_removing_poses.is_empty() {
            debug!(
                "Applying removal for last keys {:?}, level {}",
                &guard_removing_poses, level
            );
            apply_removal(
                &mut cursor_guard,
                &mut guard_removing_poses,
                &mut upper_removal,
                &prev_key,
                !deepest,
            );
        }
    }
    if !removal.split.is_empty() {
        let mut cursor_guard = write_node::<KS, PS>(node);
        for (node, pivot) in &removal.split {
            cursor_guard = write_targeted(cursor_guard, &pivot);
            let pos = cursor_guard.search(&pivot);
            let innode = cursor_guard.innode_mut();
            let pivot = pivot.clone();
            let node = node.clone();
            if innode.len >= KS::slice_len() {
                upper_removal
                    .split
                    .push(innode.split_insert(pivot, node, pos, true));
            } else {
                innode.insert_in_place(pivot, node, pos, true)
            }
        }
    }
    debug!(
        "Have empty nodes {:?}, level {:?}",
        &upper_removal.empty_pages, level
    );
    box upper_removal
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();

    debug!("Merge selected {} pages", left_most_leaf_guards.len());
    debug_assert_eq!(left_most_id, src_tree.head_page_id, "{}", left_most_leaf_guards.first().unwrap().type_name());

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // cleanup upper level references
    {
        let page_keys = left_most_leaf_guards
            .iter()
            .filter(|g| !g.is_empty())
            .map(|g| g.first_key())
            .collect_vec();
        let mut removal = NodeRemoval::new();
        removal.empty_pages = page_keys;
        prune_selected::<KS, PS>(&src_tree.get_root(), box removal, 0);
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = left_most_leaf_guards.first().unwrap().left_ref().unwrap().clone();

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());

        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = left_most_id;
        new_first_node_ext.prev = left_left_most;

        debug_assert_eq!(new_first_node_ext.id, src_tree.head_page_id);

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<|endoftext|>


<commit_before>use super::Mode;
use super::KeyMap;
use super::Key;
use super::Command;
use super::KeyMapState;
use super::Direction;
use super::WordEdgeMatch;
use super::OverlayType;

use command;

/// NormalMode mimics Vi's Normal mode.
pub struct NormalMode {
    keymap: KeyMap<command::Command>,
    builder: command::Builder,
}

impl NormalMode {

    /// Create a new instance of NormalMode
    pub fn new() -> NormalMode {
        NormalMode {
            keymap: NormalMode::key_defaults(),
            builder: command::Builder::new(),
        }
    }

    /// Creates a KeyMap with default NormalMode key bindings
    fn key_defaults() -> KeyMap<command::Command> {
        let mut keymap = KeyMap::new();

        // movement
        // keymap.bind_key(Key::Char('W'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_key(Key::Char('B'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_key(Key::Char('w'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_key(Key::Char('b'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_key(Key::Char('G'), Command::MoveCursor(Direction::LastLine, 0));
        // keymap.bind_keys(&[Key::Char('g'), Key::Char('g')], Command::MoveCursor(Direction::FirstLine, 0));

        // editing
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('W')], Command::Delete(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('B')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('w')], Command::Delete(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('b')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_key(Key::Char('x'), Command::Delete(Direction::Right, 1));
        // keymap.bind_key(Key::Char('X'), Command::Delete(Direction::Left, 1));

        keymap.bind_key(Key::Char('u'), command::Command::undo());
        keymap.bind_key(Key::Ctrl('r'), command::Command::redo());

        keymap
    }

}

impl Mode for NormalMode {
    /// Given a key, pass it through the NormalMode KeyMap and return the associated Command, if any.
    fn handle_key_event(&mut self, key: Key) -> command::BuilderEvent {
        match self.builder.check_key(key) {
            command::BuilderEvent::Complete(cmd) => command::BuilderEvent::Complete(cmd),
            command::BuilderEvent::Incomplete => {
                if let KeyMapState::Match(c) = self.keymap.check_key(key) {
                    command::BuilderEvent::Complete(c)
                } else {
                    command::BuilderEvent::Incomplete
                }
            }
            command::BuilderEvent::Invalid => { command::BuilderEvent::Invalid }
        }
    }
}
<commit_msg>Updated comments<commit_after>use super::Mode;
use super::KeyMap;
use super::Key;
use super::Command;
use super::KeyMapState;
use super::Direction;
use super::WordEdgeMatch;
use super::OverlayType;

use command;

/// NormalMode mimics Vi's Normal mode.
pub struct NormalMode {
    keymap: KeyMap<command::Command>,
    builder: command::Builder,
}

impl NormalMode {

    /// Create a new instance of NormalMode
    pub fn new() -> NormalMode {
        NormalMode {
            keymap: NormalMode::key_defaults(),
            builder: command::Builder::new(),
        }
    }

    /// Creates a KeyMap with default NormalMode key bindings
    fn key_defaults() -> KeyMap<command::Command> {
        let mut keymap = KeyMap::new();

        // movement
        // keymap.bind_key(Key::Char('W'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_key(Key::Char('B'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_key(Key::Char('w'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_key(Key::Char('b'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_key(Key::Char('G'), Command::MoveCursor(Direction::LastLine, 0));
        // keymap.bind_keys(&[Key::Char('g'), Key::Char('g')], Command::MoveCursor(Direction::FirstLine, 0));

        // editing
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('W')], Command::Delete(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('B')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('w')], Command::Delete(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_keys(&[Key::Char('d'), Key::Char('b')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        // keymap.bind_key(Key::Char('x'), Command::Delete(Direction::Right, 1));
        // keymap.bind_key(Key::Char('X'), Command::Delete(Direction::Left, 1));

        keymap.bind_key(Key::Char('u'), command::Command::undo());
        keymap.bind_key(Key::Ctrl('r'), command::Command::redo());

        keymap
    }

}

impl Mode for NormalMode {
    fn handle_key_event(&mut self, key: Key) -> command::BuilderEvent {
        match self.builder.check_key(key) {
            // builder gives us a full command, return that
            command::BuilderEvent::Complete(cmd) => command::BuilderEvent::Complete(cmd),

            // no command from the builder, check the internal keymap
            command::BuilderEvent::Incomplete => {
                if let KeyMapState::Match(c) = self.keymap.check_key(key) {
                    command::BuilderEvent::Complete(c)
                } else {
                    command::BuilderEvent::Incomplete
                }
            }

            // invalid result from builder, return invalid
            command::BuilderEvent::Invalid => { command::BuilderEvent::Invalid }
        }
    }
}
<|endoftext|>


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

/// Implementation of Quartz (CoreGraphics) fonts.
use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::kCTFontDefaultOrientation;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use crate::font::{
    FontHandleMethods, FontMetrics, FontTableMethods, FontTableTag, FractionalPixel,
};
use crate::font::{GPOS, GSUB, KERN};
use crate::platform::font_template::FontTemplateData;
use crate::platform::macos::font_context::FontContextHandle;
use crate::text::glyph::GlyphId;
use servo_atoms::Atom;
use std::ops::Range;
use std::sync::Arc;
use std::{fmt, ptr};
use style::values::computed::font::{FontStretch, FontStyle, FontWeight};

const KERN_PAIR_LEN: usize = 6;

pub struct FontTable {
    data: CFData,
}

// assumes 72 points per inch, and 96 px per inch
fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

// assumes 72 points per inch, and 96 px per inch
fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

fn au_from_pt(pt: f64) -> Au {
    Au::from_f64_px(pt_to_px(pt))
}

impl FontTable {
    pub fn wrap(data: CFData) -> FontTable {
        FontTable { data: data }
    }
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        self.data.bytes()
    }
}

#[derive(Debug)]
pub struct FontHandle {
    font_data: Arc<FontTemplateData>,
    ctfont: CTFont,
    h_kern_subtable: Option<CachedKernTable>,
    can_do_fast_shaping: bool,
}

impl FontHandle {
    /// Cache all the data needed for basic horizontal kerning. This is used only as a fallback or
    /// fast path (when the GPOS table is missing or unnecessary) so it needn't handle every case.
    fn find_h_kern_subtable(&self) -> Option<CachedKernTable> {
        let font_table = self.table_for_tag(KERN)?;
        let mut result = CachedKernTable {
            font_table: font_table,
            pair_data_range: 0..0,
            px_per_font_unit: 0.0,
        };

        // Look for a subtable with horizontal kerning in format 0.
        // https://www.microsoft.com/typography/otspec/kern.htm
        const KERN_COVERAGE_HORIZONTAL_FORMAT_0: u16 = 1;
        const SUBTABLE_HEADER_LEN: usize = 6;
        const FORMAT_0_HEADER_LEN: usize = 8;
        {
            let table = result.font_table.buffer();
            let version = BigEndian::read_u16(table);
            if version != 0 {
                return None;
            }
            let num_subtables = BigEndian::read_u16(&table[2..]);
            let mut start = 4;
            for _ in 0..num_subtables {
                // TODO: Check the subtable version number?
                let len = BigEndian::read_u16(&table[start + 2..]) as usize;
                let cov = BigEndian::read_u16(&table[start + 4..]);
                let end = start + len;
                if cov == KERN_COVERAGE_HORIZONTAL_FORMAT_0 {
                    // Found a matching subtable.
                    if result.pair_data_range.len() > 0 {
                        debug!("Found multiple horizontal kern tables. Disable fast path.");
                        return None;
                    }
                    // Read the subtable header.
                    let subtable_start = start + SUBTABLE_HEADER_LEN;
                    let n_pairs = BigEndian::read_u16(&table[subtable_start..]) as usize;
                    let pair_data_start = subtable_start + FORMAT_0_HEADER_LEN;

                    result.pair_data_range = pair_data_start..end;
                    if result.pair_data_range.len() != n_pairs * KERN_PAIR_LEN {
                        debug!("Bad data in kern header. Disable fast path.");
                        return None;
                    }

                    let pt_per_font_unit =
                        self.ctfont.pt_size() as f64 / self.ctfont.units_per_em() as f64;
                    result.px_per_font_unit = pt_to_px(pt_per_font_unit);
                }
                start = end;
            }
        }
        if result.pair_data_range.len() > 0 {
            Some(result)
        } else {
            None
        }
    }
}

struct CachedKernTable {
    font_table: FontTable,
    pair_data_range: Range<usize>,
    px_per_font_unit: f64,
}

impl CachedKernTable {
    /// Search for a glyph pair in the kern table and return the corresponding value.
    fn binary_search(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> Option<i16> {
        let pairs = &self.font_table.buffer()[self.pair_data_range.clone()];

        let query = first_glyph << 16 | second_glyph;
        let (mut start, mut end) = (0, pairs.len() / KERN_PAIR_LEN);
        while start < end {
            let i = (start + end) / 2;
            let key = BigEndian::read_u32(&pairs[i * KERN_PAIR_LEN..]);
            if key > query {
                end = i;
            } else if key < query {
                start = i + 1;
            } else {
                return Some(BigEndian::read_i16(&pairs[i * KERN_PAIR_LEN + 4..]));
            }
        }
        None
    }
}

impl fmt::Debug for CachedKernTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "CachedKernTable")
    }
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(
        _fctx: &FontContextHandle,
        template: Arc<FontTemplateData>,
        pt_size: Option<Au>,
    ) -> Result<FontHandle, ()> {
        let size = match pt_size {
            Some(s) => s.to_f64_px(),
            None => 0.0,
        };
        match template.ctfont(size) {
            Some(ref ctfont) => {
                let mut handle = FontHandle {
                    font_data: template.clone(),
                    ctfont: ctfont.clone_with_font_size(size),
                    h_kern_subtable: None,
                    can_do_fast_shaping: false,
                };
                handle.h_kern_subtable = handle.find_h_kern_subtable();
                // TODO (#11310): Implement basic support for GPOS and GSUB.
                handle.can_do_fast_shaping = handle.h_kern_subtable.is_some() &&
                    handle.table_for_tag(GPOS).is_none() &&
                    handle.table_for_tag(GSUB).is_none();
                Ok(handle)
            },
            None => Err(()),
        }
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> Option<String> {
        Some(self.ctfont.family_name())
    }

    fn face_name(&self) -> Option<String> {
        Some(self.ctfont.face_name())
    }

    fn style(&self) -> FontStyle {
        use style::values::generics::font::FontStyle::*;
        if self.ctfont.symbolic_traits().is_italic() {
            Italic
        } else {
            Normal
        }
    }

    fn boldness(&self) -> FontWeight {
        let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0]

        // TODO(emilio): It may make sense to make this range [.01, 10.0], to
        // align with css-fonts-4's range of [1, 1000].
        let normalized = if normalized <= 0.0 {
            4.0 + normalized * 3.0 // [1.0, 4.0]
        } else {
            4.0 + normalized * 5.0 // [4.0, 9.0]
        }; // [1.0, 9.0], centered on 4.0
        FontWeight(normalized as f32 * 100.)
    }

    fn stretchiness(&self) -> FontStretch {
        use style::values::computed::Percentage;
        use style::values::generics::NonNegative;

        let normalized = self.ctfont.all_traits().normalized_width(); // [-1.0, 1.0]
        FontStretch(NonNegative(Percentage(normalized as f32 + 1.0)))
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let characters: [UniChar; 1] = [codepoint as UniChar];
        let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
        let count: CFIndex = 1;

        let result = unsafe {
            self.ctfont
                .get_glyphs_for_characters(&characters[0], &mut glyphs[0], count)
        };

        if !result {
            // No glyph for this character
            return None;
        }

        assert_ne!(glyphs[0], 0); // FIXME: error handling
        return Some(glyphs[0] as GlyphId);
    }

    fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
        if let Some(ref table) = self.h_kern_subtable {
            if let Some(font_units) = table.binary_search(first_glyph, second_glyph) {
                return font_units as f64 * table.px_per_font_unit;
            }
        }
        0.0
    }

    fn can_do_fast_shaping(&self) -> bool {
        self.can_do_fast_shaping
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        let glyphs = [glyph as CGGlyph];
        let advance = unsafe {
            self.ctfont.get_advances_for_glyphs(
                kCTFontDefaultOrientation,
                &glyphs[0],
                ptr::null_mut(),
                1,
            )
        };
        Some(advance as FractionalPixel)
    }

    fn metrics(&self) -> FontMetrics {
        let bounding_rect: CGRect = self.ctfont.bounding_box();
        let ascent = self.ctfont.ascent() as f64;
        let descent = self.ctfont.descent() as f64;
        let em_size = Au::from_f64_px(self.ctfont.pt_size() as f64);
        let leading = self.ctfont.leading() as f64;

        let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
        let line_gap = (ascent + descent + leading + 0.5).floor();

        let max_advance_width = au_from_pt(bounding_rect.size.width as f64);
        let average_advance = self
            .glyph_index('0')
            .and_then(|idx| self.glyph_h_advance(idx))
            .map(Au::from_f64_px)
            .unwrap_or(max_advance_width);

        let metrics = FontMetrics {
            underline_size: au_from_pt(self.ctfont.underline_thickness() as f64),
            // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
            // directly.
            //
            // see also: https://bugs.webkit.org/show_bug.cgi?id=16768
            // see also: https://bugreports.qt-project.org/browse/QTBUG-13364
            underline_offset: au_from_pt(self.ctfont.underline_position() as f64),
            strikeout_size: Au(0),   // FIXME(Issue #942)
            strikeout_offset: Au(0), // FIXME(Issue #942)
            leading: au_from_pt(leading),
            x_height: au_from_pt((self.ctfont.x_height() as f64) * scale),
            em_size: em_size,
            ascent: au_from_pt(ascent * scale),
            descent: au_from_pt(descent * scale),
            max_advance: max_advance_width,
            average_advance: average_advance,
            line_gap: Au::from_f64_px(line_gap),
        };
        debug!(
            "Font metrics (@{} pt): {:?}",
            self.ctfont.pt_size() as f64,
            metrics
        );
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let result: Option<CFData> = self.ctfont.get_font_table(tag);
        result.and_then(|data| Some(FontTable::wrap(data)))
    }

    fn identifier(&self) -> Atom {
        self.font_data.identifier.clone()
    }
}
<commit_msg>mac: Treat CT returning 0 glyph indexes as failing to find indexes.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

/// Implementation of Quartz (CoreGraphics) fonts.
use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::kCTFontDefaultOrientation;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use crate::font::{
    FontHandleMethods, FontMetrics, FontTableMethods, FontTableTag, FractionalPixel,
};
use crate::font::{GPOS, GSUB, KERN};
use crate::platform::font_template::FontTemplateData;
use crate::platform::macos::font_context::FontContextHandle;
use crate::text::glyph::GlyphId;
use servo_atoms::Atom;
use std::ops::Range;
use std::sync::Arc;
use std::{fmt, ptr};
use style::values::computed::font::{FontStretch, FontStyle, FontWeight};

const KERN_PAIR_LEN: usize = 6;

pub struct FontTable {
    data: CFData,
}

// assumes 72 points per inch, and 96 px per inch
fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

// assumes 72 points per inch, and 96 px per inch
fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

fn au_from_pt(pt: f64) -> Au {
    Au::from_f64_px(pt_to_px(pt))
}

impl FontTable {
    pub fn wrap(data: CFData) -> FontTable {
        FontTable { data: data }
    }
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        self.data.bytes()
    }
}

#[derive(Debug)]
pub struct FontHandle {
    font_data: Arc<FontTemplateData>,
    ctfont: CTFont,
    h_kern_subtable: Option<CachedKernTable>,
    can_do_fast_shaping: bool,
}

impl FontHandle {
    /// Cache all the data needed for basic horizontal kerning. This is used only as a fallback or
    /// fast path (when the GPOS table is missing or unnecessary) so it needn't handle every case.
    fn find_h_kern_subtable(&self) -> Option<CachedKernTable> {
        let font_table = self.table_for_tag(KERN)?;
        let mut result = CachedKernTable {
            font_table: font_table,
            pair_data_range: 0..0,
            px_per_font_unit: 0.0,
        };

        // Look for a subtable with horizontal kerning in format 0.
        // https://www.microsoft.com/typography/otspec/kern.htm
        const KERN_COVERAGE_HORIZONTAL_FORMAT_0: u16 = 1;
        const SUBTABLE_HEADER_LEN: usize = 6;
        const FORMAT_0_HEADER_LEN: usize = 8;
        {
            let table = result.font_table.buffer();
            let version = BigEndian::read_u16(table);
            if version != 0 {
                return None;
            }
            let num_subtables = BigEndian::read_u16(&table[2..]);
            let mut start = 4;
            for _ in 0..num_subtables {
                // TODO: Check the subtable version number?
                let len = BigEndian::read_u16(&table[start + 2..]) as usize;
                let cov = BigEndian::read_u16(&table[start + 4..]);
                let end = start + len;
                if cov == KERN_COVERAGE_HORIZONTAL_FORMAT_0 {
                    // Found a matching subtable.
                    if result.pair_data_range.len() > 0 {
                        debug!("Found multiple horizontal kern tables. Disable fast path.");
                        return None;
                    }
                    // Read the subtable header.
                    let subtable_start = start + SUBTABLE_HEADER_LEN;
                    let n_pairs = BigEndian::read_u16(&table[subtable_start..]) as usize;
                    let pair_data_start = subtable_start + FORMAT_0_HEADER_LEN;

                    result.pair_data_range = pair_data_start..end;
                    if result.pair_data_range.len() != n_pairs * KERN_PAIR_LEN {
                        debug!("Bad data in kern header. Disable fast path.");
                        return None;
                    }

                    let pt_per_font_unit =
                        self.ctfont.pt_size() as f64 / self.ctfont.units_per_em() as f64;
                    result.px_per_font_unit = pt_to_px(pt_per_font_unit);
                }
                start = end;
            }
        }
        if result.pair_data_range.len() > 0 {
            Some(result)
        } else {
            None
        }
    }
}

struct CachedKernTable {
    font_table: FontTable,
    pair_data_range: Range<usize>,
    px_per_font_unit: f64,
}

impl CachedKernTable {
    /// Search for a glyph pair in the kern table and return the corresponding value.
    fn binary_search(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> Option<i16> {
        let pairs = &self.font_table.buffer()[self.pair_data_range.clone()];

        let query = first_glyph << 16 | second_glyph;
        let (mut start, mut end) = (0, pairs.len() / KERN_PAIR_LEN);
        while start < end {
            let i = (start + end) / 2;
            let key = BigEndian::read_u32(&pairs[i * KERN_PAIR_LEN..]);
            if key > query {
                end = i;
            } else if key < query {
                start = i + 1;
            } else {
                return Some(BigEndian::read_i16(&pairs[i * KERN_PAIR_LEN + 4..]));
            }
        }
        None
    }
}

impl fmt::Debug for CachedKernTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "CachedKernTable")
    }
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(
        _fctx: &FontContextHandle,
        template: Arc<FontTemplateData>,
        pt_size: Option<Au>,
    ) -> Result<FontHandle, ()> {
        let size = match pt_size {
            Some(s) => s.to_f64_px(),
            None => 0.0,
        };
        match template.ctfont(size) {
            Some(ref ctfont) => {
                let mut handle = FontHandle {
                    font_data: template.clone(),
                    ctfont: ctfont.clone_with_font_size(size),
                    h_kern_subtable: None,
                    can_do_fast_shaping: false,
                };
                handle.h_kern_subtable = handle.find_h_kern_subtable();
                // TODO (#11310): Implement basic support for GPOS and GSUB.
                handle.can_do_fast_shaping = handle.h_kern_subtable.is_some() &&
                    handle.table_for_tag(GPOS).is_none() &&
                    handle.table_for_tag(GSUB).is_none();
                Ok(handle)
            },
            None => Err(()),
        }
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> Option<String> {
        Some(self.ctfont.family_name())
    }

    fn face_name(&self) -> Option<String> {
        Some(self.ctfont.face_name())
    }

    fn style(&self) -> FontStyle {
        use style::values::generics::font::FontStyle::*;
        if self.ctfont.symbolic_traits().is_italic() {
            Italic
        } else {
            Normal
        }
    }

    fn boldness(&self) -> FontWeight {
        let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0]

        // TODO(emilio): It may make sense to make this range [.01, 10.0], to
        // align with css-fonts-4's range of [1, 1000].
        let normalized = if normalized <= 0.0 {
            4.0 + normalized * 3.0 // [1.0, 4.0]
        } else {
            4.0 + normalized * 5.0 // [4.0, 9.0]
        }; // [1.0, 9.0], centered on 4.0
        FontWeight(normalized as f32 * 100.)
    }

    fn stretchiness(&self) -> FontStretch {
        use style::values::computed::Percentage;
        use style::values::generics::NonNegative;

        let normalized = self.ctfont.all_traits().normalized_width(); // [-1.0, 1.0]
        FontStretch(NonNegative(Percentage(normalized as f32 + 1.0)))
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let characters: [UniChar; 1] = [codepoint as UniChar];
        let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
        let count: CFIndex = 1;

        let result = unsafe {
            self.ctfont
                .get_glyphs_for_characters(characters.as_ptr(), glyphs.as_mut_ptr(), count)
        };

        if !result || glyphs[0] == 0 {
            // No glyph for this character
            return None;
        }

        return Some(glyphs[0] as GlyphId);
    }

    fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
        if let Some(ref table) = self.h_kern_subtable {
            if let Some(font_units) = table.binary_search(first_glyph, second_glyph) {
                return font_units as f64 * table.px_per_font_unit;
            }
        }
        0.0
    }

    fn can_do_fast_shaping(&self) -> bool {
        self.can_do_fast_shaping
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        let glyphs = [glyph as CGGlyph];
        let advance = unsafe {
            self.ctfont.get_advances_for_glyphs(
                kCTFontDefaultOrientation,
                &glyphs[0],
                ptr::null_mut(),
                1,
            )
        };
        Some(advance as FractionalPixel)
    }

    fn metrics(&self) -> FontMetrics {
        let bounding_rect: CGRect = self.ctfont.bounding_box();
        let ascent = self.ctfont.ascent() as f64;
        let descent = self.ctfont.descent() as f64;
        let em_size = Au::from_f64_px(self.ctfont.pt_size() as f64);
        let leading = self.ctfont.leading() as f64;

        let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
        let line_gap = (ascent + descent + leading + 0.5).floor();

        let max_advance_width = au_from_pt(bounding_rect.size.width as f64);
        let average_advance = self
            .glyph_index('0')
            .and_then(|idx| self.glyph_h_advance(idx))
            .map(Au::from_f64_px)
            .unwrap_or(max_advance_width);

        let metrics = FontMetrics {
            underline_size: au_from_pt(self.ctfont.underline_thickness() as f64),
            // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
            // directly.
            //
            // see also: https://bugs.webkit.org/show_bug.cgi?id=16768
            // see also: https://bugreports.qt-project.org/browse/QTBUG-13364
            underline_offset: au_from_pt(self.ctfont.underline_position() as f64),
            strikeout_size: Au(0),   // FIXME(Issue #942)
            strikeout_offset: Au(0), // FIXME(Issue #942)
            leading: au_from_pt(leading),
            x_height: au_from_pt((self.ctfont.x_height() as f64) * scale),
            em_size: em_size,
            ascent: au_from_pt(ascent * scale),
            descent: au_from_pt(descent * scale),
            max_advance: max_advance_width,
            average_advance: average_advance,
            line_gap: Au::from_f64_px(line_gap),
        };
        debug!(
            "Font metrics (@{} pt): {:?}",
            self.ctfont.pt_size() as f64,
            metrics
        );
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let result: Option<CFData> = self.ctfont.get_font_table(tag);
        result.and_then(|data| Some(FontTable::wrap(data)))
    }

    fn identifier(&self) -> Atom {
        self.font_data.identifier.clone()
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// 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.

pub use std::string::String;
pub use rust::{Ident, Name, Span, str_lit};
use rust;
use std::ops::Deref;

pub fn ident_to_string(ident: Ident) -> String {
  ident.to_string()
}

pub fn string_to_ident(cx: &rust::ExtCtxt, name: String) -> Ident {
  cx.ident_of(name.as_str())
}

pub fn cook_lit(name: Name) -> String {
  str_lit(name.to_string().as_str())
}

pub trait ItemIdent
{
  fn ident(&self) -> Ident;
}

pub trait ItemSpan
{
  fn span(&self) -> Span;
}

impl ItemIdent for rust::Item
{
  fn ident(&self) -> Ident {
    self.ident.clone()
  }
}

impl ItemSpan for rust::Item
{
  fn span(&self) -> Span {
    self.span.clone()
  }
}

impl<InnerItem: ItemIdent> ItemIdent for rust::P<InnerItem>
{
  fn ident(&self) -> Ident {
    self.deref().ident()
  }
}

impl<InnerItem: ItemSpan> ItemSpan for rust::P<InnerItem>
{
  fn span(&self) -> Span {
    self.deref().span()
  }
}
<commit_msg>Update str_lit invocation<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// 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.

pub use std::string::String;
pub use rust::{Ident, Name, Span, str_lit};
use rust;
use std::ops::Deref;

pub fn ident_to_string(ident: Ident) -> String {
  ident.to_string()
}

pub fn string_to_ident(cx: &rust::ExtCtxt, name: String) -> Ident {
  cx.ident_of(name.as_str())
}

pub fn cook_lit(name: Name) -> String {
  str_lit(name.to_string().as_str(), None)
}

pub trait ItemIdent
{
  fn ident(&self) -> Ident;
}

pub trait ItemSpan
{
  fn span(&self) -> Span;
}

impl ItemIdent for rust::Item
{
  fn ident(&self) -> Ident {
    self.ident.clone()
  }
}

impl ItemSpan for rust::Item
{
  fn span(&self) -> Span {
    self.span.clone()
  }
}

impl<InnerItem: ItemIdent> ItemIdent for rust::P<InnerItem>
{
  fn ident(&self) -> Ident {
    self.deref().ident()
  }
}

impl<InnerItem: ItemSpan> ItemSpan for rust::P<InnerItem>
{
  fn span(&self) -> Span {
    self.deref().span()
  }
}
<|endoftext|>


<commit_before>#![feature(proc_macro, proc_macro_lib)] #![feature(trace_macros)]
#![recursion_limit = "256"]
// trace_macros!(true);

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate asn1_cereal;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate post_expansion;

use proc_macro::TokenStream;

use ::tag::parse_tag;
use ::alias::{ber_alias_serialize, ber_alias_deserialize};
use ::seq_of::{ber_sequence_of_serialize, ber_sequence_of_deserialize};
use ::choice::{ber_choice_serialize, ber_choice_deserialize};

register_post_expansion!(PostExpansion_asn1);

mod tag;
mod seq;
mod seq_of;
mod alias;
mod choice;

#[proc_macro_derive(Asn1Info)]
pub fn asn1_info(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  // Tag and asn1 type for this rust type.
  let mut tag = quote!(None);
  let mut asn1_type = ast.ident.as_ref().to_owned();
  let mut _logging = false;

  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() != "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => _logging = true,
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "tag" => tag = parse_tag(value.as_bytes()).unwrap().1,
              "asn1_type" => asn1_type = value.clone(),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  // Used in the quasi-quotation below as `#name`
  let name = &ast.ident;

  // Helper is provided for handling complex generic types correctly and effortlessly
  let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

  let derived = quote! {
    impl #impl_generics ::asn1_cereal::Asn1Info for #name #ty_generics #where_clause {
      fn asn1_tag() -> Option<::asn1_cereal::tag::Tag> {
        #tag
      }

      fn asn1_type() -> ::asn1_cereal::tag::Type {
        #asn1_type.to_owned()
      }
    }
  };

  let stripped = post_expansion::strip_attrs_later(ast.clone(), &["asn1"], "asn1");
  let expanded = quote!(
    #stripped
    #derived
  );
  expanded.to_string().parse().expect("Failure parsing derived impl")
}

fn logging_enabled(ast: &syn::MacroInput) -> bool {
  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => return true,
          _ => (),
        };
      }
    }
  }
  false
}

#[proc_macro_derive(BerSerialize)]
pub fn ber_serialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).unwrap();

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_serialize(&ast),
      "alias" => ber_alias_serialize(&ast),
      "choice" => ber_choice_serialize(&ast),
      _ => panic!("Unknown serialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_deserialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_serialize(&ast)
        } else {
          unimplemented!()
        }
      },
      _ => unimplemented!(),
    }
  };

  let stripped = post_expansion::strip_attrs_later(ast, &["asn1"], "asn1");
  let expanded = quote!(
    #stripped
    #derived
  );
  expanded.to_string().parse().expect("Failure parsing derived impl")
}

#[proc_macro_derive(BerDeserialize)]
pub fn ber_deserialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_deserialize(&ast),
      "alias" => ber_alias_deserialize(&ast),
      "choice" => ber_choice_deserialize(&ast),
      _ => panic!("Unknown deserialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_serialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_deserialize(&ast)
        } else {
          unimplemented!()
        }
      },
      _ => unimplemented!(),
    }
  };

  let stripped = post_expansion::strip_attrs_later(ast, &["asn1"], "asn1");
  let expanded = quote!(
    #stripped
    #derived
  );
  expanded.to_string().parse().expect("Failure parsing derived impl")
}
<commit_msg>Fix Asn1Info derive<commit_after>#![feature(proc_macro, proc_macro_lib)] #![feature(trace_macros)]
#![recursion_limit = "256"]
// trace_macros!(true);

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate asn1_cereal;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate post_expansion;

use proc_macro::TokenStream;

use ::tag::parse_tag;
use ::alias::{ber_alias_serialize, ber_alias_deserialize};
use ::seq_of::{ber_sequence_of_serialize, ber_sequence_of_deserialize};
use ::choice::{ber_choice_serialize, ber_choice_deserialize};

register_post_expansion!(PostExpansion_asn1);

mod tag;
mod seq;
mod seq_of;
mod alias;
mod choice;

#[proc_macro_derive(Asn1Info)]
pub fn asn1_info(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  // Tag and asn1 type for this rust type.
  let mut tag = quote!(None);
  let mut asn1_type = ast.ident.as_ref().to_owned();
  let mut _logging = false;

  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => _logging = true,
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "tag" => tag = parse_tag(value.as_bytes()).unwrap().1,
              "asn1_type" => asn1_type = value.clone(),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  // Used in the quasi-quotation below as `#name`
  let name = &ast.ident;

  // Helper is provided for handling complex generic types correctly and effortlessly
  let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

  let derived = quote! {
    impl #impl_generics ::asn1_cereal::Asn1Info for #name #ty_generics #where_clause {
      fn asn1_tag() -> Option<::asn1_cereal::tag::Tag> {
        #tag
      }

      fn asn1_type() -> ::asn1_cereal::tag::Type {
        #asn1_type.to_owned()
      }
    }
  };

  let stripped = post_expansion::strip_attrs_later(ast.clone(), &["asn1"], "asn1");
  let expanded = quote!(
    #stripped
    #derived
  );
  expanded.to_string().parse().expect("Failure parsing derived impl")
}

fn logging_enabled(ast: &syn::MacroInput) -> bool {
  // Parse attributes.
  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::Word(ref _ident) if _ident == "log" => return true,
          _ => (),
        };
      }
    }
  }
  false
}

#[proc_macro_derive(BerSerialize)]
pub fn ber_serialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).unwrap();

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_serialize(&ast),
      "alias" => ber_alias_serialize(&ast),
      "choice" => ber_choice_serialize(&ast),
      _ => panic!("Unknown serialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_deserialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_serialize(&ast)
        } else {
          unimplemented!()
        }
      },
      _ => unimplemented!(),
    }
  };

  let stripped = post_expansion::strip_attrs_later(ast, &["asn1"], "asn1");
  let expanded = quote!(
    #stripped
    #derived
  );
  expanded.to_string().parse().expect("Failure parsing derived impl")
}

#[proc_macro_derive(BerDeserialize)]
pub fn ber_deserialize(input: TokenStream) -> TokenStream {
  let source = input.to_string();
  let ast = syn::parse_macro_input(&source).expect("Couldn't parse input TokenSteam into AST");

  let body = ast.body.clone();
  let mut form = None;

  for attr in &ast.attrs.iter().find(|e| e.name() == "asn1") {
    if let syn::MetaItem::List(_, ref items) = attr.value {
      for item in items {
        match *item {
          syn::MetaItem::NameValue(ref _name, syn::Lit::Str(ref value, _)) => {
            let name: &str = _name.as_ref();
            match name {
              "form" => form = Some(value.clone()),
              _ => (),
            };
          },
          _ => (),
        };
      }
    }
  }

  let derived = if let Some(form) = form {
    match form.as_str() {
      "seq of" | "sequence of" | "set of" => ber_sequence_of_deserialize(&ast),
      "alias" => ber_alias_deserialize(&ast),
      "choice" => ber_choice_deserialize(&ast),
      _ => panic!("Unknown deserialize form {}", form),
    }
  } else {
    match body {
      syn::Body::Enum(_) => {
        ber_choice_serialize(&ast)
      },
      syn::Body::Struct(syn::VariantData::Tuple(fields)) => {
        if fields.len() == 1 {
          ber_alias_deserialize(&ast)
        } else {
          unimplemented!()
        }
      },
      _ => unimplemented!(),
    }
  };

  let stripped = post_expansion::strip_attrs_later(ast, &["asn1"], "asn1");
  let expanded = quote!(
    #stripped
    #derived
  );
  expanded.to_string().parse().expect("Failure parsing derived impl")
}
<|endoftext|>


<commit_before>use std::net::TcpStream;
use std::sync::mpsc;

use metrics::MetricsRecorder;
use metrics::Timer;
use options::MemcacheOptions;
use protocol::cmd::Resp;
use tcp_transport::TcpTransport;

use super::CmdSender;
use super::MetricsSender;
use super::RespReceiver;
use super::RespSender;
use super::TransportId;

pub struct TransportTask {
    id: TransportId,
    cmd_tx: CmdSender,
    met_tx: MetricsSender,
    options: MemcacheOptions,
}

impl TransportTask {
    pub fn new(id: TransportId,
               cmd_tx: CmdSender,
               met_tx: MetricsSender,
               options: MemcacheOptions)
               -> TransportTask {
        TransportTask {
            id: id,
            cmd_tx: cmd_tx,
            met_tx: met_tx,
            options: options,
        }
    }

    pub fn run(&self, stream: TcpStream) {
        let mut rec = MetricsRecorder::new(self.met_tx.clone(),
                                           self.options.get_metrics_enabled());

        let mut transport = TcpTransport::new(stream);
        let (resp_tx, resp_rx): (RespSender, RespReceiver) = mpsc::channel();

        loop {
            // Time the whole loop
            rec.start_timer("TransportTask:loop");

            // println!("Ready to read command...");
            let rv = {
                let _t = Timer::new(&mut rec, "TransportTask:read_cmd");
                transport.read_cmd()
            };

            // If we couldn't parse the command return an error
            if !rv.is_ok() {
                println!("Failed to read command, returning error");
                let _ = transport.write_resp(&Resp::Error);
                return; // Here we just drop the connection
            }

            // Send the command to the driver
            let cmd = rv.unwrap();
            let resp_tx_clone = resp_tx.clone();
            let stats = transport.get_stats_clone();
            {
                let _t = Timer::new(&mut rec, "TransportTask:send_cmd");
                self.cmd_tx
                    .send((self.id, resp_tx_clone, cmd, stats))
                    .unwrap();
            }

            // Obtain a response
            let resp = {
                let _t = Timer::new(&mut rec, "TransportTask:recv_resp");
                resp_rx.recv().unwrap()
            };

            // Return a response
            // println!("Returning response: {:?}", &resp);
            let rv = {
                let _t = Timer::new(&mut rec, "TransportTask:write_resp");
                transport.write_resp(&resp)
            };
            if !rv.is_ok() {
                println!("Failed to write response :(");
            }

            // Stop timing the loop
            rec.stop_timer("TransportTask:loop");

            // Now flush metrics outside the request path
            rec.flush_metrics();
        }
    }
}
<commit_msg>add explanation for error<commit_after>use std::net::TcpStream;
use std::sync::mpsc;

use metrics::MetricsRecorder;
use metrics::Timer;
use options::MemcacheOptions;
use protocol::cmd::Resp;
use tcp_transport::TcpTransport;

use super::CmdSender;
use super::MetricsSender;
use super::RespReceiver;
use super::RespSender;
use super::TransportId;

pub struct TransportTask {
    id: TransportId,
    cmd_tx: CmdSender,
    met_tx: MetricsSender,
    options: MemcacheOptions,
}

impl TransportTask {
    pub fn new(id: TransportId,
               cmd_tx: CmdSender,
               met_tx: MetricsSender,
               options: MemcacheOptions)
               -> TransportTask {
        TransportTask {
            id: id,
            cmd_tx: cmd_tx,
            met_tx: met_tx,
            options: options,
        }
    }

    pub fn run(&self, stream: TcpStream) {
        let mut rec = MetricsRecorder::new(self.met_tx.clone(),
                                           self.options.get_metrics_enabled());

        let mut transport = TcpTransport::new(stream);
        let (resp_tx, resp_rx): (RespSender, RespReceiver) = mpsc::channel();

        loop {
            // Time the whole loop
            rec.start_timer("TransportTask:loop");

            // println!("Ready to read command...");
            let rv = {
                let _t = Timer::new(&mut rec, "TransportTask:read_cmd");
                transport.read_cmd()
            };

            // If we couldn't parse the command return an error
            if !rv.is_ok() {
                println!("Failed to read command, returning error (client disconncted?)");
                let _ = transport.write_resp(&Resp::Error);
                return; // Here we just drop the connection
            }

            // Send the command to the driver
            let cmd = rv.unwrap();
            let resp_tx_clone = resp_tx.clone();
            let stats = transport.get_stats_clone();
            {
                let _t = Timer::new(&mut rec, "TransportTask:send_cmd");
                self.cmd_tx
                    .send((self.id, resp_tx_clone, cmd, stats))
                    .unwrap();
            }

            // Obtain a response
            let resp = {
                let _t = Timer::new(&mut rec, "TransportTask:recv_resp");
                resp_rx.recv().unwrap()
            };

            // Return a response
            // println!("Returning response: {:?}", &resp);
            let rv = {
                let _t = Timer::new(&mut rec, "TransportTask:write_resp");
                transport.write_resp(&resp)
            };
            if !rv.is_ok() {
                println!("Failed to write response :(");
            }

            // Stop timing the loop
            rec.stop_timer("TransportTask:loop");

            // Now flush metrics outside the request path
            rec.flush_metrics();
        }
    }
}
<|endoftext|>


<commit_before>use num::traits::{Zero};
use std::ops::Index;

#[derive(PartialEq,Debug)]
pub struct Matrix44<T> {
    pub m: [[T; 4]; 4],
}

impl <T> Matrix44<T> where T: Zero {
    pub fn zero() -> Matrix44<T> {
        Matrix44 { m: [
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()], ]}
    }

    pub fn new(mm: [[T; 4]; 4]) -> Matrix44<T> {
        Matrix44 { m : mm }
    }
}

impl <T> Index<usize> for Matrix44<T> where T: Zero {
    type Output = [T; 4];

    fn index(&self, index: usize) -> &[T; 4] {
       &(self.m[index])
    }
}

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

    #[test]
    fn should_be_initialized_as_zero_matrix() {
        let m: Matrix44<f64> = Matrix44::zero();

        assert_eq!(m, Matrix44::<f64> { m: [
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            ]});
    }

    #[test]
    fn should_be_initialized_by_coefficients() {
        let m: Matrix44<f64> = Matrix44::new([
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]);

        assert_eq!(m, Matrix44::<f64> { m: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]});
    }

    #[test]
    fn should_index_rows() {
        let m: Matrix44<f64> = Matrix44::new([
            [1.0, 2.0, 3.0, 4.0],
            [2.0, 3.0, 4.0, 5.0],
            [3.0, 4.0, 5.0, 6.0],
            [4.0, 5.0, 6.0, 7.0], ]);

        let row = m[1];

        assert_eq!(row, [2.0, 3.0, 4.0, 5.0]);
    }
}
<commit_msg>Implement Matrix multiplication<commit_after>use num::traits::{Zero,One};
use std::ops::{Mul,Add,Sub,Index};

#[derive(PartialEq,Debug)]
pub struct Matrix44<T> {
    pub m: [[T; 4]; 4],
}

impl <T> Matrix44<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Zero + One + Copy + Clone {
    pub fn zero() -> Matrix44<T> {
        Matrix44 { m: [
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()], ]}
    }

    pub fn diagonal(p: T, q: T, r: T, s: T) -> Matrix44<T> {
        Matrix44 { m: [
            [p, T::zero(), T::zero(), T::zero()],
            [T::zero(), q, T::zero(), T::zero()],
            [T::zero(), T::zero(), r, T::zero()],
            [T::zero(), T::zero(), T::zero(), s], ]}
    }

    pub fn new(mm: [[T; 4]; 4]) -> Matrix44<T> {
        Matrix44 { m : mm }
    }
}

impl <T> Index<usize> for Matrix44<T> where T: Zero {
    type Output = [T; 4];

    fn index(&self, index: usize) -> &[T; 4] {
       &(self.m[index])
    }
}

impl <T> Mul<Matrix44<T>> for Matrix44<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> + Zero + One + Copy + Clone {
    type Output = Matrix44<T>;

    fn mul(self, rhs: Matrix44<T>) -> Matrix44<T> {
        let mut result: [[T; 4]; 4] = [[T::zero(); 4]; 4];
        for i in 0..4 {
            for j in 0..4 {
                result[i][j] = self[i][0] * rhs[0][j] +
                    self[i][1] * rhs[1][j] +
                    self[i][2] * rhs[2][j] +
                    self[i][3] * rhs[3][j]
            }
        }
        Matrix44::new(result)
    }
}

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

    #[test]
    fn should_be_initialized_as_zero_matrix() {
        let m: Matrix44<f64> = Matrix44::zero();

        assert_eq!(m, Matrix44::<f64> { m: [
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            ]});
    }

    #[test]
    fn should_be_initialized_by_coefficients() {
        let m: Matrix44<f64> = Matrix44::new([
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]);

        assert_eq!(m, Matrix44::<f64> { m: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]});
    }

    #[test]
    fn should_index_rows() {
        let m: Matrix44<f64> = Matrix44::new([
            [1.0, 2.0, 3.0, 4.0],
            [2.0, 3.0, 4.0, 5.0],
            [3.0, 4.0, 5.0, 6.0],
            [4.0, 5.0, 6.0, 7.0], ]);

        let row = m[1];

        assert_eq!(row, [2.0, 3.0, 4.0, 5.0]);
    }

    #[test]
    fn should_matrix_multiply() {
        let m: Matrix44<f64> = Matrix44::diagonal(1.0, 2.0, 3.0, 4.0);
        let n: Matrix44<f64> = Matrix44::diagonal(4.0, 3.0, 2.0, 1.0);

        let product: Matrix44<f64> = m * n;

        assert_eq!(product, Matrix44::<f64> { m: [
            [4.0, 0.0, 0.0, 0.0],
            [0.0, 6.0, 0.0, 0.0],
            [0.0, 0.0, 6.0, 0.0],
            [0.0, 0.0, 0.0, 4.0],
        ]})
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul,Add};

pub struct Vec3<T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> {
    x: T,
    y: T,
    z: T,
}

impl <T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> Vec3<T> {
    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_know_its_length() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<commit_msg>Rename to should_know_its_norm<commit_after>use std::ops::{Mul,Add};

pub struct Vec3<T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> {
    x: T,
    y: T,
    z: T,
}

impl <T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> Vec3<T> {
    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_know_its_norm() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<|endoftext|>