<commit_before>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::method_chain_args;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for unnecessary `ok()` in `while let`.
    ///
    /// ### Why is this bad?
    /// Calling `ok()` in `while let` is unnecessary, instead match
    /// on `Ok(pat)`
    ///
    /// ### Example
    /// ```ignore
    /// while let Some(value) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Some(valie) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// while let Ok(value) = iter.next() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Ok(value) = iter.next() {
    ///        vec.push_value)
    /// }
    /// ```
    pub MATCH_RESULT_OK,
    style,
    "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
}

declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]);

impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        let (let_pat, let_expr, ifwhile) =
            if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
                (let_pat, let_expr, "if")
            } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
                (let_pat, let_expr, "while")
            } else {
                return;
            };

        if_chain! {
            if let ExprKind::MethodCall(_, ok_span, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
            if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = let_pat.kind; //get operation
            if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
            if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";

            then {

                let mut applicability = Applicability::MachineApplicable;
                let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
                let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability);
                let sugg = format!(
                    "{} let Ok({}) = {}",
                    ifwhile,
                    some_expr_string,
                    trimmed_ok.trim().trim_end_matches('.'),
                );
                span_lint_and_sugg(
                    cx,
                    MATCH_RESULT_OK,
                    expr.span.with_hi(let_expr.span.hi()),
                    "matching on `Some` with `ok()` is redundant",
                    &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
                    sugg,
                    applicability,
                );
            }
        }
    }
}
<commit_msg>Auto merge of #7815 - nhamovitz:patch-1, r=giraffate<commit_after>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::method_chain_args;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for unnecessary `ok()` in `while let`.
    ///
    /// ### Why is this bad?
    /// Calling `ok()` in `while let` is unnecessary, instead match
    /// on `Ok(pat)`
    ///
    /// ### Example
    /// ```ignore
    /// while let Some(value) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Some(valie) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// while let Ok(value) = iter.next() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Ok(value) = iter.next() {
    ///        vec.push(value)
    /// }
    /// ```
    pub MATCH_RESULT_OK,
    style,
    "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
}

declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]);

impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        let (let_pat, let_expr, ifwhile) =
            if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
                (let_pat, let_expr, "if")
            } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
                (let_pat, let_expr, "while")
            } else {
                return;
            };

        if_chain! {
            if let ExprKind::MethodCall(_, ok_span, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
            if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = let_pat.kind; //get operation
            if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
            if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";

            then {

                let mut applicability = Applicability::MachineApplicable;
                let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
                let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability);
                let sugg = format!(
                    "{} let Ok({}) = {}",
                    ifwhile,
                    some_expr_string,
                    trimmed_ok.trim().trim_end_matches('.'),
                );
                span_lint_and_sugg(
                    cx,
                    MATCH_RESULT_OK,
                    expr.span.with_hi(let_expr.span.hi()),
                    "matching on `Some` with `ok()` is redundant",
                    &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
                    sugg,
                    applicability,
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>use gluon::vm::types::VmTag;
use proc_macro2::{Span, TokenStream};
use syn::{
    self, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, FieldsNamed, FieldsUnnamed,
    GenericParam, Generics, Ident, Lifetime, LifetimeDef, Variant,
};

pub fn derive(input: TokenStream) -> TokenStream {
    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = syn::parse2(input).expect("Input is checked by rustc");

    let tokens = match data {
        Data::Struct(ast) => derive_struct(ast, ident, generics),
        Data::Enum(ast) => derive_enum(ast, ident, generics),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn derive_struct(ast: DataStruct, ident: Ident, generics: Generics) -> TokenStream {
    // TODO: impl derive for structs
    unimplemented!()
}

fn derive_enum(ast: DataEnum, ident: Ident, generics: Generics) -> TokenStream {
    let variants: Vec<_> = ast.variants
        .iter()
        .enumerate()
        .map(|(tag, variant)| gen_variant_match(&ident, tag as VmTag, variant))
        .collect();

    let (_, ty_generics, where_clause) = generics.split_for_impl();
    let where_clause = where_clause
        .map(|clause| quote! { #clause, })
        .unwrap_or(quote! { where });

    let mut generics = generics.clone();
    let lifetime =
        GenericParam::Lifetime(LifetimeDef::new(Lifetime::new("'vm", Span::call_site())));
    generics.params.insert(0, lifetime);
    let (impl_generics, ..) = generics.split_for_impl();

    let getable_bounds = ast.variants
        .iter()
        .flat_map(|variant| create_getable_bounds(&variant.fields));

    quote! {
        impl #impl_generics ::gluon::vm::api::Getable<'vm> for #ident #ty_generics
        #where_clause #(#getable_bounds),*
        {
            fn from_value(vm: &'vm ::gluon::vm::thread::Thread, variants: ::gluon::vm::Variants) -> Self {
                let data = match variants.as_ref() {
                    ::gluon::vm::api::ValueRef::Data(data) => data,
                    val => panic!("Unexpected value: '{:?}'. Do the type definitions match?", val),
                };

                match data.tag() {
                    #(#variants,)*
                    tag => panic!("Unexpected tag: '{}'. Do the type definitions match?", tag)
                }
            }
        }
    }
}

fn gen_variant_match(ident: &Ident, tag: VmTag, variant: &Variant) -> TokenStream {
    let variant_ident = &variant.ident;

    match &variant.fields {
        Fields::Unit => quote! {
            #tag => #ident::#variant_ident
        },
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
            let cons = gen_tuple_cons(unnamed.into_iter().collect());

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
        Fields::Named(FieldsNamed { named, .. }) => {
            let cons = gen_struct_cons(named.into_iter().collect());

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
    }
}

fn gen_tuple_cons(fields: Vec<&Field>) -> TokenStream {
    let fields: Vec<_> = fields
        .into_iter()
        .enumerate()
        .map(|(idx, field)| {
            let field_ty = &field.ty;

            quote! {
                if let Some(val) = data.get_variant(#idx) {
                    <#field_ty as ::gluon::vm::api::Getable<'vm>>::from_value(vm, val)
                } else {
                    panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
                }
            }
        })
        .collect();

    quote!{
        (#(#fields),*)
    }
}

fn gen_struct_cons(fields: Vec<&Field>) -> TokenStream {
    let fields: Vec<_> = fields
        .into_iter()
        .enumerate()
        .map(|(idx, field)| {
            let field_ty = &field.ty;
            let field_ident = field
                .ident
                .as_ref()
                .expect("Struct fields always have names");

            quote! {
                #field_ident: if let Some(val) = data.get_variant(#idx) {
                    <#field_ty as ::gluon::vm::api::Getable<'vm>>::from_value(vm, val)
                } else {
                    panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
                }
            }
        })
        .collect();

    quote!{
        {#(#fields),*}
    }
}

fn create_getable_bounds(fields: &Fields) -> Vec<TokenStream> {
    let fields = match fields {
        Fields::Named(FieldsNamed { named, .. }) => named.iter().collect(),
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => unnamed.iter().collect(),
        Fields::Unit => Vec::new(),
    };

    fields
        .into_iter()
        .map(|field| {
            let ty = &field.ty;

            quote! {
                #ty: ::gluon::vm::api::Getable<'vm>
            }
        })
        .collect()
}
<commit_msg>Use '__vm as lifetime parameter to avoid collisions<commit_after>use gluon::vm::types::VmTag;
use proc_macro2::{Span, TokenStream};
use syn::{
    self, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, FieldsNamed, FieldsUnnamed,
    GenericParam, Generics, Ident, Lifetime, LifetimeDef, Variant,
};

pub fn derive(input: TokenStream) -> TokenStream {
    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = syn::parse2(input).expect("Input is checked by rustc");

    let tokens = match data {
        Data::Struct(ast) => derive_struct(ast, ident, generics),
        Data::Enum(ast) => derive_enum(ast, ident, generics),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn derive_struct(ast: DataStruct, ident: Ident, generics: Generics) -> TokenStream {
    // TODO: impl derive for structs
    unimplemented!()
}

fn derive_enum(ast: DataEnum, ident: Ident, generics: Generics) -> TokenStream {
    let variants: Vec<_> = ast.variants
        .iter()
        .enumerate()
        .map(|(tag, variant)| gen_variant_match(&ident, tag as VmTag, variant))
        .collect();

    let (_, ty_generics, where_clause) = generics.split_for_impl();
    let where_clause = where_clause
        .map(|clause| quote! { #clause, })
        .unwrap_or(quote! { where });

    let mut generics = generics.clone();
    let lifetime =
        GenericParam::Lifetime(LifetimeDef::new(Lifetime::new("'__vm", Span::call_site())));
    generics.params.insert(0, lifetime);
    let (impl_generics, ..) = generics.split_for_impl();

    let getable_bounds = ast.variants
        .iter()
        .flat_map(|variant| create_getable_bounds(&variant.fields));

    quote! {
        impl #impl_generics ::gluon::vm::api::Getable<'__vm> for #ident #ty_generics
        #where_clause #(#getable_bounds),*
        {
            fn from_value(vm: &'__vm ::gluon::vm::thread::Thread, variants: ::gluon::vm::Variants) -> Self {
                let data = match variants.as_ref() {
                    ::gluon::vm::api::ValueRef::Data(data) => data,
                    val => panic!("Unexpected value: '{:?}'. Do the type definitions match?", val),
                };

                match data.tag() {
                    #(#variants,)*
                    tag => panic!("Unexpected tag: '{}'. Do the type definitions match?", tag)
                }
            }
        }
    }
}

fn gen_variant_match(ident: &Ident, tag: VmTag, variant: &Variant) -> TokenStream {
    let variant_ident = &variant.ident;

    match &variant.fields {
        Fields::Unit => quote! {
            #tag => #ident::#variant_ident
        },
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
            let cons = gen_tuple_cons(unnamed.into_iter().collect());

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
        Fields::Named(FieldsNamed { named, .. }) => {
            let cons = gen_struct_cons(named.into_iter().collect());

            quote! {
                #tag => #ident::#variant_ident#cons
            }
        }
    }
}

fn gen_tuple_cons(fields: Vec<&Field>) -> TokenStream {
    let fields: Vec<_> = fields
        .into_iter()
        .enumerate()
        .map(|(idx, field)| {
            let field_ty = &field.ty;

            quote! {
                if let Some(val) = data.get_variant(#idx) {
                    <#field_ty as ::gluon::vm::api::Getable<'__vm>>::from_value(vm, val)
                } else {
                    panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
                }
            }
        })
        .collect();

    quote!{
        (#(#fields),*)
    }
}

fn gen_struct_cons(fields: Vec<&Field>) -> TokenStream {
    let fields: Vec<_> = fields
        .into_iter()
        .enumerate()
        .map(|(idx, field)| {
            let field_ty = &field.ty;
            let field_ident = field
                .ident
                .as_ref()
                .expect("Struct fields always have names");

            quote! {
                #field_ident: if let Some(val) = data.get_variant(#idx) {
                    <#field_ty as ::gluon::vm::api::Getable<'__vm>>::from_value(vm, val)
                } else {
                    panic!("Enum does not contain data at index '{}'. Do the type definitions match?", #idx)
                }
            }
        })
        .collect();

    quote!{
        {#(#fields),*}
    }
}

fn create_getable_bounds(fields: &Fields) -> Vec<TokenStream> {
    let fields = match fields {
        Fields::Named(FieldsNamed { named, .. }) => named.iter().collect(),
        Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => unnamed.iter().collect(),
        Fields::Unit => Vec::new(),
    };

    fields
        .into_iter()
        .map(|field| {
            let ty = &field.ty;

            quote! {
                #ty: ::gluon::vm::api::Getable<'__vm>
            }
        })
        .collect()
}
<|endoftext|>


<commit_before>use std::time::{Duration, Instant};

use control::cio;
use torrent::Peer;
use util::{random_sample, FHashSet, UHashMap};

pub struct Choker {
    unchoked: Vec<usize>,
    interested: FHashSet<usize>,
    last_updated: Instant,
}

#[derive(Debug, PartialEq)]
pub struct SwapRes {
    pub choked: usize,
    pub unchoked: usize,
}

impl Choker {
    pub fn new() -> Choker {
        Choker {
            unchoked: Vec::with_capacity(5),
            interested: FHashSet::default(),
            last_updated: Instant::now(),
        }
    }

    pub fn add_peer<T: cio::CIO>(&mut self, peer: &mut Peer<T>) {
        if self.unchoked.len() < 5 {
            self.unchoked.push(peer.id());
            peer.flush();
            peer.unchoke();
        } else {
            self.interested.insert(peer.id());
        }
    }

    fn unchoke_random<T: cio::CIO>(&mut self, peers: &mut UHashMap<Peer<T>>) -> Option<usize> {
        if let Some(random_id) = random_sample(self.interested.iter()).cloned() {
            peers.get_mut(&random_id).map(|mut peer| {
                self.interested.remove(&random_id);
                self.add_peer(&mut peer);
                random_id
            })
        } else {
            None
        }
    }

    pub fn remove_peer<T: cio::CIO>(
        &mut self,
        peer: &mut Peer<T>,
        peers: &mut UHashMap<Peer<T>>,
    ) -> Option<SwapRes> {
        if let Some(idx) = self.unchoked.iter().position(|&id| id == peer.id()) {
            self.unchoked.remove(idx);
            peer.choke();
            self.unchoke_random(peers).map(|unchoked| SwapRes {
                choked: peer.id(),
                unchoked,
            })
        } else {
            self.interested.remove(&peer.id());
            None
        }
    }

    fn update_timer(&mut self) -> Result<(), ()> {
        if self.last_updated.elapsed() < Duration::from_secs(10)
            || self.unchoked.len() < 5
            || self.interested.is_empty()
        {
            Err(())
        } else {
            self.last_updated = Instant::now();
            Ok(())
        }
    }

    pub fn update_upload<T: cio::CIO>(&mut self, peers: &mut UHashMap<Peer<T>>) -> Option<SwapRes> {
        if self.update_timer().is_err() {
            return None;
        }
        if self.interested.is_empty() {
            return None;
        }
        let (slowest, _) = self.unchoked.iter().enumerate().fold(
            (0, ::std::u32::MAX),
            |(slowest, min), (idx, id)| {
                match peers.get_mut(id).map(Peer::flush) {
                    Some((ul, _)) if ul < min => (idx, ul),
                    _ => (slowest, min),
                }
            }
        );
        Some(self.swap_peer(slowest, peers))
    }

    pub fn update_download<T: cio::CIO>(
        &mut self,
        peers: &mut UHashMap<Peer<T>>,
    ) -> Option<SwapRes> {
        if self.update_timer().is_err() {
            return None;
        }

        let (slowest, _) = self.unchoked.iter().enumerate().fold(
            (0, ::std::u32::MAX),
            |(slowest, min), (idx, id)| {
                match peers.get_mut(id).map(Peer::flush) {
                    Some((_, dl)) if dl < min =>
                        (idx, dl),
                    _ =>
                        (slowest, min),
                }
            },
        );
        Some(self.swap_peer(slowest, peers))
    }

    fn swap_peer<T: cio::CIO>(&mut self, idx: usize, peers: &mut UHashMap<Peer<T>>) -> SwapRes {
        let id = self.unchoked.remove(idx);
        {
            peers.get_mut(&id).map(Peer::choke);
        }

        // Unchoke one random interested peer
        let r = SwapRes {
            choked: id,
            unchoked: self.unchoke_random(peers).unwrap(),
        };
        self.interested.insert(id);
        r
    }
}

#[cfg(test)]
mod tests {
    use super::{Choker, SwapRes};
    use std::time::{Duration, Instant};
    use torrent::{Bitfield, Peer};
    use util::UHashMap;

    #[test]
    fn test_add_peers() {
        let mut c = Choker::new();
        for i in 0..6 {
            let mut p = Peer::test(i, 0, 0, 0, Bitfield::new(1));
            // Since the socket is a dummy
            c.add_peer(&mut p);
        }
        assert_eq!(c.unchoked.len(), 5);
        assert_eq!(c.interested.len(), 1);
    }

    #[test]
    fn test_remove_peers() {
        let mut c = Choker::new();
        let mut v = Vec::new();
        let mut h = UHashMap::default();
        for i in 0..6 {
            let mut p = Peer::test_from_stats(i, 0, 0);
            c.add_peer(&mut p);
            v.push(p);
            // Semi copy
            let pc = Peer::test_from_stats(i, 0, 0);
            h.insert(i, pc);
        }
        assert_eq!(c.unchoked.contains(&v[0].id()), true);
        assert_eq!(
            c.remove_peer(&mut v[0], &mut h),
            Some(SwapRes {
                choked: v[0].id(),
                unchoked: 5,
            })
        );
        assert_eq!(c.unchoked.contains(&v[0].id()), false);
    }

    #[test]
    fn test_update_upload() {
        let mut c = Choker::new();
        let mut h = UHashMap::default();
        assert_eq!(c.update_upload(&mut h).is_none(), true);
        for i in 0..6 {
            let mut p = Peer::test_from_stats(i, i as u32, 6 - i as u32);
            c.add_peer(&mut p);
            h.insert(i, p);
        }
        assert_eq!(c.update_upload(&mut h).is_none(), true);
        c.last_updated = Instant::now() - Duration::from_secs(11);
        let res = c.update_upload(&mut h).unwrap();
        assert_eq!(res.choked, 0);
        assert_eq!(res.unchoked, 5);
    }

    #[test]
    fn test_update_download() {
        let mut c = Choker::new();
        let mut h = UHashMap::default();
        assert_eq!(c.update_download(&mut h).is_none(), true);
        for i in 0..6 {
            let mut p = Peer::test_from_stats(i, 6 - i as u32, i as u32);
            c.add_peer(&mut p);
            h.insert(i, p);
        }
        assert_eq!(c.update_download(&mut h).is_none(), true);
        c.last_updated = Instant::now() - Duration::from_secs(11);
        let res = c.update_download(&mut h).unwrap();
        assert_eq!(res.choked, 0);
        assert_eq!(res.unchoked, 5);
    }
}
<commit_msg>Prevent peer swap choker panic<commit_after>use std::time::{Duration, Instant};

use control::cio;
use torrent::Peer;
use util::{random_sample, FHashSet, UHashMap};

pub struct Choker {
    unchoked: Vec<usize>,
    interested: FHashSet<usize>,
    last_updated: Instant,
}

#[derive(Debug, PartialEq)]
pub struct SwapRes {
    pub choked: usize,
    pub unchoked: usize,
}

impl Choker {
    pub fn new() -> Choker {
        Choker {
            unchoked: Vec::with_capacity(5),
            interested: FHashSet::default(),
            last_updated: Instant::now(),
        }
    }

    pub fn add_peer<T: cio::CIO>(&mut self, peer: &mut Peer<T>) {
        if self.unchoked.len() < 5 {
            self.unchoked.push(peer.id());
            peer.flush();
            peer.unchoke();
        } else {
            self.interested.insert(peer.id());
        }
    }

    fn unchoke_random<T: cio::CIO>(&mut self, peers: &mut UHashMap<Peer<T>>) -> Option<usize> {
        if let Some(random_id) = random_sample(self.interested.iter()).cloned() {
            peers.get_mut(&random_id).map(|mut peer| {
                self.interested.remove(&random_id);
                self.add_peer(&mut peer);
                random_id
            })
        } else {
            None
        }
    }

    pub fn remove_peer<T: cio::CIO>(
        &mut self,
        peer: &mut Peer<T>,
        peers: &mut UHashMap<Peer<T>>,
    ) -> Option<SwapRes> {
        if let Some(idx) = self.unchoked.iter().position(|&id| id == peer.id()) {
            self.unchoked.remove(idx);
            peer.choke();
            self.unchoke_random(peers).map(|unchoked| SwapRes {
                choked: peer.id(),
                unchoked,
            })
        } else {
            self.interested.remove(&peer.id());
            None
        }
    }

    fn update_timer(&mut self) -> Result<(), ()> {
        if self.last_updated.elapsed() < Duration::from_secs(10)
            || self.unchoked.len() < 5
            || self.interested.is_empty()
        {
            Err(())
        } else {
            self.last_updated = Instant::now();
            Ok(())
        }
    }

    pub fn update_upload<T: cio::CIO>(&mut self, peers: &mut UHashMap<Peer<T>>) -> Option<SwapRes> {
        if self.update_timer().is_err() {
            return None;
        }
        if self.interested.is_empty() {
            return None;
        }
        let (slowest, _) = self.unchoked.iter().enumerate().fold(
            (0, ::std::u32::MAX),
            |(slowest, min), (idx, id)| {
                match peers.get_mut(id).map(Peer::flush) {
                    Some((ul, _)) if ul < min => (idx, ul),
                    _ => (slowest, min),
                }
            }
        );
        self.swap_peer(slowest, peers)
    }

    pub fn update_download<T: cio::CIO>(
        &mut self,
        peers: &mut UHashMap<Peer<T>>,
    ) -> Option<SwapRes> {
        if self.update_timer().is_err() {
            return None;
        }

        let (slowest, _) = self.unchoked.iter().enumerate().fold(
            (0, ::std::u32::MAX),
            |(slowest, min), (idx, id)| {
                match peers.get_mut(id).map(Peer::flush) {
                    Some((_, dl)) if dl < min =>
                        (idx, dl),
                    _ =>
                        (slowest, min),
                }
            },
        );
        self.swap_peer(slowest, peers)
    }

    fn swap_peer<T: cio::CIO>(&mut self, idx: usize, peers: &mut UHashMap<Peer<T>>) -> Option<SwapRes> {
        let id = self.unchoked.remove(idx);
        {
            peers.get_mut(&id).map(Peer::choke);
        }

        // Unchoke one random interested peer
        self.unchoke_random(peers)
            .map(|unchoked| {
                self.interested.insert(id);
                SwapRes {
                    choked: id,
                    unchoked
                }
            })
    }
}

#[cfg(test)]
mod tests {
    use super::{Choker, SwapRes};
    use std::time::{Duration, Instant};
    use torrent::{Bitfield, Peer};
    use util::UHashMap;

    #[test]
    fn test_add_peers() {
        let mut c = Choker::new();
        for i in 0..6 {
            let mut p = Peer::test(i, 0, 0, 0, Bitfield::new(1));
            // Since the socket is a dummy
            c.add_peer(&mut p);
        }
        assert_eq!(c.unchoked.len(), 5);
        assert_eq!(c.interested.len(), 1);
    }

    #[test]
    fn test_remove_peers() {
        let mut c = Choker::new();
        let mut v = Vec::new();
        let mut h = UHashMap::default();
        for i in 0..6 {
            let mut p = Peer::test_from_stats(i, 0, 0);
            c.add_peer(&mut p);
            v.push(p);
            // Semi copy
            let pc = Peer::test_from_stats(i, 0, 0);
            h.insert(i, pc);
        }
        assert_eq!(c.unchoked.contains(&v[0].id()), true);
        assert_eq!(
            c.remove_peer(&mut v[0], &mut h),
            Some(SwapRes {
                choked: v[0].id(),
                unchoked: 5,
            })
        );
        assert_eq!(c.unchoked.contains(&v[0].id()), false);
    }

    #[test]
    fn test_update_upload() {
        let mut c = Choker::new();
        let mut h = UHashMap::default();
        assert_eq!(c.update_upload(&mut h).is_none(), true);
        for i in 0..6 {
            let mut p = Peer::test_from_stats(i, i as u32, 6 - i as u32);
            c.add_peer(&mut p);
            h.insert(i, p);
        }
        assert_eq!(c.update_upload(&mut h).is_none(), true);
        c.last_updated = Instant::now() - Duration::from_secs(11);
        let res = c.update_upload(&mut h).unwrap();
        assert_eq!(res.choked, 0);
        assert_eq!(res.unchoked, 5);
    }

    #[test]
    fn test_update_download() {
        let mut c = Choker::new();
        let mut h = UHashMap::default();
        assert_eq!(c.update_download(&mut h).is_none(), true);
        for i in 0..6 {
            let mut p = Peer::test_from_stats(i, 6 - i as u32, i as u32);
            c.add_peer(&mut p);
            h.insert(i, p);
        }
        assert_eq!(c.update_download(&mut h).is_none(), true);
        c.last_updated = Instant::now() - Duration::from_secs(11);
        let res = c.update_download(&mut h).unwrap();
        assert_eq!(res.choked, 0);
        assert_eq!(res.unchoked, 5);
    }
}
<|endoftext|>


<commit_before>use std;

use std::borrow::Borrow;
use std::ops::Deref;
use std::ptr;
use std::str;

use crlf;
use smallvec::{Array, SmallVec};
use str_utils::{char_idx_to_byte_idx, count_chars};
use tree::MAX_BYTES;

/// A custom small string, with an internal buffer of `tree::MAX_BYTES`
/// length.  Has a bunch of methods on it that are useful for the rope
/// tree.
#[derive(Clone, Default)]
pub(crate) struct NodeText {
    buffer: SmallVec<BackingArray>,
}

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText {
            buffer: SmallVec::new(),
        }
    }

    /// Creates a new empty `NodeText` with at least `capacity` bytes
    /// of capacity.
    #[inline(always)]
    pub fn with_capacity(capacity: usize) -> Self {
        NodeText {
            buffer: SmallVec::with_capacity(capacity),
        }
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        debug_assert!(string.len() <= MAX_BYTES);
        let mut nodetext = NodeText::with_capacity(string.len());
        unsafe { nodetext.insert_bytes(0, string.as_bytes()) };
        nodetext
    }

    /// Inserts a `&str` at byte offset `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        debug_assert!(self.is_char_boundary(byte_idx));
        debug_assert!(byte_idx <= self.len());
        debug_assert!((self.len() + string.len()) <= MAX_BYTES);

        unsafe {
            self.insert_bytes(byte_idx, string.as_bytes());
        }
    }

    /// Inserts the given text into the given string at the given char index.
    pub fn insert_str_at_char(&mut self, text: &str, char_idx: usize) {
        debug_assert!((self.len() + text.len()) <= MAX_BYTES);
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.insert_str(byte_idx, text);
    }

    /// Inserts a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(idx));
        debug_assert!((self.len() + string.len()) <= (MAX_BYTES * 2 - 4));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = idx;
        let b = idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        debug_assert!(split_idx <= MAX_BYTES);

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        debug_assert!((self.len() + string.len()) <= MAX_BYTES);
        let len = self.len();
        unsafe {
            self.insert_bytes(len, string.as_bytes());
        }
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// grapheme boundaries, so if the whole string is a single code point or
    /// CRLF pair, the split will fail and the returned string will be empty.
    ///
    /// TODO: make this work without allocations when possible.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        self.buffer.truncate(idx);
        self.inline_if_possible();
    }

    /// Drops the text before byte index `idx`, shifting the
    /// rest of the text to fill in the space.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate_front(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        unsafe {
            self.remove_bytes(0, idx);
        }
    }

    /// Removes the text in the byte index interval `[start, end)`.
    ///
    /// Panics if either `start` or `end` are not char boundaries, as that
    /// would result in an invalid utf8 string.
    pub fn remove_range(&mut self, start: usize, end: usize) {
        assert!(self.is_char_boundary(start));
        assert!(self.is_char_boundary(end));
        debug_assert!(end <= self.len());
        debug_assert!(start <= end);
        unsafe {
            self.remove_bytes(start, end);
        }
        self.inline_if_possible();
    }

    pub fn remove_char_range(&mut self, start: usize, end: usize) {
        debug_assert!(start <= end);
        debug_assert!(end <= count_chars(self));

        let byte_start = char_idx_to_byte_idx(self, start);
        let byte_end = char_idx_to_byte_idx(&self[start..], end - start);

        unsafe { self.remove_bytes(byte_start, byte_end) }
        self.inline_if_possible();
    }

    /// Splits the `NodeText` at `idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn split_off(&mut self, idx: usize) -> Self {
        assert!(self.is_char_boundary(idx));
        assert!(idx <= self.len());
        let len = self.len();
        let mut other = NodeText::with_capacity(len - idx);
        unsafe {
            ptr::copy_nonoverlapping(
                self.buffer.as_ptr().offset(idx as isize),
                other.buffer.as_mut_ptr().offset(0),
                len - idx,
            );
            self.buffer.set_len(idx);
            other.buffer.set_len(len - idx);
        }
        self.inline_if_possible();
        other
    }

    /// Splits a string into two strings at the char index given.
    /// The first section of the split is stored in the original string,
    /// while the second section of the split is returned as a new string.
    pub fn split_off_at_char(&mut self, char_idx: usize) -> Self {
        debug_assert!(char_idx <= count_chars(self));
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.split_off(byte_idx)
    }

    #[inline(always)]
    pub fn shrink_to_fit(&mut self) {
        self.buffer.shrink_to_fit();
    }

    /// Returns whether the string has spilled out into a heap-allocated
    /// memory area.
    pub fn spilled(&self) -> bool {
        self.buffer.spilled()
    }

    #[inline(always)]
    pub unsafe fn as_mut_smallvec(&mut self) -> &mut SmallVec<BackingArray> {
        &mut self.buffer
    }

    #[inline(always)]
    unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
        assert!(idx <= self.len());
        debug_assert!((self.len() + bytes.len()) <= MAX_BYTES);

        let len = self.len();
        let amt = bytes.len();
        self.buffer.reserve(amt);

        ptr::copy(
            self.buffer.as_ptr().offset(idx as isize),
            self.buffer.as_mut_ptr().offset((idx + amt) as isize),
            len - idx,
        );
        ptr::copy(
            bytes.as_ptr(),
            self.buffer.as_mut_ptr().offset(idx as isize),
            amt,
        );
        self.buffer.set_len(len + amt);
    }

    #[inline(always)]
    unsafe fn remove_bytes(&mut self, start: usize, end: usize) {
        assert!(start <= end);
        assert!(end <= self.len());
        let len = self.len();
        let amt = end - start;
        ptr::copy(
            self.buffer.as_ptr().offset(end as isize),
            self.buffer.as_mut_ptr().offset(start as isize),
            len - end,
        );
        self.buffer.set_len(len - amt);

        self.inline_if_possible();
    }

    /// Re-inlines the data if it's been heap allocated but can
    /// fit inline.
    #[inline(always)]
    fn inline_if_possible(&mut self) {
        if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
            self.buffer.shrink_to_fit();
        }
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

impl<'a> From<&'a str> for NodeText {
    fn from(s: &str) -> Self {
        Self::from_str(s)
    }
}

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl Borrow<str> for NodeText {
    fn borrow(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

//=======================================================================

/// Takes two `NodeText`s and mends the segment break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is one big grapheme.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    // Find the nearest breaks around the seam.
    let l_split = crlf::prev_break(l.len(), l.as_bytes());
    let r_split = l.len() + crlf::next_break(0, r.as_bytes());

    // Find the new split position, if any.
    let new_split_pos = {
        let tot_len = l.len() + r.len();
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The backing internal buffer for `NodeText`.
#[derive(Copy, Clone)]
pub(crate) struct BackingArray([u8; MAX_BYTES]);
unsafe impl Array for BackingArray {
    type Item = u8;
    fn size() -> usize {
        MAX_BYTES
    }
    fn ptr(&self) -> *const u8 {
        &self.0[0]
    }
    fn ptr_mut(&mut self) -> *mut u8 {
        &mut self.0[0]
    }
}

//=======================================================================

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

    #[test]
    fn remove_bytes_01() {
        let mut s = NodeText::new();
        s.push_str("Hello!");
        unsafe {
            s.remove_bytes(2, 4);
        }
        assert_eq!("Heo!", s);
    }
}
<commit_msg>Stop-gap to make the grapheme seam corner-case work.<commit_after>use std;

use std::borrow::Borrow;
use std::ops::Deref;
use std::ptr;
use std::str;

use crlf;
use smallvec::{Array, SmallVec};
use str_utils::{char_idx_to_byte_idx, count_chars};
use tree::MAX_BYTES;

// TODO: handle corner-case when fixing CRLF seams, and then uncomment
// all of the `MAX_BYTES` asserts to make sure that no allocations are
// happening.  Finally, remove SmallVec in favor of a simple byte array
// + len.

/// A custom small string, with an internal buffer of `tree::MAX_BYTES`
/// length.  Has a bunch of methods on it that are useful for the rope
/// tree.
#[derive(Clone, Default)]
pub(crate) struct NodeText {
    buffer: SmallVec<BackingArray>,
}

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText {
            buffer: SmallVec::new(),
        }
    }

    /// Creates a new empty `NodeText` with at least `capacity` bytes
    /// of capacity.
    #[inline(always)]
    pub fn with_capacity(capacity: usize) -> Self {
        NodeText {
            buffer: SmallVec::with_capacity(capacity),
        }
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        debug_assert!(string.len() <= MAX_BYTES);
        let mut nodetext = NodeText::with_capacity(string.len());
        unsafe { nodetext.insert_bytes(0, string.as_bytes()) };
        nodetext
    }

    /// Inserts a `&str` at byte offset `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        debug_assert!(self.is_char_boundary(byte_idx));
        debug_assert!(byte_idx <= self.len());
        // debug_assert!((self.len() + string.len()) <= MAX_BYTES);

        unsafe {
            self.insert_bytes(byte_idx, string.as_bytes());
        }
    }

    /// Inserts the given text into the given string at the given char index.
    pub fn insert_str_at_char(&mut self, text: &str, char_idx: usize) {
        // debug_assert!((self.len() + text.len()) <= MAX_BYTES);
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.insert_str(byte_idx, text);
    }

    /// Inserts a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(idx));
        // debug_assert!((self.len() + string.len()) <= (MAX_BYTES * 2 - 4));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = idx;
        let b = idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        // debug_assert!(split_idx <= MAX_BYTES);

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        // debug_assert!((self.len() + string.len()) <= MAX_BYTES);
        let len = self.len();
        unsafe {
            self.insert_bytes(len, string.as_bytes());
        }
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// grapheme boundaries, so if the whole string is a single code point or
    /// CRLF pair, the split will fail and the returned string will be empty.
    ///
    /// TODO: make this work without allocations when possible.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        self.buffer.truncate(idx);
        self.inline_if_possible();
    }

    /// Drops the text before byte index `idx`, shifting the
    /// rest of the text to fill in the space.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate_front(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        unsafe {
            self.remove_bytes(0, idx);
        }
    }

    /// Removes the text in the byte index interval `[start, end)`.
    ///
    /// Panics if either `start` or `end` are not char boundaries, as that
    /// would result in an invalid utf8 string.
    pub fn remove_range(&mut self, start: usize, end: usize) {
        assert!(self.is_char_boundary(start));
        assert!(self.is_char_boundary(end));
        debug_assert!(end <= self.len());
        debug_assert!(start <= end);
        unsafe {
            self.remove_bytes(start, end);
        }
        self.inline_if_possible();
    }

    pub fn remove_char_range(&mut self, start: usize, end: usize) {
        debug_assert!(start <= end);
        debug_assert!(end <= count_chars(self));

        let byte_start = char_idx_to_byte_idx(self, start);
        let byte_end = char_idx_to_byte_idx(&self[start..], end - start);

        unsafe { self.remove_bytes(byte_start, byte_end) }
        self.inline_if_possible();
    }

    /// Splits the `NodeText` at `idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn split_off(&mut self, idx: usize) -> Self {
        assert!(self.is_char_boundary(idx));
        assert!(idx <= self.len());
        let len = self.len();
        let mut other = NodeText::with_capacity(len - idx);
        unsafe {
            ptr::copy_nonoverlapping(
                self.buffer.as_ptr().offset(idx as isize),
                other.buffer.as_mut_ptr().offset(0),
                len - idx,
            );
            self.buffer.set_len(idx);
            other.buffer.set_len(len - idx);
        }
        self.inline_if_possible();
        other
    }

    /// Splits a string into two strings at the char index given.
    /// The first section of the split is stored in the original string,
    /// while the second section of the split is returned as a new string.
    pub fn split_off_at_char(&mut self, char_idx: usize) -> Self {
        debug_assert!(char_idx <= count_chars(self));
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.split_off(byte_idx)
    }

    #[inline(always)]
    pub fn shrink_to_fit(&mut self) {
        self.buffer.shrink_to_fit();
    }

    /// Returns whether the string has spilled out into a heap-allocated
    /// memory area.
    pub fn spilled(&self) -> bool {
        self.buffer.spilled()
    }

    #[inline(always)]
    pub unsafe fn as_mut_smallvec(&mut self) -> &mut SmallVec<BackingArray> {
        &mut self.buffer
    }

    #[inline(always)]
    unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
        assert!(idx <= self.len());
        // debug_assert!((self.len() + bytes.len()) <= MAX_BYTES);

        let len = self.len();
        let amt = bytes.len();
        self.buffer.reserve(amt);

        ptr::copy(
            self.buffer.as_ptr().offset(idx as isize),
            self.buffer.as_mut_ptr().offset((idx + amt) as isize),
            len - idx,
        );
        ptr::copy(
            bytes.as_ptr(),
            self.buffer.as_mut_ptr().offset(idx as isize),
            amt,
        );
        self.buffer.set_len(len + amt);
    }

    #[inline(always)]
    unsafe fn remove_bytes(&mut self, start: usize, end: usize) {
        assert!(start <= end);
        assert!(end <= self.len());
        let len = self.len();
        let amt = end - start;
        ptr::copy(
            self.buffer.as_ptr().offset(end as isize),
            self.buffer.as_mut_ptr().offset(start as isize),
            len - end,
        );
        self.buffer.set_len(len - amt);

        self.inline_if_possible();
    }

    /// Re-inlines the data if it's been heap allocated but can
    /// fit inline.
    #[inline(always)]
    fn inline_if_possible(&mut self) {
        if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
            self.buffer.shrink_to_fit();
        }
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

impl<'a> From<&'a str> for NodeText {
    fn from(s: &str) -> Self {
        Self::from_str(s)
    }
}

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl Borrow<str> for NodeText {
    fn borrow(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

//=======================================================================

/// Takes two `NodeText`s and mends the segment break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is one big grapheme.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    let tot_len = l.len() + r.len();

    // Find the new split position, if any.
    let new_split_pos = {
        let l_split = crlf::prev_break(l.len(), l.as_bytes());
        let r_split = l.len() + crlf::next_break(0, r.as_bytes());
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // debug_assert!(new_split_pos <= MAX_BYTES);
    // debug_assert!((tot_len - new_split_pos) <= MAX_BYTES);

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The backing internal buffer for `NodeText`.
#[derive(Copy, Clone)]
pub(crate) struct BackingArray([u8; MAX_BYTES]);
unsafe impl Array for BackingArray {
    type Item = u8;
    fn size() -> usize {
        MAX_BYTES
    }
    fn ptr(&self) -> *const u8 {
        &self.0[0]
    }
    fn ptr_mut(&mut self) -> *mut u8 {
        &mut self.0[0]
    }
}

//=======================================================================

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

    #[test]
    fn remove_bytes_01() {
        let mut s = NodeText::new();
        s.push_str("Hello!");
        unsafe {
            s.remove_bytes(2, 4);
        }
        assert_eq!("Heo!", s);
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016; Dmitry Roschin
// Licensed under the MIT License <LICENSE.md>
use shared::basetsd::{UINT64};
use shared::guiddef::{IID};
use shared::minwindef::{UINT, ULONG, LPVOID, BOOL, INT, BYTE};
use um::d3dcommon::*;
use um::unknwnbase::{IUnknown, IUnknownVtbl};
use um::winnt::{HRESULT, LPCSTR};

ENUM!{enum D3D12_SHADER_VERSION_TYPE {
    D3D12_SHVER_PIXEL_SHADER = 0x0,
    D3D12_SHVER_VERTEX_SHADER = 0x1,
    D3D12_SHVER_GEOMETRY_SHADER = 0x2,
    D3D12_SHVER_HULL_SHADER = 0x3,
    D3D12_SHVER_DOMAIN_SHADER = 0x4,
    D3D12_SHVER_COMPUTE_SHADER = 0x5,
    D3D12_SHVER_RESERVED0 = 0xFFF0,
}}

STRUCT!{struct D3D12_FUNCTION_DESC {
    Version: UINT,
    Creator: LPCSTR,
    Flags: UINT,
    ConstantBuffers: UINT,
    BoundResources: UINT,
    InstructionCount: UINT,
    TempRegisterCount: UINT,
    TempArrayCount: UINT,
    DefCount: UINT,
    DclCount: UINT,
    TextureNormalInstructions: UINT,
    TextureLoadInstructions: UINT,
    TextureCompInstructions: UINT,
    TextureBiasInstructions: UINT,
    TextureGradientInstructions: UINT,
    FloatInstructionCount: UINT,
    IntInstructionCount: UINT,
    UintInstructionCount: UINT,
    StaticFlowControlCount: UINT,
    DynamicFlowControlCount: UINT,
    MacroInstructionCount: UINT,
    ArrayInstructionCount: UINT,
    MovInstructionCount: UINT,
    MovcInstructionCount: UINT,
    ConversionInstructionCount: UINT,
    BitwiseInstructionCount: UINT,
    MinFeatureLevel: D3D_FEATURE_LEVEL,
    RequiredFeatureFlags: UINT64,
    Name: LPCSTR,
    FunctionParameterCount: INT,
    HasReturn: BOOL,
    Has10Level9VertexShader: BOOL,
    Has10Level9PixelShader: BOOL,
}}

STRUCT!{struct D3D12_LIBRARY_DESC {
    Creator: LPCSTR,
    Flags: UINT,
    FunctionCount: UINT,
}}

STRUCT!{struct D3D12_PARAMETER_DESC {
    Name: LPCSTR,
    SemanticName: LPCSTR,
    Type: D3D_SHADER_VARIABLE_TYPE,
    Class: D3D_SHADER_VARIABLE_CLASS,
    Rows: UINT,
    Columns: UINT,
    InterpolationMode: D3D_INTERPOLATION_MODE,
    Flags: D3D_PARAMETER_FLAGS,
    FirstInRegister: UINT,
    FirstInComponent: UINT,
    FirstOutRegister: UINT,
    FirstOutComponent: UINT,
}}

STRUCT!{struct D3D12_SHADER_BUFFER_DESC {
    Name: LPCSTR,
    Type: D3D_CBUFFER_TYPE,
    Variables: UINT,
    Size: UINT,
    uFlags: UINT,
}}

STRUCT!{struct D3D12_SHADER_DESC {
    Version: UINT,
    Creator: LPCSTR,
    Flags: UINT,
    ConstantBuffers: UINT,
    BoundResources: UINT,
    InputParameters: UINT,
    OutputParameters: UINT,
    InstructionCount: UINT,
    TempRegisterCount: UINT,
    TempArrayCount: UINT,
    DefCount: UINT,
    DclCount: UINT,
    TextureNormalInstructions: UINT,
    TextureLoadInstructions: UINT,
    TextureCompInstructions: UINT,
    TextureBiasInstructions: UINT,
    TextureGradientInstructions: UINT,
    FloatInstructionCount: UINT,
    IntInstructionCount: UINT,
    UintInstructionCount: UINT,
    StaticFlowControlCount: UINT,
    DynamicFlowControlCount: UINT,
    MacroInstructionCount: UINT,
    ArrayInstructionCount: UINT,
    CutInstructionCount: UINT,
    EmitInstructionCount: UINT,
    GSOutputTopology: D3D_PRIMITIVE_TOPOLOGY,
    GSMaxOutputVertexCount: UINT,
    InputPrimitive: D3D_PRIMITIVE,
    PatchConstantParameters: UINT,
    cGSInstanceCount: UINT,
    cControlPoints: UINT,
    HSOutputPrimitive: D3D_TESSELLATOR_OUTPUT_PRIMITIVE,
    HSPartitioning: D3D_TESSELLATOR_PARTITIONING,
    TessellatorDomain: D3D_TESSELLATOR_DOMAIN,
    cBarrierInstructions: UINT,
    cInterlockedInstructions: UINT,
    cTextureStoreInstructions: UINT,
}}

STRUCT!{struct D3D12_SHADER_INPUT_BIND_DESC {
    Name: LPCSTR,
    Type: D3D_SHADER_INPUT_TYPE,
    BindPoint: UINT,
    BindCount: UINT,
    uFlags: UINT,
    ReturnType: D3D_RESOURCE_RETURN_TYPE,
    Dimension: D3D_SRV_DIMENSION,
    NumSamples: UINT,
    Space: UINT,
    uID: UINT,
}}

STRUCT!{struct D3D12_SHADER_TYPE_DESC {
    Class: D3D_SHADER_VARIABLE_CLASS,
    Type: D3D_SHADER_VARIABLE_TYPE,
    Rows: UINT,
    Columns: UINT,
    Elements: UINT,
    Members: UINT,
    Offset: UINT,
    Name: LPCSTR,
}}

STRUCT!{struct D3D12_SHADER_VARIABLE_DESC {
    Name: LPCSTR,
    StartOffset: UINT,
    Size: UINT,
    uFlags: UINT,
    DefaultValue: LPVOID,
    StartTexture: UINT,
    TextureSize: UINT,
    StartSampler: UINT,
    SamplerSize: UINT,
}}

STRUCT!{struct D3D12_SIGNATURE_PARAMETER_DESC {
    SemanticName: LPCSTR,
    SemanticIndex: UINT,
    Register: UINT,
    SystemValueType: D3D_NAME,
    ComponentType: D3D_REGISTER_COMPONENT_TYPE,
    Mask: BYTE,
    ReadWriteMask: BYTE,
    Stream: UINT,
    MinPrecision: D3D_MIN_PRECISION,
}}

RIDL!{#[uuid(0xec25f42d, 0x7006, 0x4f2b, 0xb3, 0x3e, 0x02, 0xcc, 0x33, 0x75, 0x73, 0x3f)]
interface ID3D12FunctionParameterReflection(ID3D12FunctionParameterReflectionVtbl) {
    fn GetDesc(pDesc: *mut D3D12_PARAMETER_DESC) -> HRESULT
}}

RIDL!{#[uuid(0x1108795c, 0x2772, 0x4ba9, 0xb2, 0xa8, 0xd4, 0x64, 0xdc, 0x7e, 0x27, 0x99)]
interface ID3D12FunctionReflection(ID3D12FunctionReflectionVtbl) {
    fn GetDesc(pDesc: *mut D3D12_FUNCTION_DESC) -> HRESULT,
    fn GetConstantBufferByIndex(
        BufferIndex: UINT
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetConstantBufferByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetResourceBindingDesc(
        ResourceIndex: UINT, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetVariableByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionVariable,
    fn GetResourceBindingDescByName(
        Name: LPCSTR, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetFunctionParameter(
        ParameterIndex: INT
    ) -> *mut ID3D12FunctionParameterReflection
}}

RIDL!(#[uuid(0x8e349d19, 0x54db, 0x4a56, 0x9d, 0xc9, 0x11, 0x9d, 0x87, 0xbd, 0xb8, 0x4)]
interface ID3D12LibraryReflection(ID3D12LibraryReflectionVtbl): IUnknown(IUnknownVtbl) {
    fn GetDesc(pDesc: *mut D3D12_LIBRARY_DESC) -> HRESULT,
    fn GetFunctionByIndex(
        FunctionIndex: INT
    ) -> *mut ID3D12FunctionReflection
});

RIDL!{#[uuid(0xc59598b4, 0x48b3, 0x4869, 0xb9, 0xb1, 0xb1, 0x61, 0x8b, 0x14, 0xa8, 0xb7)]
interface ID3D12ShaderReflectionConstantBuffer(ID3D12ShaderReflectionConstantBufferVtbl) {
    fn GetDesc(pDesc: *mut D3D12_SHADER_BUFFER_DESC) -> HRESULT,
    fn GetVariableByIndex(
        Index: UINT
    ) -> *mut ID3D12ShaderReflectionVariable,
    fn GetVariableByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionVariable
}}

RIDL!{#[uuid(0xe913c351, 0x783d, 0x48ca, 0xa1, 0xd1, 0x4f, 0x30, 0x62, 0x84, 0xad, 0x56)]
interface ID3D12ShaderReflectionType(ID3D12ShaderReflectionTypeVtbl) {
    fn GetDesc(pDesc: *mut D3D12_SHADER_TYPE_DESC) -> HRESULT,
    fn GetMemberTypeByIndex(
        Index: UINT
    ) -> *mut ID3D12ShaderReflectionType,
    fn GetMemberTypeByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionType,
    fn GetMemberTypeName(Index: UINT) -> LPCSTR,
    fn IsEqual(
        pType: *mut ID3D12ShaderReflectionType
    ) -> HRESULT,
    fn GetSubType() -> *mut ID3D12ShaderReflectionType,
    fn GetBaseClass() -> *mut ID3D12ShaderReflectionType,
    fn GetNumInterfaces() -> UINT,
    fn GetInterfaceByIndex(
        uIndex: UINT
    ) -> *mut ID3D12ShaderReflectionType,
    fn IsOfType(
        pType: *mut ID3D12ShaderReflectionType
    ) -> HRESULT,
    fn ImplementsInterface(
        pBase: *mut ID3D12ShaderReflectionType
    ) -> HRESULT
}}

RIDL!{#[uuid(0x8337a8a6, 0xa216, 0x444a, 0xb2, 0xf4, 0x31, 0x47, 0x33, 0xa7, 0x3a, 0xea)]
interface ID3D12ShaderReflectionVariable(ID3D12ShaderReflectionVariableVtbl) {
    fn GetDesc(
        pDesc: *mut D3D12_SHADER_VARIABLE_DESC
    ) -> HRESULT,
    fn GetType() -> *mut ID3D12ShaderReflectionType,
    fn GetBuffer() -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetInterfaceSlot(uArrayIndex: UINT) -> UINT
}}

RIDL!(#[uuid(0x5a58797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e)]
interface ID3D12ShaderReflection(ID3D12ShaderReflectionVtbl): IUnknown(IUnknownVtbl) {
    fn GetDesc(pDesc: *mut D3D12_SHADER_DESC) -> HRESULT,
    fn GetConstantBufferByIndex(
        Index: UINT
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetConstantBufferByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetResourceBindingDesc(
        ResourceIndex: UINT, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetInputParameterDesc(
        ParameterIndex: UINT, pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC
    ) -> HRESULT,
    fn GetOutputParameterDesc(
        ParameterIndex: UINT, pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC
    ) -> HRESULT,
    fn GetPatchConstantParameterDesc(
        ParameterIndex: UINT, pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC
    ) -> HRESULT,
    fn GetVariableByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionVariable,
    fn GetResourceBindingDescByName(
        Name: LPCSTR, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetMovInstructionCount() -> UINT,
    fn GetMovcInstructionCount() -> UINT,
    fn GetConversionInstructionCount() -> UINT,
    fn GetBitwiseInstructionCount() -> UINT,
    fn GetGSInputPrimitive() -> D3D_PRIMITIVE,
    fn IsSampleFrequencyShader() -> BOOL,
    fn GetNumInterfaceSlots() -> UINT,
    fn GetMinFeatureLevel(
        pLevel: *mut D3D_FEATURE_LEVEL
    ) -> HRESULT,
    fn GetThreadGroupSize(
        pSizeX: *mut UINT, pSizeY: *mut UINT, pSizeZ: *mut UINT
    ) -> UINT,
    fn GetRequiresFlags() -> UINT64
});

pub type D3D12_CBUFFER_TYPE = D3D_CBUFFER_TYPE;
pub type D3D12_RESOURCE_RETURN_TYPE = D3D_RESOURCE_RETURN_TYPE;
pub type D3D12_TESSELLATOR_DOMAIN = D3D_TESSELLATOR_DOMAIN;
pub type D3D12_TESSELLATOR_OUTPUT_PRIMITIVE = D3D_TESSELLATOR_OUTPUT_PRIMITIVE;
pub type D3D12_TESSELLATOR_PARTITIONING = D3D_TESSELLATOR_PARTITIONING;
pub type LPD3D12FUNCTIONPARAMETERREFLECTION = *mut ID3D12FunctionParameterReflection;
pub type LPD3D12FUNCTIONREFLECTION = *mut ID3D12FunctionReflection;
pub type LPD3D12LIBRARYREFLECTION = *mut ID3D12LibraryReflection;
pub type LPD3D12SHADERREFLECTION = *mut ID3D12ShaderReflection;
pub type LPD3D12SHADERREFLECTIONCONSTANTBUFFER = *mut ID3D12ShaderReflectionConstantBuffer;
pub type LPD3D12SHADERREFLECTIONTYPE = *mut ID3D12ShaderReflectionType;
pub type LPD3D12SHADERREFLECTIONVARIABLE = *mut ID3D12ShaderReflectionVariable;
pub const D3D_SHADER_REQUIRES_INNER_COVERAGE: UINT64 = 0x00000400;
pub const D3D_SHADER_REQUIRES_ROVS: UINT64 = 0x00001000;
pub const D3D_SHADER_REQUIRES_STENCIL_REF: UINT64 = 0x00000200;
pub const D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS: UINT64 = 0x00000800;
pub const D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER: UINT64 = 0x00002000;
<commit_msg>Must remember to test before pushing changes<commit_after>// Copyright © 2016; Dmitry Roschin
// Licensed under the MIT License <LICENSE.md>
use shared::basetsd::{UINT64};
use shared::minwindef::{UINT, LPVOID, BOOL, INT, BYTE};
use um::d3dcommon::*;
use um::unknwnbase::{IUnknown, IUnknownVtbl};
use um::winnt::{HRESULT, LPCSTR};

ENUM!{enum D3D12_SHADER_VERSION_TYPE {
    D3D12_SHVER_PIXEL_SHADER = 0x0,
    D3D12_SHVER_VERTEX_SHADER = 0x1,
    D3D12_SHVER_GEOMETRY_SHADER = 0x2,
    D3D12_SHVER_HULL_SHADER = 0x3,
    D3D12_SHVER_DOMAIN_SHADER = 0x4,
    D3D12_SHVER_COMPUTE_SHADER = 0x5,
    D3D12_SHVER_RESERVED0 = 0xFFF0,
}}

STRUCT!{struct D3D12_FUNCTION_DESC {
    Version: UINT,
    Creator: LPCSTR,
    Flags: UINT,
    ConstantBuffers: UINT,
    BoundResources: UINT,
    InstructionCount: UINT,
    TempRegisterCount: UINT,
    TempArrayCount: UINT,
    DefCount: UINT,
    DclCount: UINT,
    TextureNormalInstructions: UINT,
    TextureLoadInstructions: UINT,
    TextureCompInstructions: UINT,
    TextureBiasInstructions: UINT,
    TextureGradientInstructions: UINT,
    FloatInstructionCount: UINT,
    IntInstructionCount: UINT,
    UintInstructionCount: UINT,
    StaticFlowControlCount: UINT,
    DynamicFlowControlCount: UINT,
    MacroInstructionCount: UINT,
    ArrayInstructionCount: UINT,
    MovInstructionCount: UINT,
    MovcInstructionCount: UINT,
    ConversionInstructionCount: UINT,
    BitwiseInstructionCount: UINT,
    MinFeatureLevel: D3D_FEATURE_LEVEL,
    RequiredFeatureFlags: UINT64,
    Name: LPCSTR,
    FunctionParameterCount: INT,
    HasReturn: BOOL,
    Has10Level9VertexShader: BOOL,
    Has10Level9PixelShader: BOOL,
}}

STRUCT!{struct D3D12_LIBRARY_DESC {
    Creator: LPCSTR,
    Flags: UINT,
    FunctionCount: UINT,
}}

STRUCT!{struct D3D12_PARAMETER_DESC {
    Name: LPCSTR,
    SemanticName: LPCSTR,
    Type: D3D_SHADER_VARIABLE_TYPE,
    Class: D3D_SHADER_VARIABLE_CLASS,
    Rows: UINT,
    Columns: UINT,
    InterpolationMode: D3D_INTERPOLATION_MODE,
    Flags: D3D_PARAMETER_FLAGS,
    FirstInRegister: UINT,
    FirstInComponent: UINT,
    FirstOutRegister: UINT,
    FirstOutComponent: UINT,
}}

STRUCT!{struct D3D12_SHADER_BUFFER_DESC {
    Name: LPCSTR,
    Type: D3D_CBUFFER_TYPE,
    Variables: UINT,
    Size: UINT,
    uFlags: UINT,
}}

STRUCT!{struct D3D12_SHADER_DESC {
    Version: UINT,
    Creator: LPCSTR,
    Flags: UINT,
    ConstantBuffers: UINT,
    BoundResources: UINT,
    InputParameters: UINT,
    OutputParameters: UINT,
    InstructionCount: UINT,
    TempRegisterCount: UINT,
    TempArrayCount: UINT,
    DefCount: UINT,
    DclCount: UINT,
    TextureNormalInstructions: UINT,
    TextureLoadInstructions: UINT,
    TextureCompInstructions: UINT,
    TextureBiasInstructions: UINT,
    TextureGradientInstructions: UINT,
    FloatInstructionCount: UINT,
    IntInstructionCount: UINT,
    UintInstructionCount: UINT,
    StaticFlowControlCount: UINT,
    DynamicFlowControlCount: UINT,
    MacroInstructionCount: UINT,
    ArrayInstructionCount: UINT,
    CutInstructionCount: UINT,
    EmitInstructionCount: UINT,
    GSOutputTopology: D3D_PRIMITIVE_TOPOLOGY,
    GSMaxOutputVertexCount: UINT,
    InputPrimitive: D3D_PRIMITIVE,
    PatchConstantParameters: UINT,
    cGSInstanceCount: UINT,
    cControlPoints: UINT,
    HSOutputPrimitive: D3D_TESSELLATOR_OUTPUT_PRIMITIVE,
    HSPartitioning: D3D_TESSELLATOR_PARTITIONING,
    TessellatorDomain: D3D_TESSELLATOR_DOMAIN,
    cBarrierInstructions: UINT,
    cInterlockedInstructions: UINT,
    cTextureStoreInstructions: UINT,
}}

STRUCT!{struct D3D12_SHADER_INPUT_BIND_DESC {
    Name: LPCSTR,
    Type: D3D_SHADER_INPUT_TYPE,
    BindPoint: UINT,
    BindCount: UINT,
    uFlags: UINT,
    ReturnType: D3D_RESOURCE_RETURN_TYPE,
    Dimension: D3D_SRV_DIMENSION,
    NumSamples: UINT,
    Space: UINT,
    uID: UINT,
}}

STRUCT!{struct D3D12_SHADER_TYPE_DESC {
    Class: D3D_SHADER_VARIABLE_CLASS,
    Type: D3D_SHADER_VARIABLE_TYPE,
    Rows: UINT,
    Columns: UINT,
    Elements: UINT,
    Members: UINT,
    Offset: UINT,
    Name: LPCSTR,
}}

STRUCT!{struct D3D12_SHADER_VARIABLE_DESC {
    Name: LPCSTR,
    StartOffset: UINT,
    Size: UINT,
    uFlags: UINT,
    DefaultValue: LPVOID,
    StartTexture: UINT,
    TextureSize: UINT,
    StartSampler: UINT,
    SamplerSize: UINT,
}}

STRUCT!{struct D3D12_SIGNATURE_PARAMETER_DESC {
    SemanticName: LPCSTR,
    SemanticIndex: UINT,
    Register: UINT,
    SystemValueType: D3D_NAME,
    ComponentType: D3D_REGISTER_COMPONENT_TYPE,
    Mask: BYTE,
    ReadWriteMask: BYTE,
    Stream: UINT,
    MinPrecision: D3D_MIN_PRECISION,
}}

RIDL!{#[uuid(0xec25f42d, 0x7006, 0x4f2b, 0xb3, 0x3e, 0x02, 0xcc, 0x33, 0x75, 0x73, 0x3f)]
interface ID3D12FunctionParameterReflection(ID3D12FunctionParameterReflectionVtbl) {
    fn GetDesc(pDesc: *mut D3D12_PARAMETER_DESC) -> HRESULT
}}

RIDL!{#[uuid(0x1108795c, 0x2772, 0x4ba9, 0xb2, 0xa8, 0xd4, 0x64, 0xdc, 0x7e, 0x27, 0x99)]
interface ID3D12FunctionReflection(ID3D12FunctionReflectionVtbl) {
    fn GetDesc(pDesc: *mut D3D12_FUNCTION_DESC) -> HRESULT,
    fn GetConstantBufferByIndex(
        BufferIndex: UINT
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetConstantBufferByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetResourceBindingDesc(
        ResourceIndex: UINT, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetVariableByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionVariable,
    fn GetResourceBindingDescByName(
        Name: LPCSTR, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetFunctionParameter(
        ParameterIndex: INT
    ) -> *mut ID3D12FunctionParameterReflection
}}

RIDL!(#[uuid(0x8e349d19, 0x54db, 0x4a56, 0x9d, 0xc9, 0x11, 0x9d, 0x87, 0xbd, 0xb8, 0x4)]
interface ID3D12LibraryReflection(ID3D12LibraryReflectionVtbl): IUnknown(IUnknownVtbl) {
    fn GetDesc(pDesc: *mut D3D12_LIBRARY_DESC) -> HRESULT,
    fn GetFunctionByIndex(
        FunctionIndex: INT
    ) -> *mut ID3D12FunctionReflection
});

RIDL!{#[uuid(0xc59598b4, 0x48b3, 0x4869, 0xb9, 0xb1, 0xb1, 0x61, 0x8b, 0x14, 0xa8, 0xb7)]
interface ID3D12ShaderReflectionConstantBuffer(ID3D12ShaderReflectionConstantBufferVtbl) {
    fn GetDesc(pDesc: *mut D3D12_SHADER_BUFFER_DESC) -> HRESULT,
    fn GetVariableByIndex(
        Index: UINT
    ) -> *mut ID3D12ShaderReflectionVariable,
    fn GetVariableByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionVariable
}}

RIDL!{#[uuid(0xe913c351, 0x783d, 0x48ca, 0xa1, 0xd1, 0x4f, 0x30, 0x62, 0x84, 0xad, 0x56)]
interface ID3D12ShaderReflectionType(ID3D12ShaderReflectionTypeVtbl) {
    fn GetDesc(pDesc: *mut D3D12_SHADER_TYPE_DESC) -> HRESULT,
    fn GetMemberTypeByIndex(
        Index: UINT
    ) -> *mut ID3D12ShaderReflectionType,
    fn GetMemberTypeByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionType,
    fn GetMemberTypeName(Index: UINT) -> LPCSTR,
    fn IsEqual(
        pType: *mut ID3D12ShaderReflectionType
    ) -> HRESULT,
    fn GetSubType() -> *mut ID3D12ShaderReflectionType,
    fn GetBaseClass() -> *mut ID3D12ShaderReflectionType,
    fn GetNumInterfaces() -> UINT,
    fn GetInterfaceByIndex(
        uIndex: UINT
    ) -> *mut ID3D12ShaderReflectionType,
    fn IsOfType(
        pType: *mut ID3D12ShaderReflectionType
    ) -> HRESULT,
    fn ImplementsInterface(
        pBase: *mut ID3D12ShaderReflectionType
    ) -> HRESULT
}}

RIDL!{#[uuid(0x8337a8a6, 0xa216, 0x444a, 0xb2, 0xf4, 0x31, 0x47, 0x33, 0xa7, 0x3a, 0xea)]
interface ID3D12ShaderReflectionVariable(ID3D12ShaderReflectionVariableVtbl) {
    fn GetDesc(
        pDesc: *mut D3D12_SHADER_VARIABLE_DESC
    ) -> HRESULT,
    fn GetType() -> *mut ID3D12ShaderReflectionType,
    fn GetBuffer() -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetInterfaceSlot(uArrayIndex: UINT) -> UINT
}}

RIDL!(#[uuid(0x5a58797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e)]
interface ID3D12ShaderReflection(ID3D12ShaderReflectionVtbl): IUnknown(IUnknownVtbl) {
    fn GetDesc(pDesc: *mut D3D12_SHADER_DESC) -> HRESULT,
    fn GetConstantBufferByIndex(
        Index: UINT
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetConstantBufferByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionConstantBuffer,
    fn GetResourceBindingDesc(
        ResourceIndex: UINT, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetInputParameterDesc(
        ParameterIndex: UINT, pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC
    ) -> HRESULT,
    fn GetOutputParameterDesc(
        ParameterIndex: UINT, pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC
    ) -> HRESULT,
    fn GetPatchConstantParameterDesc(
        ParameterIndex: UINT, pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC
    ) -> HRESULT,
    fn GetVariableByName(
        Name: LPCSTR
    ) -> *mut ID3D12ShaderReflectionVariable,
    fn GetResourceBindingDescByName(
        Name: LPCSTR, pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC
    ) -> HRESULT,
    fn GetMovInstructionCount() -> UINT,
    fn GetMovcInstructionCount() -> UINT,
    fn GetConversionInstructionCount() -> UINT,
    fn GetBitwiseInstructionCount() -> UINT,
    fn GetGSInputPrimitive() -> D3D_PRIMITIVE,
    fn IsSampleFrequencyShader() -> BOOL,
    fn GetNumInterfaceSlots() -> UINT,
    fn GetMinFeatureLevel(
        pLevel: *mut D3D_FEATURE_LEVEL
    ) -> HRESULT,
    fn GetThreadGroupSize(
        pSizeX: *mut UINT, pSizeY: *mut UINT, pSizeZ: *mut UINT
    ) -> UINT,
    fn GetRequiresFlags() -> UINT64
});

pub type D3D12_CBUFFER_TYPE = D3D_CBUFFER_TYPE;
pub type D3D12_RESOURCE_RETURN_TYPE = D3D_RESOURCE_RETURN_TYPE;
pub type D3D12_TESSELLATOR_DOMAIN = D3D_TESSELLATOR_DOMAIN;
pub type D3D12_TESSELLATOR_OUTPUT_PRIMITIVE = D3D_TESSELLATOR_OUTPUT_PRIMITIVE;
pub type D3D12_TESSELLATOR_PARTITIONING = D3D_TESSELLATOR_PARTITIONING;
pub type LPD3D12FUNCTIONPARAMETERREFLECTION = *mut ID3D12FunctionParameterReflection;
pub type LPD3D12FUNCTIONREFLECTION = *mut ID3D12FunctionReflection;
pub type LPD3D12LIBRARYREFLECTION = *mut ID3D12LibraryReflection;
pub type LPD3D12SHADERREFLECTION = *mut ID3D12ShaderReflection;
pub type LPD3D12SHADERREFLECTIONCONSTANTBUFFER = *mut ID3D12ShaderReflectionConstantBuffer;
pub type LPD3D12SHADERREFLECTIONTYPE = *mut ID3D12ShaderReflectionType;
pub type LPD3D12SHADERREFLECTIONVARIABLE = *mut ID3D12ShaderReflectionVariable;
pub const D3D_SHADER_REQUIRES_INNER_COVERAGE: UINT64 = 0x00000400;
pub const D3D_SHADER_REQUIRES_ROVS: UINT64 = 0x00001000;
pub const D3D_SHADER_REQUIRES_STENCIL_REF: UINT64 = 0x00000200;
pub const D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS: UINT64 = 0x00000800;
pub const D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER: UINT64 = 0x00002000;
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use c_ares;
use mio;

use error::Error;
use eventloop::EventLoopHandle;

// The EventLoop will set up a mio::Poll and use it to wait for the following:
//
// -  messages telling it which file descriptors it should be interested in.
//    These file descriptors are then registered (or deregistered) with the
//    mio::Poll as required.
//
// -  events telling it that something has happened on one of these file
//    descriptors.  When this happens, it tells the c_ares::Channel about it.
//
// -  a message telling it to shut down.
pub struct EventLoop {
    poll: mio::Poll,
    tx_msg_channel: mio::channel::Sender<Message>,
    rx_msg_channel: mio::channel::Receiver<Message>,
    tracked_fds: HashSet<c_ares::Socket>,
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
pub enum Message {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

// A token identifying that the message channel has become available for reading.
//
// We use Token(fd) for file descriptors, so this relies on zero not being a
// valid file descriptor for c-ares to use.  Zero is stdin, so that's true.
const CHANNEL: mio::Token = mio::Token(0);

impl EventLoop {
    // Create a new event loop.
    pub fn new(mut options: c_ares::Options) -> Result<EventLoop, Error> {
        // Create a mio::Poll on which to wait for events, and register a
        // channel with it.
        let poll = mio::Poll::new()?;
        let (tx, rx) = mio::channel::channel();
        poll.register(
            &rx,
            CHANNEL,
            mio::Ready::readable(),
            mio::PollOpt::edge()
        )?;

        // Whenever c-ares tells us what to do with a file descriptor, we'll
        // send that request along, through the channel we just created.
        let tx_clone = tx.clone();
        let sock_callback =
            move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(
                    Message::RegisterInterest(fd, readable, writable));
            };
        options.set_socket_state_callback(sock_callback);

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::new(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            poll: poll,
            tx_msg_channel: tx,
            rx_msg_channel: rx,
            tracked_fds: HashSet::<c_ares::Socket>::new(),
            ares_channel: locked_channel,
            quit: false,
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopHandle {
        let tx_clone = self.tx_msg_channel.clone();
        let join_handle = thread::spawn(|| self.event_loop_thread());
        EventLoopHandle::new(join_handle, tx_clone)
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = mio::Events::with_capacity(16);
        loop {
            // Wait for something to happen.
            let timeout = Duration::from_millis(100);
            let results = self.poll
                .poll(&mut events, Some(timeout))
                .expect("poll failed");

            // Process whatever happened.
            match results {
                0 => {
                    // No events - must be a timeout.  Tell c-ares about it.
                    self.ares_channel.lock().unwrap().process_fd(
                        c_ares::SOCKET_BAD,
                        c_ares::SOCKET_BAD
                    );
                },
                _ => {
                    // Process events.  One of them might have asked us to quit.
                    for event in &events {
                        self.handle_event(&event);
                        if self.quit { return }
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &mio::Event) {
        match event.token() {
            CHANNEL => {
                // The channel is readable.
                self.handle_messages()
            },

            mio::Token(fd) => {
                // Sockets became readable or writable - tell c-ares.
                let rfd = if event.kind().is_readable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                let wfd = if event.kind().is_writable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
            }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        loop {
            match self.rx_msg_channel.try_recv() {
                Ok(Message::RegisterInterest(fd, readable, writable)) => {
                    // Instruction to do something with a file descriptor.
                    let efd = mio::unix::EventedFd(&fd);
                    if !readable && !writable {
                        self.tracked_fds.remove(&fd);
                        let _ = self.poll.deregister(&efd);
                    } else {
                        let token = mio::Token(fd as usize);
                        let mut interest = mio::Ready::none();
                        if readable { interest.insert(mio::Ready::readable()) }
                        if writable { interest.insert(mio::Ready::writable()) }
                        let register_result = if !self.tracked_fds.insert(fd) {
                            self.poll.reregister(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge()
                            )
                        } else {
                            self.poll.register(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::edge()
                            )
                        };
                        register_result.expect("failed to register interest");
                    }
                },

                Ok(Message::ShutDown) => {
                    // Instruction to shut down.
                    self.quit = true;
                    break
                },

                // No more instructions.
                Err(_) => break,
            }
        }
    }
}
<commit_msg>Want level-triggered polling, not edge-triggered<commit_after>use std::collections::HashSet;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use c_ares;
use mio;

use error::Error;
use eventloop::EventLoopHandle;

// The EventLoop will set up a mio::Poll and use it to wait for the following:
//
// -  messages telling it which file descriptors it should be interested in.
//    These file descriptors are then registered (or deregistered) with the
//    mio::Poll as required.
//
// -  events telling it that something has happened on one of these file
//    descriptors.  When this happens, it tells the c_ares::Channel about it.
//
// -  a message telling it to shut down.
pub struct EventLoop {
    poll: mio::Poll,
    tx_msg_channel: mio::channel::Sender<Message>,
    rx_msg_channel: mio::channel::Receiver<Message>,
    tracked_fds: HashSet<c_ares::Socket>,
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
pub enum Message {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

// A token identifying that the message channel has become available for reading.
//
// We use Token(fd) for file descriptors, so this relies on zero not being a
// valid file descriptor for c-ares to use.  Zero is stdin, so that's true.
const CHANNEL: mio::Token = mio::Token(0);

impl EventLoop {
    // Create a new event loop.
    pub fn new(mut options: c_ares::Options) -> Result<EventLoop, Error> {
        // Create a mio::Poll on which to wait for events, and register a
        // channel with it.
        let poll = mio::Poll::new()?;
        let (tx, rx) = mio::channel::channel();
        poll.register(
            &rx,
            CHANNEL,
            mio::Ready::readable(),
            mio::PollOpt::edge()
        )?;

        // Whenever c-ares tells us what to do with a file descriptor, we'll
        // send that request along, through the channel we just created.
        let tx_clone = tx.clone();
        let sock_callback =
            move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(
                    Message::RegisterInterest(fd, readable, writable));
            };
        options.set_socket_state_callback(sock_callback);

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::new(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            poll: poll,
            tx_msg_channel: tx,
            rx_msg_channel: rx,
            tracked_fds: HashSet::<c_ares::Socket>::new(),
            ares_channel: locked_channel,
            quit: false,
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopHandle {
        let tx_clone = self.tx_msg_channel.clone();
        let join_handle = thread::spawn(|| self.event_loop_thread());
        EventLoopHandle::new(join_handle, tx_clone)
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = mio::Events::with_capacity(16);
        loop {
            // Wait for something to happen.
            let timeout = Duration::from_millis(100);
            let results = self.poll
                .poll(&mut events, Some(timeout))
                .expect("poll failed");

            // Process whatever happened.
            match results {
                0 => {
                    // No events - must be a timeout.  Tell c-ares about it.
                    self.ares_channel.lock().unwrap().process_fd(
                        c_ares::SOCKET_BAD,
                        c_ares::SOCKET_BAD
                    );
                },
                _ => {
                    // Process events.  One of them might have asked us to quit.
                    for event in &events {
                        self.handle_event(&event);
                        if self.quit { return }
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &mio::Event) {
        match event.token() {
            CHANNEL => {
                // The channel is readable.
                self.handle_messages()
            },

            mio::Token(fd) => {
                // Sockets became readable or writable - tell c-ares.
                let rfd = if event.kind().is_readable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                let wfd = if event.kind().is_writable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
            }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        loop {
            match self.rx_msg_channel.try_recv() {
                Ok(Message::RegisterInterest(fd, readable, writable)) => {
                    // Instruction to do something with a file descriptor.
                    let efd = mio::unix::EventedFd(&fd);
                    if !readable && !writable {
                        self.tracked_fds.remove(&fd);
                        let _ = self.poll.deregister(&efd);
                    } else {
                        let token = mio::Token(fd as usize);
                        let mut interest = mio::Ready::none();
                        if readable { interest.insert(mio::Ready::readable()) }
                        if writable { interest.insert(mio::Ready::writable()) }
                        let register_result = if !self.tracked_fds.insert(fd) {
                            self.poll.reregister(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::level()
                            )
                        } else {
                            self.poll.register(
                                &efd,
                                token,
                                interest,
                                mio::PollOpt::level()
                            )
                        };
                        register_result.expect("failed to register interest");
                    }
                },

                Ok(Message::ShutDown) => {
                    // Instruction to shut down.
                    self.quit = true;
                    break
                },

                // No more instructions.
                Err(_) => break,
            }
        }
    }
}
<|endoftext|>