<commit_before>use crate::error::{Result, ResultExt};
use lazy_static::lazy_static;
use proc_macro2::{Literal, Span};
use quote::{quote, ToTokens};
use ros_msg_parser::{DataType, FieldCase, FieldInfo, MessagePath};
use std::collections::{BTreeSet, HashMap};
use syn::Ident;

#[derive(Clone, Debug)]
pub struct Msg(pub ros_msg_parser::Msg);

impl Msg {
    pub fn new(path: MessagePath, source: &str) -> Result<Msg> {
        ros_msg_parser::Msg::new(path, source)
            .map(Self)
            .chain_err(|| "Failed to parse message")
    }

    pub fn name_ident(&self) -> Ident {
        Ident::new(self.0.path.name(), Span::call_site())
    }

    pub fn token_stream<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        let name = self.name_ident();
        let fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_token_stream(v, crate_prefix))
            .collect::<Vec<_>>();
        let field_defaults = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_default_token_stream(v, crate_prefix))
            .collect::<Vec<_>>();
        let fields_for_eq_and_debug = self
            .0
            .fields
            .iter()
            .filter_map(|v| field_info_field_name_eq_and_debug_token_stream(v))
            .collect::<Vec<_>>();
        let fields_partialeq = fields_for_eq_and_debug
            .iter()
            .map(|(_, peq, _)| quote! { self.#peq == other.#peq })
            .collect::<Vec<_>>();
        let fields_debug = fields_for_eq_and_debug
            .iter()
            .map(|(name, _, dbg)| quote! { .field(stringify!(#name), #dbg) })
            .collect::<Vec<_>>();
        let const_fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_const_token_stream(v, crate_prefix))
            .collect::<Vec<_>>();
        quote! {
            #[allow(dead_code, non_camel_case_types, non_snake_case)]
            #[derive(Clone)]
            pub struct #name {
                #(#fields)*
            }

            impl #name {
                #(#const_fields)*
            }

            impl std::cmp::PartialEq<Self> for #name {
                fn eq(&self, other: &Self) -> bool {
                    true #(&& #fields_partialeq)*
                }
            }

            impl std::fmt::Debug for #name {
                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                    f.debug_struct(stringify!(#name))
                        #(#fields_debug)*
                        .finish()
                }
            }

            impl Default for #name {
                fn default() -> Self {
                    Self {
                        #(#field_defaults)*
                    }
                }
            }
        }
    }

    pub fn token_stream_encode<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        let fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_token_stream_encode(v, crate_prefix))
            .collect::<Vec<_>>();
        quote! {
            #(#fields)*
            Ok(())
        }
    }

    pub fn token_stream_decode<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        let fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_token_stream_decode(v, crate_prefix))
            .collect::<Vec<_>>();
        quote! {
            Ok(Self {
                #(#fields)*
            })
        }
    }

    pub fn get_type(&self) -> String {
        format!("{}/{}", self.0.path.package(), self.0.path.name())
    }

    pub fn dependencies(&self) -> Result<Vec<MessagePath>> {
        self.0
            .fields
            .iter()
            .filter_map(|field| match field.datatype {
                DataType::LocalStruct(ref name) => Some(
                    MessagePath::new(self.0.path.package(), name)
                        .chain_err(|| "Invalid message path"),
                ),
                DataType::RemoteStruct(ref message) => Some(Ok(message.clone())),
                _ => None,
            })
            .collect()
    }

    pub fn get_md5_representation(
        &self,
        hashes: &HashMap<MessagePath, String>,
    ) -> ::std::result::Result<String, ()> {
        let constants = self
            .0
            .fields
            .iter()
            .filter(|v| v.is_constant())
            .map(|v| v.md5_string(self.0.path.package(), hashes))
            .collect::<::std::result::Result<Vec<String>, _>>()
            .map_err(|_| ())?;
        let fields = self
            .0
            .fields
            .iter()
            .filter(|v| !v.is_constant())
            .map(|v| v.md5_string(self.0.path.package(), hashes))
            .collect::<::std::result::Result<Vec<String>, _>>()
            .map_err(|_| ())?;
        let representation = constants
            .into_iter()
            .chain(fields)
            .collect::<Vec<_>>()
            .join("\n");
        Ok(representation)
    }

    pub fn has_header(&self) -> bool {
        self.0.fields.iter().any(FieldInfo::is_header)
    }

    pub fn header_token_stream<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        if !self.has_header() {
            return quote! {};
        }
        quote! {
            fn set_header(
                &mut self,
                clock: &::std::sync::Arc<#crate_prefix Clock>,
                seq: &::std::sync::Arc<::std::sync::atomic::AtomicUsize>,
            ) {
                if self.header.seq == 0 {
                    self.header.seq =
                        seq.fetch_add(1, ::std::sync::atomic::Ordering::SeqCst) as u32;
                }
                if self.header.stamp.nanos() == 0 {
                    self.header.stamp = clock.now();
                }
            }
        }
    }
}

lazy_static! {
    static ref RESERVED_KEYWORDS: BTreeSet<String> = [
        "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn",
        "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
        "return", "Self", "self", "static", "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while", "abstract", "alignof", "become", "box", "do", "final", "macro",
        "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof", "unsized", "virtual",
        "yield",
    ]
    .iter()
    .map(|&item| String::from(item))
    .collect();
}

pub fn field_info_create_identifier(field_info: &FieldInfo, span: Span) -> Ident {
    if RESERVED_KEYWORDS.contains(&field_info.name) {
        return Ident::new(&format!("{}_", field_info.name), span);
    }
    Ident::new(&field_info.name, span)
}

pub fn field_info_field_token_stream<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let datatype = datatype_token_stream(&field_info.datatype, crate_prefix);
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit => quote! { pub #name: #datatype, },
        FieldCase::Vector => quote! { pub #name: Vec<#datatype>, },
        FieldCase::Array(l) => quote! { pub #name: [#datatype; #l], },
        FieldCase::Const(_) => quote! {},
    }
}

pub fn field_info_field_name_eq_and_debug_token_stream(
    field_info: &FieldInfo,
) -> Option<(impl ToTokens, impl ToTokens, impl ToTokens)> {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit | FieldCase::Vector => {
            Some((quote! { #name }, quote! { #name }, quote! { &self.#name }))
        }
        FieldCase::Array(_) => Some((
            quote! { #name },
            quote! { #name[..] },
            quote! { &self.#name.iter().collect::<Vec<_>>() },
        )),
        FieldCase::Const(_) => None,
    }
}

pub fn field_info_field_default_token_stream<T: ToTokens>(
    field_info: &FieldInfo,
    _crate_prefix: &T,
) -> impl ToTokens {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit | FieldCase::Vector => quote! { #name: Default::default(), },
        FieldCase::Array(l) => {
            let instances = (0..l).map(|_| quote! {Default::default()});
            quote! { #name: [#(#instances),*], }
        }
        FieldCase::Const(_) => quote! {},
    }
}

pub fn field_info_field_token_stream_encode<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit => quote! { self.#name.encode(w.by_ref())?; },
        FieldCase::Vector => match field_info.datatype {
            DataType::String
            | DataType::Time
            | DataType::Duration
            | DataType::LocalStruct(_)
            | DataType::RemoteStruct(_) => {
                quote! { #crate_prefix rosmsg::encode_variable_slice(&self.#name, w.by_ref())?; }
            }
            _ => {
                quote! { #crate_prefix rosmsg::encode_variable_primitive_slice(&self.#name, w.by_ref())?; }
            }
        },
        FieldCase::Array(_l) => {
            quote! { #crate_prefix rosmsg::encode_fixed_slice(&self.#name, w.by_ref())?; }
        }
        FieldCase::Const(_) => quote! {},
    }
}

pub fn field_info_field_token_stream_decode<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit => quote! { #name: #crate_prefix rosmsg::RosMsg::decode(r.by_ref())?, },
        FieldCase::Vector => match field_info.datatype {
            DataType::String
            | DataType::Time
            | DataType::Duration
            | DataType::LocalStruct(_)
            | DataType::RemoteStruct(_) => {
                quote! { #name: #crate_prefix rosmsg::decode_variable_vec(r.by_ref())?, }
            }
            _ => {
                quote! { #name: #crate_prefix rosmsg::decode_variable_primitive_vec(r.by_ref())?, }
            }
        },
        FieldCase::Array(l) => {
            let lines =
                (0..l).map(|_| quote! { #crate_prefix rosmsg::RosMsg::decode(r.by_ref())?, });
            quote! { #name: [#(#lines)*], }
        }
        FieldCase::Const(_) => quote! {},
    }
}

pub fn field_info_const_token_stream<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let value = match field_info.case {
        FieldCase::Const(ref value) => value,
        _ => return quote! {},
    };
    let name = field_info_create_identifier(field_info, Span::call_site());
    let datatype = datatype_token_stream(&field_info.datatype, crate_prefix);
    let insides = match field_info.datatype {
        DataType::Bool => {
            let bool_value = if value != "0" {
                quote! { true }
            } else {
                quote! { false }
            };
            quote! { #name: bool = #bool_value }
        }
        DataType::String => quote! { #name: &'static str = #value },
        DataType::Time
        | DataType::Duration
        | DataType::LocalStruct(..)
        | DataType::RemoteStruct(..) => return quote! {},
        DataType::I8(_) => {
            let numeric_value = Literal::i8_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::I16 => {
            let numeric_value = Literal::i16_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::I32 => {
            let numeric_value = Literal::i32_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::I64 => {
            let numeric_value = Literal::i64_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U8(_) => {
            let numeric_value = Literal::u8_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U16 => {
            let numeric_value = Literal::u16_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U32 => {
            let numeric_value = Literal::u32_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U64 => {
            let numeric_value = Literal::u64_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::F32 => {
            let numeric_value = Literal::f32_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::F64 => {
            let numeric_value = Literal::f64_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
    };
    quote! {
        #[allow(dead_code,non_upper_case_globals)]
        pub const #insides;
    }
}

pub fn datatype_token_stream<T: ToTokens>(data_type: &DataType, crate_prefix: &T) -> impl ToTokens {
    match data_type {
        DataType::Bool => quote! { bool },
        DataType::I8(_) => quote! { i8 },
        DataType::I16 => quote! { i16 },
        DataType::I32 => quote! { i32 },
        DataType::I64 => quote! { i64 },
        DataType::U8(_) => quote! { u8 },
        DataType::U16 => quote! { u16 },
        DataType::U32 => quote! { u32 },
        DataType::U64 => quote! { u64 },
        DataType::F32 => quote! { f32 },
        DataType::F64 => quote! { f64 },
        DataType::String => quote! { ::std::string::String },
        DataType::Time => quote! { #crate_prefix Time },
        DataType::Duration => quote! { #crate_prefix Duration },
        DataType::LocalStruct(ref name) => {
            let name = Ident::new(name, Span::call_site());
            quote! { #name }
        }
        DataType::RemoteStruct(ref message) => {
            let name = Ident::new(message.name(), Span::call_site());
            let pkg = Ident::new(message.package(), Span::call_site());
            quote! { super::#pkg::#name }
        }
    }
}
<commit_msg>Make unnecessary public functions private<commit_after>use crate::error::{Result, ResultExt};
use lazy_static::lazy_static;
use proc_macro2::{Literal, Span};
use quote::{quote, ToTokens};
use ros_msg_parser::{DataType, FieldCase, FieldInfo, MessagePath};
use std::collections::{BTreeSet, HashMap};
use syn::Ident;

#[derive(Clone, Debug)]
pub struct Msg(pub ros_msg_parser::Msg);

impl Msg {
    pub fn new(path: MessagePath, source: &str) -> Result<Msg> {
        ros_msg_parser::Msg::new(path, source)
            .map(Self)
            .chain_err(|| "Failed to parse message")
    }

    pub fn name_ident(&self) -> Ident {
        Ident::new(self.0.path.name(), Span::call_site())
    }

    pub fn token_stream<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        let name = self.name_ident();
        let fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_token_stream(v, crate_prefix))
            .collect::<Vec<_>>();
        let field_defaults = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_default_token_stream(v, crate_prefix))
            .collect::<Vec<_>>();
        let fields_for_eq_and_debug = self
            .0
            .fields
            .iter()
            .filter_map(|v| field_info_field_name_eq_and_debug_token_stream(v))
            .collect::<Vec<_>>();
        let fields_partialeq = fields_for_eq_and_debug
            .iter()
            .map(|(_, peq, _)| quote! { self.#peq == other.#peq })
            .collect::<Vec<_>>();
        let fields_debug = fields_for_eq_and_debug
            .iter()
            .map(|(name, _, dbg)| quote! { .field(stringify!(#name), #dbg) })
            .collect::<Vec<_>>();
        let const_fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_const_token_stream(v, crate_prefix))
            .collect::<Vec<_>>();
        quote! {
            #[allow(dead_code, non_camel_case_types, non_snake_case)]
            #[derive(Clone)]
            pub struct #name {
                #(#fields)*
            }

            impl #name {
                #(#const_fields)*
            }

            impl std::cmp::PartialEq<Self> for #name {
                fn eq(&self, other: &Self) -> bool {
                    true #(&& #fields_partialeq)*
                }
            }

            impl std::fmt::Debug for #name {
                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                    f.debug_struct(stringify!(#name))
                        #(#fields_debug)*
                        .finish()
                }
            }

            impl Default for #name {
                fn default() -> Self {
                    Self {
                        #(#field_defaults)*
                    }
                }
            }
        }
    }

    pub fn token_stream_encode<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        let fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_token_stream_encode(v, crate_prefix))
            .collect::<Vec<_>>();
        quote! {
            #(#fields)*
            Ok(())
        }
    }

    pub fn token_stream_decode<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        let fields = self
            .0
            .fields
            .iter()
            .map(|v| field_info_field_token_stream_decode(v, crate_prefix))
            .collect::<Vec<_>>();
        quote! {
            Ok(Self {
                #(#fields)*
            })
        }
    }

    pub fn get_type(&self) -> String {
        format!("{}/{}", self.0.path.package(), self.0.path.name())
    }

    pub fn dependencies(&self) -> Result<Vec<MessagePath>> {
        self.0
            .fields
            .iter()
            .filter_map(|field| match field.datatype {
                DataType::LocalStruct(ref name) => Some(
                    MessagePath::new(self.0.path.package(), name)
                        .chain_err(|| "Invalid message path"),
                ),
                DataType::RemoteStruct(ref message) => Some(Ok(message.clone())),
                _ => None,
            })
            .collect()
    }

    pub fn get_md5_representation(
        &self,
        hashes: &HashMap<MessagePath, String>,
    ) -> ::std::result::Result<String, ()> {
        let constants = self
            .0
            .fields
            .iter()
            .filter(|v| v.is_constant())
            .map(|v| v.md5_string(self.0.path.package(), hashes))
            .collect::<::std::result::Result<Vec<String>, _>>()
            .map_err(|_| ())?;
        let fields = self
            .0
            .fields
            .iter()
            .filter(|v| !v.is_constant())
            .map(|v| v.md5_string(self.0.path.package(), hashes))
            .collect::<::std::result::Result<Vec<String>, _>>()
            .map_err(|_| ())?;
        let representation = constants
            .into_iter()
            .chain(fields)
            .collect::<Vec<_>>()
            .join("\n");
        Ok(representation)
    }

    pub fn has_header(&self) -> bool {
        self.0.fields.iter().any(FieldInfo::is_header)
    }

    pub fn header_token_stream<T: ToTokens>(&self, crate_prefix: &T) -> impl ToTokens {
        if !self.has_header() {
            return quote! {};
        }
        quote! {
            fn set_header(
                &mut self,
                clock: &::std::sync::Arc<#crate_prefix Clock>,
                seq: &::std::sync::Arc<::std::sync::atomic::AtomicUsize>,
            ) {
                if self.header.seq == 0 {
                    self.header.seq =
                        seq.fetch_add(1, ::std::sync::atomic::Ordering::SeqCst) as u32;
                }
                if self.header.stamp.nanos() == 0 {
                    self.header.stamp = clock.now();
                }
            }
        }
    }
}

lazy_static! {
    static ref RESERVED_KEYWORDS: BTreeSet<String> = [
        "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn",
        "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
        "return", "Self", "self", "static", "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while", "abstract", "alignof", "become", "box", "do", "final", "macro",
        "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof", "unsized", "virtual",
        "yield",
    ]
    .iter()
    .map(|&item| String::from(item))
    .collect();
}

fn field_info_create_identifier(field_info: &FieldInfo, span: Span) -> Ident {
    if RESERVED_KEYWORDS.contains(&field_info.name) {
        return Ident::new(&format!("{}_", field_info.name), span);
    }
    Ident::new(&field_info.name, span)
}

fn field_info_field_token_stream<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let datatype = datatype_token_stream(&field_info.datatype, crate_prefix);
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit => quote! { pub #name: #datatype, },
        FieldCase::Vector => quote! { pub #name: Vec<#datatype>, },
        FieldCase::Array(l) => quote! { pub #name: [#datatype; #l], },
        FieldCase::Const(_) => quote! {},
    }
}

fn field_info_field_name_eq_and_debug_token_stream(
    field_info: &FieldInfo,
) -> Option<(impl ToTokens, impl ToTokens, impl ToTokens)> {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit | FieldCase::Vector => {
            Some((quote! { #name }, quote! { #name }, quote! { &self.#name }))
        }
        FieldCase::Array(_) => Some((
            quote! { #name },
            quote! { #name[..] },
            quote! { &self.#name.iter().collect::<Vec<_>>() },
        )),
        FieldCase::Const(_) => None,
    }
}

fn field_info_field_default_token_stream<T: ToTokens>(
    field_info: &FieldInfo,
    _crate_prefix: &T,
) -> impl ToTokens {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit | FieldCase::Vector => quote! { #name: Default::default(), },
        FieldCase::Array(l) => {
            let instances = (0..l).map(|_| quote! {Default::default()});
            quote! { #name: [#(#instances),*], }
        }
        FieldCase::Const(_) => quote! {},
    }
}

fn field_info_field_token_stream_encode<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit => quote! { self.#name.encode(w.by_ref())?; },
        FieldCase::Vector => match field_info.datatype {
            DataType::String
            | DataType::Time
            | DataType::Duration
            | DataType::LocalStruct(_)
            | DataType::RemoteStruct(_) => {
                quote! { #crate_prefix rosmsg::encode_variable_slice(&self.#name, w.by_ref())?; }
            }
            _ => {
                quote! { #crate_prefix rosmsg::encode_variable_primitive_slice(&self.#name, w.by_ref())?; }
            }
        },
        FieldCase::Array(_l) => {
            quote! { #crate_prefix rosmsg::encode_fixed_slice(&self.#name, w.by_ref())?; }
        }
        FieldCase::Const(_) => quote! {},
    }
}

fn field_info_field_token_stream_decode<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let name = field_info_create_identifier(field_info, Span::call_site());
    match field_info.case {
        FieldCase::Unit => quote! { #name: #crate_prefix rosmsg::RosMsg::decode(r.by_ref())?, },
        FieldCase::Vector => match field_info.datatype {
            DataType::String
            | DataType::Time
            | DataType::Duration
            | DataType::LocalStruct(_)
            | DataType::RemoteStruct(_) => {
                quote! { #name: #crate_prefix rosmsg::decode_variable_vec(r.by_ref())?, }
            }
            _ => {
                quote! { #name: #crate_prefix rosmsg::decode_variable_primitive_vec(r.by_ref())?, }
            }
        },
        FieldCase::Array(l) => {
            let lines =
                (0..l).map(|_| quote! { #crate_prefix rosmsg::RosMsg::decode(r.by_ref())?, });
            quote! { #name: [#(#lines)*], }
        }
        FieldCase::Const(_) => quote! {},
    }
}

fn field_info_const_token_stream<T: ToTokens>(
    field_info: &FieldInfo,
    crate_prefix: &T,
) -> impl ToTokens {
    let value = match field_info.case {
        FieldCase::Const(ref value) => value,
        _ => return quote! {},
    };
    let name = field_info_create_identifier(field_info, Span::call_site());
    let datatype = datatype_token_stream(&field_info.datatype, crate_prefix);
    let insides = match field_info.datatype {
        DataType::Bool => {
            let bool_value = if value != "0" {
                quote! { true }
            } else {
                quote! { false }
            };
            quote! { #name: bool = #bool_value }
        }
        DataType::String => quote! { #name: &'static str = #value },
        DataType::Time
        | DataType::Duration
        | DataType::LocalStruct(..)
        | DataType::RemoteStruct(..) => return quote! {},
        DataType::I8(_) => {
            let numeric_value = Literal::i8_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::I16 => {
            let numeric_value = Literal::i16_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::I32 => {
            let numeric_value = Literal::i32_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::I64 => {
            let numeric_value = Literal::i64_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U8(_) => {
            let numeric_value = Literal::u8_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U16 => {
            let numeric_value = Literal::u16_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U32 => {
            let numeric_value = Literal::u32_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::U64 => {
            let numeric_value = Literal::u64_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::F32 => {
            let numeric_value = Literal::f32_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
        DataType::F64 => {
            let numeric_value = Literal::f64_suffixed(value.parse().unwrap());
            quote! { #name: #datatype = #numeric_value as #datatype }
        }
    };
    quote! {
        #[allow(dead_code,non_upper_case_globals)]
        pub const #insides;
    }
}

fn datatype_token_stream<T: ToTokens>(data_type: &DataType, crate_prefix: &T) -> impl ToTokens {
    match data_type {
        DataType::Bool => quote! { bool },
        DataType::I8(_) => quote! { i8 },
        DataType::I16 => quote! { i16 },
        DataType::I32 => quote! { i32 },
        DataType::I64 => quote! { i64 },
        DataType::U8(_) => quote! { u8 },
        DataType::U16 => quote! { u16 },
        DataType::U32 => quote! { u32 },
        DataType::U64 => quote! { u64 },
        DataType::F32 => quote! { f32 },
        DataType::F64 => quote! { f64 },
        DataType::String => quote! { ::std::string::String },
        DataType::Time => quote! { #crate_prefix Time },
        DataType::Duration => quote! { #crate_prefix Duration },
        DataType::LocalStruct(ref name) => {
            let name = Ident::new(name, Span::call_site());
            quote! { #name }
        }
        DataType::RemoteStruct(ref message) => {
            let name = Ident::new(message.name(), Span::call_site());
            let pkg = Ident::new(message.package(), Span::call_site());
            quote! { super::#pkg::#name }
        }
    }
}
<|endoftext|>


<commit_before>use super::*;

use std::{collections::HashSet, ops::Bound};

#[derive(Debug, Clone)]
pub(crate) struct View<'a> {
    pub(crate) pid: PageId,
    pub(crate) lo: &'a IVec,
    pub(crate) hi: &'a IVec,
    pub(crate) is_index: bool,
    pub(crate) next: Option<PageId>,
    pub(crate) ptr: TreePtr<'a>,
    frags: Vec<&'a Frag>,
    base_offset: usize,
    pub(crate) base_data: &'a Data,
    pub(crate) merging_child: Option<PageId>,
    pub(crate) merging: bool,
    min_children: usize,
    max_children: usize,
    size: u64,
}

impl<'a> View<'a> {
    pub(crate) fn new(
        pid: PageId,
        ptr: TreePtr<'a>,
        frags: Vec<&'a Frag>,
    ) -> View<'a> {
        let mut merging = false;
        let mut merging_child = None;
        let mut merge_confirmed = false;
        let mut min_children: isize = 0;
        let mut max_children = 0;
        let mut size = 0;

        for (offset, frag) in frags.iter().enumerate() {
            size += frag.size_in_bytes();
            match frag {
                Frag::Base(node) => {
                    // NB if we re-add ParentSplit, we must
                    // handle the hi & next members differently
                    // here

                    min_children += node.data.len() as isize;
                    max_children += node.data.len();

                    return View {
                        hi: &node.hi,
                        lo: &node.lo,
                        is_index: node.data.index_ref().is_some(),
                        next: node.next,
                        base_offset: offset,
                        base_data: &node.data,
                        pid,
                        ptr,
                        frags,
                        merging,
                        merging_child,
                        min_children: std::cmp::max(0, min_children) as usize,
                        max_children,
                        size,
                    };
                }
                Frag::ParentMergeIntention(pid) => {
                    if merge_confirmed {
                        merge_confirmed = false;
                    } else {
                        assert!(merging_child.is_none());
                        merging_child = Some(*pid);
                    }
                }
                Frag::ParentMergeConfirm => {
                    assert!(!merge_confirmed);
                    merge_confirmed = true;
                }
                Frag::ChildMergeCap => {
                    assert!(!merging);
                    assert_eq!(offset, 0);
                    merging = true;
                }
                Frag::Del(..) => min_children -= 1,
                Frag::Set(..) | Frag::Merge(..) => max_children += 1,
            }
        }

        panic!("view was never initialized with a base")
    }

    pub(crate) fn contains_upper_bound(&self, bound: &Bound<IVec>) -> bool {
        match bound {
            Bound::Excluded(bound) if self.hi >= bound => true,
            Bound::Included(bound) if self.hi > bound => true,
            _ => self.hi.is_empty(),
        }
    }

    pub(crate) fn contains_lower_bound(
        &self,
        bound: &Bound<IVec>,
        is_forward: bool,
    ) -> bool {
        match bound {
            Bound::Excluded(bound)
                if self.lo < bound || (is_forward && bound == self.lo) =>
            {
                true
            }
            Bound::Included(bound) if self.lo <= bound => true,
            Bound::Unbounded if !is_forward => self.hi.is_empty(),
            _ => self.lo.is_empty(),
        }
    }

    fn keys(&self) -> Vec<&IVec> {
        let mut keys: HashSet<&IVec> = self
            .base_data
            .leaf_ref()
            .unwrap()
            .iter()
            .map(|(k, _v)| k)
            .collect();

        for offset in (0..self.base_offset).rev() {
            match self.frags[offset] {
                Frag::Set(k, _) => {
                    keys.insert(k);
                }
                Frag::Del(k) => {
                    keys.remove(k);
                }
                Frag::Merge(k, _) => {
                    keys.insert(k);
                }
                Frag::Base(_) => {
                    panic!(
                        "somehow hit 2 base nodes while \
                         searching for a successor"
                    );
                }
                Frag::ChildMergeCap => {}
                Frag::ParentMergeIntention(_) | Frag::ParentMergeConfirm => {
                    panic!(
                        "somehow hit parent merge \
                         frags while searching for a \
                         successor"
                    )
                }
            }
        }

        let mut keys: Vec<_> = keys.into_iter().collect();
        keys.sort_unstable_by(|a, b| prefix_cmp(&a, &b));

        keys
    }

    pub(crate) fn successor(
        &self,
        bound: &Bound<IVec>,
        config: &Config,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.is_index);

        // This encoding happens this way because
        // keys cannot be lower than the node's lo key.
        let predecessor_key = match bound {
            Bound::Unbounded => prefix_encode(self.lo, self.lo),
            Bound::Included(b) => {
                let max = std::cmp::max(b, self.lo);
                prefix_encode(self.lo, max)
            }
            Bound::Excluded(b) => {
                let max = std::cmp::max(b, self.lo);
                prefix_encode(self.lo, max)
            }
        };

        let keys = self.keys();

        let successor_keys = keys.iter().filter(|k| {
            let ord = prefix_cmp(k, &predecessor_key);

            ord == std::cmp::Ordering::Greater
                || ord == std::cmp::Ordering::Equal
        });

        for encoded_key in successor_keys {
            let decoded_key = prefix_decode(self.lo, &encoded_key);

            if let Bound::Excluded(e) = bound {
                if e == &decoded_key {
                    // skip this excluded key
                    continue;
                }
            }

            // try to get this key until it works
            if let Some(value) = self.leaf_value_for_key(&decoded_key, config) {
                return Some((IVec::from(decoded_key), value));
            }
        }

        None
    }

    pub(crate) fn predecessor(
        &self,
        bound: &Bound<IVec>,
        config: &Config,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.is_index);

        // This encoding happens this way because
        // the rightmost (unbounded) node has
        // a hi key represented by the empty slice
        let successor_key = match bound {
            Bound::Unbounded => {
                if self.hi.is_empty() {
                    prefix_encode(self.lo, &[255; 1024 * 1024])
                } else {
                    prefix_encode(self.lo, self.hi)
                }
            }
            Bound::Included(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, self.hi)
                };
                prefix_encode(self.lo, min)
            }
            Bound::Excluded(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, self.hi)
                };
                prefix_encode(self.lo, min)
            }
        };

        let keys = self.keys();

        let predecessor_keys = keys.iter().filter(|k| {
            let ord = prefix_cmp(k, &successor_key);

            ord == std::cmp::Ordering::Less || ord == std::cmp::Ordering::Equal
        });

        for encoded_key in predecessor_keys.rev() {
            let decoded_key = prefix_decode(self.lo, &encoded_key);

            if let Bound::Excluded(e) = bound {
                if e == &decoded_key {
                    // skip this excluded key
                    continue;
                }
            }

            // try to get this key until it works
            if let Some(value) = self.leaf_value_for_key(&decoded_key, config) {
                return Some((IVec::from(decoded_key), value));
            }
        }

        None
    }

    pub(crate) fn leaf_value_for_key(
        &self,
        key: &[u8],
        config: &Config,
    ) -> Option<IVec> {
        assert!(!self.is_index);

        let mut merge_base = None;
        let mut merges = vec![];

        for frag in self.frags[..=self.base_offset].iter() {
            match frag {
                Frag::Set(k, val) if self.key_eq(k, key) => {
                    if merges.is_empty() {
                        return Some(val.clone());
                    } else {
                        merge_base = Some(val);
                        break;
                    }
                }
                Frag::Del(k) if self.key_eq(k, key) => {
                    // we should ignore "earlier" Frag's for
                    // this key, but still need to handle
                    // merges we encountered "after" this
                    // deletion
                    break;
                }
                Frag::Merge(k, val) if self.key_eq(k, key) => merges.push(val),
                Frag::Base(node) => {
                    let data = &node.data;
                    let items =
                        data.leaf_ref().expect("last_node should be a leaf");
                    let search = items
                        .binary_search_by(|&(ref k, ref _v)| {
                            prefix_cmp_encoded(k, key, &self.lo)
                        })
                        .ok();

                    let val = search.map(|idx| &items[idx].1);
                    if merges.is_empty() {
                        return val.cloned();
                    } else {
                        merge_base = val;
                    }
                }
                _ => {}
            }
        }

        if merges.is_empty() {
            None
        } else {
            let merge_fn_ptr = config
                .merge_operator
                .expect("must have a merge operator set");

            unsafe {
                let merge_fn: MergeOperator = std::mem::transmute(merge_fn_ptr);

                let mut ret = merge_fn(
                    key,
                    merge_base.map(|iv| &**iv),
                    &merges.pop().unwrap(),
                );
                                       ;
                for merge in merges.into_iter().rev() {
                    if let Some(v) = ret {
                        ret = merge_fn(key, Some(&*v), merge);
                    } else {
                        ret = merge_fn(key, None, merge);
                    }
                }

                ret.map(IVec::from)
            }
        }
    }

    #[inline]
    fn key_eq(&self, encoded: &[u8], not_encoded: &[u8]) -> bool {
        prefix_cmp_encoded(encoded, not_encoded, self.lo)
            == std::cmp::Ordering::Equal
    }

    pub(crate) fn index_next_node(&self, key: &[u8]) -> (usize, PageId) {
        assert!(self.is_index);

        for frag in self.frags[..=self.base_offset].iter() {
            match frag {
                Frag::Set(..) => unimplemented!(),
                Frag::Del(..) => unimplemented!(),
                Frag::Merge(..) => unimplemented!(),
                Frag::Base(node) => {
                    let data = &node.data;
                    let items =
                        data.index_ref().expect("last_node should be a leaf");
                    let search =
                        binary_search_lub(items, |&(ref k, ref _v)| {
                            prefix_cmp_encoded(k, key, &node.lo)
                        });

                    // This might be none if ord is Less and we're
                    // searching for the empty key
                    let index = search.expect("failed to traverse index");

                    return (index, items[index].1);
                }
                Frag::ParentMergeIntention(_)
                | Frag::ParentMergeConfirm
                | Frag::ChildMergeCap => {
                    // nothing to do for these frags
                }
            }
        }
        panic!("no index found")
    }

    pub(crate) fn should_split(&self, max_sz: u64) -> bool {
        let size_checks = self.min_children > 2 && self.size > max_sz;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn should_merge(&self, min_sz: u64) -> bool {
        let size_checks = self.max_children < 2 || self.size < min_sz;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn can_merge_child(&self) -> bool {
        self.merging_child.is_none() && !self.merging
    }

    pub(crate) fn compact(&self, config: &Config) -> Node {
        let mut lhs = self.frags[self.base_offset].unwrap_base().clone();
        for offset in (0..self.base_offset).rev() {
            let frag = self.frags[offset];
            lhs.apply(frag, config.merge_operator);
        }
        lhs
    }

    pub(crate) fn split(&self, config: &Config) -> (Node, Node) {
        let mut lhs = self.compact(config);
        let rhs = lhs.split();

        lhs.data.drop_gte(&rhs.lo, &lhs.lo);
        lhs.hi = rhs.lo.clone();

        // intentionally make this the end to make
        // any issues pop out with setting it
        // correctly after the split.
        lhs.next = None;

        (lhs, rhs)
    }
}
<commit_msg>Account for merged children in index traversal<commit_after>use super::*;

use std::{collections::HashSet, ops::Bound};

#[derive(Debug, Clone)]
pub(crate) struct View<'a> {
    pub(crate) pid: PageId,
    pub(crate) lo: &'a IVec,
    pub(crate) hi: &'a IVec,
    pub(crate) is_index: bool,
    pub(crate) next: Option<PageId>,
    pub(crate) ptr: TreePtr<'a>,
    frags: Vec<&'a Frag>,
    base_offset: usize,
    pub(crate) base_data: &'a Data,
    pub(crate) merging_child: Option<PageId>,
    pub(crate) merging: bool,
    min_children: usize,
    max_children: usize,
    size: u64,
}

impl<'a> View<'a> {
    pub(crate) fn new(
        pid: PageId,
        ptr: TreePtr<'a>,
        frags: Vec<&'a Frag>,
    ) -> View<'a> {
        let mut merging = false;
        let mut merging_child = None;
        let mut merge_confirmed = false;
        let mut min_children: isize = 0;
        let mut max_children = 0;
        let mut size = 0;

        for (offset, frag) in frags.iter().enumerate() {
            size += frag.size_in_bytes();
            match frag {
                Frag::Base(node) => {
                    // NB if we re-add ParentSplit, we must
                    // handle the hi & next members differently
                    // here

                    min_children += node.data.len() as isize;
                    max_children += node.data.len();

                    return View {
                        hi: &node.hi,
                        lo: &node.lo,
                        is_index: node.data.index_ref().is_some(),
                        next: node.next,
                        base_offset: offset,
                        base_data: &node.data,
                        pid,
                        ptr,
                        frags,
                        merging,
                        merging_child,
                        min_children: std::cmp::max(0, min_children) as usize,
                        max_children,
                        size,
                    };
                }
                Frag::ParentMergeIntention(pid) => {
                    if merge_confirmed {
                        merge_confirmed = false;
                    } else {
                        assert!(merging_child.is_none());
                        merging_child = Some(*pid);
                    }
                }
                Frag::ParentMergeConfirm => {
                    assert!(!merge_confirmed);
                    merge_confirmed = true;
                }
                Frag::ChildMergeCap => {
                    assert!(!merging);
                    assert_eq!(offset, 0);
                    merging = true;
                }
                Frag::Del(..) => min_children -= 1,
                Frag::Set(..) | Frag::Merge(..) => max_children += 1,
            }
        }

        panic!("view was never initialized with a base")
    }

    pub(crate) fn contains_upper_bound(&self, bound: &Bound<IVec>) -> bool {
        match bound {
            Bound::Excluded(bound) if self.hi >= bound => true,
            Bound::Included(bound) if self.hi > bound => true,
            _ => self.hi.is_empty(),
        }
    }

    pub(crate) fn contains_lower_bound(
        &self,
        bound: &Bound<IVec>,
        is_forward: bool,
    ) -> bool {
        match bound {
            Bound::Excluded(bound)
                if self.lo < bound || (is_forward && bound == self.lo) =>
            {
                true
            }
            Bound::Included(bound) if self.lo <= bound => true,
            Bound::Unbounded if !is_forward => self.hi.is_empty(),
            _ => self.lo.is_empty(),
        }
    }

    fn keys(&self) -> Vec<&IVec> {
        let mut keys: HashSet<&IVec> = self
            .base_data
            .leaf_ref()
            .unwrap()
            .iter()
            .map(|(k, _v)| k)
            .collect();

        for offset in (0..self.base_offset).rev() {
            match self.frags[offset] {
                Frag::Set(k, _) => {
                    keys.insert(k);
                }
                Frag::Del(k) => {
                    keys.remove(k);
                }
                Frag::Merge(k, _) => {
                    keys.insert(k);
                }
                Frag::Base(_) => {
                    panic!(
                        "somehow hit 2 base nodes while \
                         searching for a successor"
                    );
                }
                Frag::ChildMergeCap => {}
                Frag::ParentMergeIntention(_) | Frag::ParentMergeConfirm => {
                    panic!(
                        "somehow hit parent merge \
                         frags while searching for a \
                         successor"
                    )
                }
            }
        }

        let mut keys: Vec<_> = keys.into_iter().collect();
        keys.sort_unstable_by(|a, b| prefix_cmp(&a, &b));

        keys
    }

    pub(crate) fn successor(
        &self,
        bound: &Bound<IVec>,
        config: &Config,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.is_index);

        // This encoding happens this way because
        // keys cannot be lower than the node's lo key.
        let predecessor_key = match bound {
            Bound::Unbounded => prefix_encode(self.lo, self.lo),
            Bound::Included(b) => {
                let max = std::cmp::max(b, self.lo);
                prefix_encode(self.lo, max)
            }
            Bound::Excluded(b) => {
                let max = std::cmp::max(b, self.lo);
                prefix_encode(self.lo, max)
            }
        };

        let keys = self.keys();

        let successor_keys = keys.iter().filter(|k| {
            let ord = prefix_cmp(k, &predecessor_key);

            ord == std::cmp::Ordering::Greater
                || ord == std::cmp::Ordering::Equal
        });

        for encoded_key in successor_keys {
            let decoded_key = prefix_decode(self.lo, &encoded_key);

            if let Bound::Excluded(e) = bound {
                if e == &decoded_key {
                    // skip this excluded key
                    continue;
                }
            }

            // try to get this key until it works
            if let Some(value) = self.leaf_value_for_key(&decoded_key, config) {
                return Some((IVec::from(decoded_key), value));
            }
        }

        None
    }

    pub(crate) fn predecessor(
        &self,
        bound: &Bound<IVec>,
        config: &Config,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.is_index);

        // This encoding happens this way because
        // the rightmost (unbounded) node has
        // a hi key represented by the empty slice
        let successor_key = match bound {
            Bound::Unbounded => {
                if self.hi.is_empty() {
                    prefix_encode(self.lo, &[255; 1024 * 1024])
                } else {
                    prefix_encode(self.lo, self.hi)
                }
            }
            Bound::Included(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, self.hi)
                };
                prefix_encode(self.lo, min)
            }
            Bound::Excluded(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, self.hi)
                };
                prefix_encode(self.lo, min)
            }
        };

        let keys = self.keys();

        let predecessor_keys = keys.iter().filter(|k| {
            let ord = prefix_cmp(k, &successor_key);

            ord == std::cmp::Ordering::Less || ord == std::cmp::Ordering::Equal
        });

        for encoded_key in predecessor_keys.rev() {
            let decoded_key = prefix_decode(self.lo, &encoded_key);

            if let Bound::Excluded(e) = bound {
                if e == &decoded_key {
                    // skip this excluded key
                    continue;
                }
            }

            // try to get this key until it works
            if let Some(value) = self.leaf_value_for_key(&decoded_key, config) {
                return Some((IVec::from(decoded_key), value));
            }
        }

        None
    }

    pub(crate) fn leaf_value_for_key(
        &self,
        key: &[u8],
        config: &Config,
    ) -> Option<IVec> {
        assert!(!self.is_index);

        let mut merge_base = None;
        let mut merges = vec![];

        for frag in self.frags[..=self.base_offset].iter() {
            match frag {
                Frag::Set(k, val) if self.key_eq(k, key) => {
                    if merges.is_empty() {
                        return Some(val.clone());
                    } else {
                        merge_base = Some(val);
                        break;
                    }
                }
                Frag::Del(k) if self.key_eq(k, key) => {
                    // we should ignore "earlier" Frag's for
                    // this key, but still need to handle
                    // merges we encountered "after" this
                    // deletion
                    break;
                }
                Frag::Merge(k, val) if self.key_eq(k, key) => merges.push(val),
                Frag::Base(node) => {
                    let data = &node.data;
                    let items =
                        data.leaf_ref().expect("last_node should be a leaf");
                    let search = items
                        .binary_search_by(|&(ref k, ref _v)| {
                            prefix_cmp_encoded(k, key, &self.lo)
                        })
                        .ok();

                    let val = search.map(|idx| &items[idx].1);
                    if merges.is_empty() {
                        return val.cloned();
                    } else {
                        merge_base = val;
                    }
                }
                _ => {}
            }
        }

        if merges.is_empty() {
            None
        } else {
            let merge_fn_ptr = config
                .merge_operator
                .expect("must have a merge operator set");

            unsafe {
                let merge_fn: MergeOperator = std::mem::transmute(merge_fn_ptr);

                let mut ret = merge_fn(
                    key,
                    merge_base.map(|iv| &**iv),
                    &merges.pop().unwrap(),
                );
                                       ;
                for merge in merges.into_iter().rev() {
                    if let Some(v) = ret {
                        ret = merge_fn(key, Some(&*v), merge);
                    } else {
                        ret = merge_fn(key, None, merge);
                    }
                }

                ret.map(IVec::from)
            }
        }
    }

    #[inline]
    fn key_eq(&self, encoded: &[u8], not_encoded: &[u8]) -> bool {
        prefix_cmp_encoded(encoded, not_encoded, self.lo)
            == std::cmp::Ordering::Equal
    }

    pub(crate) fn index_next_node(&self, key: &[u8]) -> (usize, PageId) {
        assert!(self.is_index);
        let mut removed = vec![];

        for frag in self.frags[..=self.base_offset].iter() {
            match frag {
                Frag::Set(..) => unimplemented!(),
                Frag::Del(..) => unimplemented!(),
                Frag::Merge(..) => unimplemented!(),
                Frag::Base(node) => {
                    let data = &node.data;
                    let items =
                        data.index_ref().expect("last_node should be a leaf");
                    let search =
                        binary_search_lub(items, |&(ref k, ref _v)| {
                            prefix_cmp_encoded(k, key, &node.lo)
                        });

                    // This might be none if ord is Less and we're
                    // searching for the empty key
                    let mut index = search.expect("failed to traverse index");
                    while removed.contains(&items[index].1) {
                        index -= 1;
                    }

                    return (index, items[index].1);
                }
                Frag::ParentMergeIntention(child_pid) => {
                    removed.push(*child_pid);
                }
                Frag::ParentMergeConfirm | Frag::ChildMergeCap => {
                    // nothing to do for these frags
                }
            }
        }
        panic!("no index found")
    }

    pub(crate) fn should_split(&self, max_sz: u64) -> bool {
        let size_checks = self.min_children > 2 && self.size > max_sz;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn should_merge(&self, min_sz: u64) -> bool {
        let size_checks = self.max_children < 2 || self.size < min_sz;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn can_merge_child(&self) -> bool {
        self.merging_child.is_none() && !self.merging
    }

    pub(crate) fn compact(&self, config: &Config) -> Node {
        let mut lhs = self.frags[self.base_offset].unwrap_base().clone();
        for offset in (0..self.base_offset).rev() {
            let frag = self.frags[offset];
            lhs.apply(frag, config.merge_operator);
        }
        lhs
    }

    pub(crate) fn split(&self, config: &Config) -> (Node, Node) {
        let mut lhs = self.compact(config);
        let rhs = lhs.split();

        lhs.data.drop_gte(&rhs.lo, &lhs.lo);
        lhs.hi = rhs.lo.clone();

        // intentionally make this the end to make
        // any issues pop out with setting it
        // correctly after the split.
        lhs.next = None;

        (lhs, rhs)
    }
}
<|endoftext|>


<commit_before>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Representation the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Write a single `MidiEvent`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
        self.write_events(vec![midi_event])
    }

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, midi_message.into()) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<commit_msg>s/Representations/Represents<commit_after>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Represents the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Write a single `MidiEvent`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
        self.write_events(vec![midi_event])
    }

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, midi_message.into()) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<|endoftext|>


<commit_before>//! # Find the last box of a list.
//! # example
///```
///use p99::p1::my_last;
///assert_eq!(my_last(&['a','b','c','d']),Some(['d']));
///assert_eq!(my_last(&['d']),Some(['d']));
///assert_eq!(my_last(&[]),None);
///```

pub fn my_last(list: &[char]) -> Option<[char; 1]> {
    if list.len() > 0 {
        Some([list[list.len() - 1]])
    } else {
        None
    }
}
<commit_msg>generic function p1<commit_after>//! # Find the last box of a list.
//! # example
///```
///use p99::p1::my_last;
///assert_eq!(my_last(&['a','b','c','d']),Some(['d']));
///assert_eq!(my_last(&['d']),Some(['d']));
///let list: &[char] = &[];
///assert_eq!(my_last(list),None);
///```
// TODO should rewrite about line to assert_eq!(&[]:&[char])
// after issue 23416 implemented

use std::clone::Clone;
pub fn my_last<T>(list: &[T]) -> Option<[T; 1]> where T: PartialEq + Clone {
    if list.len() > 0 {
        Some([list[list.len() - 1].clone()])
    } else {
        None
    }
}
<|endoftext|>