<commit_before>//! Handling of enum discriminants
//!
//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>

use rustc_target::abi::{Int, TagEncoding, Variants};

use crate::prelude::*;

pub(crate) fn codegen_set_discriminant<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    place: CPlace<'tcx>,
    variant_index: VariantIdx,
) {
    let layout = place.layout();
    if layout.for_variant(fx, variant_index).abi.is_uninhabited() {
        return;
    }
    match layout.variants {
        Variants::Single { index } => {
            assert_eq!(index, variant_index);
        }
        Variants::Multiple {
            tag: _,
            tag_field,
            tag_encoding: TagEncoding::Direct,
            variants: _,
        } => {
            let ptr = place.place_field(fx, mir::Field::new(tag_field));
            let to = ty::ScalarInt::try_from_uint(
                layout
                    .ty
                    .discriminant_for_variant(fx.tcx, variant_index)
                    .unwrap()
                    .val,
                ptr.layout().size,
            )
            .unwrap();
            let discr = CValue::const_val(fx, ptr.layout(), to);
            ptr.write_cvalue(fx, discr);
        }
        Variants::Multiple {
            tag: _,
            tag_field,
            tag_encoding:
                TagEncoding::Niche {
                    dataful_variant,
                    ref niche_variants,
                    niche_start,
                },
            variants: _,
        } => {
            if variant_index != dataful_variant {
                let niche = place.place_field(fx, mir::Field::new(tag_field));
                let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                let niche_value = u128::from(niche_value).wrapping_add(niche_start);
                let niche_llval = CValue::const_val(fx, niche.layout(), niche_value.into());
                niche.write_cvalue(fx, niche_llval);
            }
        }
    }
}

pub(crate) fn codegen_get_discriminant<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    value: CValue<'tcx>,
    dest_layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
    let layout = value.layout();

    if layout.abi == Abi::Uninhabited {
        return trap_unreachable_ret_value(
            fx,
            dest_layout,
            "[panic] Tried to get discriminant for uninhabited type.",
        );
    }

    let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
        Variants::Single { index } => {
            let discr_val = layout
                .ty
                .discriminant_for_variant(fx.tcx, *index)
                .map_or(u128::from(index.as_u32()), |discr| discr.val);
            return CValue::const_val(fx, dest_layout, discr_val.into());
        }
        Variants::Multiple {
            tag,
            tag_field,
            tag_encoding,
            variants: _,
        } => (tag, *tag_field, tag_encoding),
    };

    let cast_to = fx.clif_type(dest_layout.ty).unwrap();

    // Read the tag/niche-encoded discriminant from memory.
    let tag = value.value_field(fx, mir::Field::new(tag_field));
    let tag = tag.load_scalar(fx);

    // Decode the discriminant (specifically if it's niche-encoded).
    match *tag_encoding {
        TagEncoding::Direct => {
            let signed = match tag_scalar.value {
                Int(_, signed) => signed,
                _ => false,
            };
            let val = clif_intcast(fx, tag, cast_to, signed);
            CValue::by_val(val, dest_layout)
        }
        TagEncoding::Niche {
            dataful_variant,
            ref niche_variants,
            niche_start,
        } => {
            // Rebase from niche values to discriminants, and check
            // whether the result is in range for the niche variants.

            // We first compute the "relative discriminant" (wrt `niche_variants`),
            // that is, if `n = niche_variants.end() - niche_variants.start()`,
            // we remap `niche_start..=niche_start + n` (which may wrap around)
            // to (non-wrap-around) `0..=n`, to be able to check whether the
            // discriminant corresponds to a niche variant with one comparison.
            // We also can't go directly to the (variant index) discriminant
            // and check that it is in the range `niche_variants`, because
            // that might not fit in the same type, on top of needing an extra
            // comparison (see also the comment on `let niche_discr`).
            let relative_discr = if niche_start == 0 {
                tag
            } else {
                // FIXME handle niche_start > i64::MAX
                fx.bcx
                    .ins()
                    .iadd_imm(tag, -i64::try_from(niche_start).unwrap())
            };
            let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
            let is_niche = {
                codegen_icmp_imm(
                    fx,
                    IntCC::UnsignedLessThanOrEqual,
                    relative_discr,
                    i128::from(relative_max),
                )
            };

            // NOTE(eddyb) this addition needs to be performed on the final
            // type, in case the niche itself can't represent all variant
            // indices (e.g. `u8` niche with more than `256` variants,
            // but enough uninhabited variants so that the remaining variants
            // fit in the niche).
            // In other words, `niche_variants.end - niche_variants.start`
            // is representable in the niche, but `niche_variants.end`
            // might not be, in extreme cases.
            let niche_discr = {
                let relative_discr = if relative_max == 0 {
                    // HACK(eddyb) since we have only one niche, we know which
                    // one it is, and we can avoid having a dynamic value here.
                    fx.bcx.ins().iconst(cast_to, 0)
                } else {
                    clif_intcast(fx, relative_discr, cast_to, false)
                };
                fx.bcx
                    .ins()
                    .iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
            };

            let dataful_variant = fx
                .bcx
                .ins()
                .iconst(cast_to, i64::from(dataful_variant.as_u32()));
            let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
            CValue::by_val(discr, dest_layout)
        }
    }
}
<commit_msg>Fix ICE (part 2)<commit_after>//! Handling of enum discriminants
//!
//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>

use rustc_target::abi::{Int, TagEncoding, Variants};

use crate::prelude::*;

pub(crate) fn codegen_set_discriminant<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    place: CPlace<'tcx>,
    variant_index: VariantIdx,
) {
    let layout = place.layout();
    if layout.for_variant(fx, variant_index).abi.is_uninhabited() {
        return;
    }
    match layout.variants {
        Variants::Single { index } => {
            assert_eq!(index, variant_index);
        }
        Variants::Multiple {
            tag: _,
            tag_field,
            tag_encoding: TagEncoding::Direct,
            variants: _,
        } => {
            let ptr = place.place_field(fx, mir::Field::new(tag_field));
            let to = layout
                .ty
                .discriminant_for_variant(fx.tcx, variant_index)
                .unwrap()
                .val;
            let to = if ptr.layout().abi.is_signed() {
                ty::ScalarInt::try_from_int(
                    ptr.layout().size.sign_extend(to) as i128,
                    ptr.layout().size,
                )
                .unwrap()
            } else {
                ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap()
            };
            let discr = CValue::const_val(fx, ptr.layout(), to);
            ptr.write_cvalue(fx, discr);
        }
        Variants::Multiple {
            tag: _,
            tag_field,
            tag_encoding:
                TagEncoding::Niche {
                    dataful_variant,
                    ref niche_variants,
                    niche_start,
                },
            variants: _,
        } => {
            if variant_index != dataful_variant {
                let niche = place.place_field(fx, mir::Field::new(tag_field));
                let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                let niche_value = ty::ScalarInt::try_from_uint(
                    u128::from(niche_value).wrapping_add(niche_start),
                    niche.layout().size,
                )
                .unwrap();
                let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
                niche.write_cvalue(fx, niche_llval);
            }
        }
    }
}

pub(crate) fn codegen_get_discriminant<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    value: CValue<'tcx>,
    dest_layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
    let layout = value.layout();

    if layout.abi == Abi::Uninhabited {
        return trap_unreachable_ret_value(
            fx,
            dest_layout,
            "[panic] Tried to get discriminant for uninhabited type.",
        );
    }

    let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
        Variants::Single { index } => {
            let discr_val = layout
                .ty
                .discriminant_for_variant(fx.tcx, *index)
                .map_or(u128::from(index.as_u32()), |discr| discr.val);
            let discr_val = if dest_layout.abi.is_signed() {
                ty::ScalarInt::try_from_int(
                    dest_layout.size.sign_extend(discr_val) as i128,
                    dest_layout.size,
                )
                .unwrap()
            } else {
                ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap()
            };
            return CValue::const_val(fx, dest_layout, discr_val);
        }
        Variants::Multiple {
            tag,
            tag_field,
            tag_encoding,
            variants: _,
        } => (tag, *tag_field, tag_encoding),
    };

    let cast_to = fx.clif_type(dest_layout.ty).unwrap();

    // Read the tag/niche-encoded discriminant from memory.
    let tag = value.value_field(fx, mir::Field::new(tag_field));
    let tag = tag.load_scalar(fx);

    // Decode the discriminant (specifically if it's niche-encoded).
    match *tag_encoding {
        TagEncoding::Direct => {
            let signed = match tag_scalar.value {
                Int(_, signed) => signed,
                _ => false,
            };
            let val = clif_intcast(fx, tag, cast_to, signed);
            CValue::by_val(val, dest_layout)
        }
        TagEncoding::Niche {
            dataful_variant,
            ref niche_variants,
            niche_start,
        } => {
            // Rebase from niche values to discriminants, and check
            // whether the result is in range for the niche variants.

            // We first compute the "relative discriminant" (wrt `niche_variants`),
            // that is, if `n = niche_variants.end() - niche_variants.start()`,
            // we remap `niche_start..=niche_start + n` (which may wrap around)
            // to (non-wrap-around) `0..=n`, to be able to check whether the
            // discriminant corresponds to a niche variant with one comparison.
            // We also can't go directly to the (variant index) discriminant
            // and check that it is in the range `niche_variants`, because
            // that might not fit in the same type, on top of needing an extra
            // comparison (see also the comment on `let niche_discr`).
            let relative_discr = if niche_start == 0 {
                tag
            } else {
                // FIXME handle niche_start > i64::MAX
                fx.bcx
                    .ins()
                    .iadd_imm(tag, -i64::try_from(niche_start).unwrap())
            };
            let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
            let is_niche = {
                codegen_icmp_imm(
                    fx,
                    IntCC::UnsignedLessThanOrEqual,
                    relative_discr,
                    i128::from(relative_max),
                )
            };

            // NOTE(eddyb) this addition needs to be performed on the final
            // type, in case the niche itself can't represent all variant
            // indices (e.g. `u8` niche with more than `256` variants,
            // but enough uninhabited variants so that the remaining variants
            // fit in the niche).
            // In other words, `niche_variants.end - niche_variants.start`
            // is representable in the niche, but `niche_variants.end`
            // might not be, in extreme cases.
            let niche_discr = {
                let relative_discr = if relative_max == 0 {
                    // HACK(eddyb) since we have only one niche, we know which
                    // one it is, and we can avoid having a dynamic value here.
                    fx.bcx.ins().iconst(cast_to, 0)
                } else {
                    clif_intcast(fx, relative_discr, cast_to, false)
                };
                fx.bcx
                    .ins()
                    .iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
            };

            let dataful_variant = fx
                .bcx
                .ins()
                .iconst(cast_to, i64::from(dataful_variant.as_u32()));
            let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
            CValue::by_val(discr, dest_layout)
        }
    }
}
<|endoftext|>


<commit_before>use db::Pool;
use rocket::{self, Rocket, Request};
use rocket_contrib::{JSON, Value};

mod teams;
mod members;

pub fn app(pool: Pool) -> Rocket {
    rocket::ignite()
        .manage(pool)
        .mount("/teams", teams::routes())
        .mount("/members", members::routes())
        .catch(errors![not_found, server_error])
}

#[error(404)]
fn not_found(_req: &Request) -> JSON<Value> {
    JSON(json!({ "message": "Not Found" }))
}

#[error(500)]
fn server_error(_req: &Request) -> JSON<Value> {
    JSON(json!({ "message": "Internal Server Error" }))
}
<commit_msg>feat: Configure Rocket to log minimally<commit_after>use db::Pool;
use rocket::{self, Rocket, Request};
use rocket_contrib::{JSON, Value};
use std::env;

mod teams;
mod members;

pub fn app(pool: Pool) -> Rocket {
    set_log_level();
    rocket::ignite()
        .manage(pool)
        .mount("/teams", teams::routes())
        .mount("/members", members::routes())
        .catch(errors![not_found, server_error])
}

#[error(404)]
fn not_found(_req: &Request) -> JSON<Value> {
    JSON(json!({ "message": "Not Found" }))
}

#[error(500)]
fn server_error(_req: &Request) -> JSON<Value> {
    JSON(json!({ "message": "Internal Server Error" }))
}

fn set_log_level() {
    env::set_var("ROCKET_LOG", "critical");
}
<|endoftext|>


<commit_before>extern crate pancurses;

use backend;
use event::{Event, Key};

use self::super::find_closest;
use theme::{Color, ColorStyle, Effect};

pub struct Concrete {
    window: pancurses::Window,
}

impl backend::Backend for Concrete {
    fn init() -> Self {
        ::std::env::set_var("ESCDELAY", "25");
        let window = pancurses::initscr();
        window.keypad(true);
        pancurses::noecho();
        pancurses::cbreak();
        pancurses::start_color();
        pancurses::curs_set(0);
        window.bkgd(pancurses::COLOR_PAIR(ColorStyle::Background.id() as u64));

        Concrete { window: window }
    }

    fn screen_size(&self) -> (usize, usize) {
        let (x, y) = self.window.get_max_yx();
        (x as usize, y as usize)
    }

    fn has_colors(&self) -> bool {
        pancurses::has_colors()
    }

    fn finish(&mut self) {
        pancurses::endwin();
    }

    fn init_color_style(&mut self, style: ColorStyle, foreground: &Color,
                        background: &Color) {
        pancurses::init_pair(style.id(),
                             find_closest(foreground) as i16,
                             find_closest(background) as i16);
    }

    fn with_color<F: FnOnce()>(&self, color: ColorStyle, f: F) {
        // TODO: pancurses doesn't have an `attr_get` equivalent
        // let mut current_style: pancurses::attr_t = 0;
        // let mut current_color: i16 = 0;
        // pancurses::attr_get(&mut current_style, &mut current_color);

        let style = pancurses::COLOR_PAIR(color.id() as u64);
        self.window.attron(style);
        f();
        self.window.attroff(style);
        // pancurses::attron(current_style);
    }

    fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
        let style = match effect {
            // A_REVERSE, taken from ncurses
            Effect::Reverse => 1 << (10 + 8u32),
            Effect::Simple => pancurses::A_NORMAL,
        };
        self.window.attron(style);
        f();
        self.window.attroff(style);
    }

    fn clear(&self) {
        self.window.clear();
    }

    fn refresh(&mut self) {
        self.window.refresh();
    }

    fn print_at(&self, (x, y): (usize, usize), text: &str) {
        self.window.mvaddstr(y as i32, x as i32, text);
    }

    fn poll_event(&self) -> Event {
        // TODO: there seems to not be any indication
        // of Ctrl/Alt/Shift in these :v
        if let Some(ev) = self.window.getch() {
            match ev {
                pancurses::Input::Character(c) => Event::Char(c),
                pancurses::Input::Unknown(i) => Event::Unknown(i),
                // TODO: I honestly have no fucking idea what KeyCodeYes is
                pancurses::Input::KeyCodeYes => Event::Refresh,
                pancurses::Input::KeyBreak => Event::Key(Key::PauseBreak),
                pancurses::Input::KeyDown => Event::Key(Key::Down),
                pancurses::Input::KeyUp => Event::Key(Key::Up),
                pancurses::Input::KeyLeft => Event::Key(Key::Left),
                pancurses::Input::KeyRight => Event::Key(Key::Right),
                pancurses::Input::KeyHome => Event::Key(Key::Home),
                pancurses::Input::KeyBackspace => Event::Key(Key::Backspace),
                pancurses::Input::KeyF0 => Event::Key(Key::F0),
                pancurses::Input::KeyF1 => Event::Key(Key::F1),
                pancurses::Input::KeyF2 => Event::Key(Key::F2),
                pancurses::Input::KeyF3 => Event::Key(Key::F3),
                pancurses::Input::KeyF4 => Event::Key(Key::F4),
                pancurses::Input::KeyF5 => Event::Key(Key::F5),
                pancurses::Input::KeyF6 => Event::Key(Key::F6),
                pancurses::Input::KeyF7 => Event::Key(Key::F7),
                pancurses::Input::KeyF8 => Event::Key(Key::F8),
                pancurses::Input::KeyF9 => Event::Key(Key::F9),
                pancurses::Input::KeyF10 => Event::Key(Key::F10),
                pancurses::Input::KeyF11 => Event::Key(Key::F11),
                pancurses::Input::KeyF12 => Event::Key(Key::F12),
                // TODO: there seems to not be any F-keys above F15
                // for some reason?
                pancurses::Input::KeyF13 => Event::Refresh,
                pancurses::Input::KeyF14 => Event::Refresh,
                pancurses::Input::KeyF15 => Event::Refresh,
                // TODO: not sure what those are
                pancurses::Input::KeyDL => Event::Refresh,
                pancurses::Input::KeyIL => Event::Refresh,
                pancurses::Input::KeyDC => Event::Refresh,
                pancurses::Input::KeyIC => Event::Refresh,
                pancurses::Input::KeyEIC => Event::Refresh,
                pancurses::Input::KeyClear => Event::Refresh,
                pancurses::Input::KeyEOS => Event::Refresh,
                pancurses::Input::KeyEOL => Event::Refresh,
                pancurses::Input::KeySF => Event::Refresh,
                pancurses::Input::KeySR => Event::Refresh,
                pancurses::Input::KeyNPage => Event::Refresh,
                pancurses::Input::KeyPPage => Event::Refresh,
                pancurses::Input::KeySTab => Event::Shift(Key::Tab),
                pancurses::Input::KeyCTab => Event::Ctrl(Key::Tab),
                pancurses::Input::KeyCATab => Event::CtrlAlt(Key::Tab),
                pancurses::Input::KeyEnter => Event::Key(Key::Enter),
                // TODO: not sure what those are
                pancurses::Input::KeySReset => Event::Refresh,
                pancurses::Input::KeyReset => Event::Refresh,
                pancurses::Input::KeyPrint => Event::Refresh,
                pancurses::Input::KeyLL => Event::Refresh,
                pancurses::Input::KeyAbort => Event::Refresh,
                pancurses::Input::KeySHelp => Event::Refresh,
                pancurses::Input::KeyLHelp => Event::Refresh,
                pancurses::Input::KeyBTab => Event::Refresh,
                pancurses::Input::KeyBeg => Event::Refresh,
                pancurses::Input::KeyCancel => Event::Refresh,
                pancurses::Input::KeyClose => Event::Refresh,
                pancurses::Input::KeyCommand => Event::Refresh,
                pancurses::Input::KeyCopy => Event::Refresh,
                pancurses::Input::KeyCreate => Event::Refresh,
                pancurses::Input::KeyEnd => Event::Refresh,
                pancurses::Input::KeyExit => Event::Refresh,
                pancurses::Input::KeyFind => Event::Refresh,
                pancurses::Input::KeyHelp => Event::Refresh,
                pancurses::Input::KeyMark => Event::Refresh,
                pancurses::Input::KeyMessage => Event::Refresh,
                pancurses::Input::KeyMove => Event::Refresh,
                pancurses::Input::KeyNext => Event::Refresh,
                pancurses::Input::KeyOpen => Event::Refresh,
                pancurses::Input::KeyOptions => Event::Refresh,
                pancurses::Input::KeyPrevious => Event::Refresh,
                pancurses::Input::KeyRedo => Event::Refresh,
                pancurses::Input::KeyReference => Event::Refresh,
                pancurses::Input::KeyRefresh => Event::Refresh,
                pancurses::Input::KeyReplace => Event::Refresh,
                pancurses::Input::KeyRestart => Event::Refresh,
                pancurses::Input::KeyResume => Event::Refresh,
                pancurses::Input::KeySave => Event::Refresh,
                pancurses::Input::KeySBeg => Event::Refresh,
                pancurses::Input::KeySCancel => Event::Refresh,
                pancurses::Input::KeySCommand => Event::Refresh,
                pancurses::Input::KeySCopy => Event::Refresh,
                pancurses::Input::KeySCreate => Event::Refresh,
                pancurses::Input::KeySDC => Event::Refresh,
                pancurses::Input::KeySDL => Event::Refresh,
                pancurses::Input::KeySelect => Event::Refresh,
                pancurses::Input::KeySEnd => Event::Refresh,
                pancurses::Input::KeySEOL => Event::Refresh,
                pancurses::Input::KeySExit => Event::Refresh,
                pancurses::Input::KeySFind => Event::Refresh,
                pancurses::Input::KeySHome => Event::Refresh,
                pancurses::Input::KeySIC => Event::Refresh,
                pancurses::Input::KeySLeft => Event::Refresh,
                pancurses::Input::KeySMessage => Event::Refresh,
                pancurses::Input::KeySMove => Event::Refresh,
                pancurses::Input::KeySNext => Event::Refresh,
                pancurses::Input::KeySOptions => Event::Refresh,
                pancurses::Input::KeySPrevious => Event::Refresh,
                pancurses::Input::KeySPrint => Event::Refresh,
                pancurses::Input::KeySRedo => Event::Refresh,
                pancurses::Input::KeySReplace => Event::Refresh,
                pancurses::Input::KeySRight => Event::Refresh,
                pancurses::Input::KeySResume => Event::Refresh,
                pancurses::Input::KeySSave => Event::Refresh,
                pancurses::Input::KeySSuspend => Event::Refresh,
                pancurses::Input::KeySUndo => Event::Refresh,
                pancurses::Input::KeySuspend => Event::Refresh,
                pancurses::Input::KeyUndo => Event::Refresh,
                pancurses::Input::KeyResize => Event::Refresh,
                pancurses::Input::KeyEvent => Event::Refresh,
                // TODO: mouse support
                pancurses::Input::KeyMouse => Event::Refresh,
                // TODO: not sure what those are
                pancurses::Input::KeyA1 => Event::Refresh,
                pancurses::Input::KeyA3 => Event::Refresh,
                pancurses::Input::KeyB2 => Event::Refresh,
                pancurses::Input::KeyC1 => Event::Refresh,
                pancurses::Input::KeyC3 => Event::Refresh,
            }
        } else {
            Event::Refresh
        }
    }

    fn set_refresh_rate(&mut self, fps: u32) {
        if fps == 0 {
            self.window.timeout(-1);
        } else {
            self.window.timeout(1000 / fps as i32);
        }
    }
}
<commit_msg>Handle F[14;15]<commit_after>extern crate pancurses;

use backend;
use event::{Event, Key};

use self::super::find_closest;
use theme::{Color, ColorStyle, Effect};

pub struct Concrete {
    window: pancurses::Window,
}

impl backend::Backend for Concrete {
    fn init() -> Self {
        ::std::env::set_var("ESCDELAY", "25");
        let window = pancurses::initscr();
        window.keypad(true);
        pancurses::noecho();
        pancurses::cbreak();
        pancurses::start_color();
        pancurses::curs_set(0);
        window.bkgd(pancurses::COLOR_PAIR(ColorStyle::Background.id() as u64));

        Concrete { window: window }
    }

    fn screen_size(&self) -> (usize, usize) {
        let (x, y) = self.window.get_max_yx();
        (x as usize, y as usize)
    }

    fn has_colors(&self) -> bool {
        pancurses::has_colors()
    }

    fn finish(&mut self) {
        pancurses::endwin();
    }

    fn init_color_style(&mut self, style: ColorStyle, foreground: &Color,
                        background: &Color) {
        pancurses::init_pair(style.id(),
                             find_closest(foreground) as i16,
                             find_closest(background) as i16);
    }

    fn with_color<F: FnOnce()>(&self, color: ColorStyle, f: F) {
        // TODO: pancurses doesn't have an `attr_get` equivalent
        // let mut current_style: pancurses::attr_t = 0;
        // let mut current_color: i16 = 0;
        // pancurses::attr_get(&mut current_style, &mut current_color);

        let style = pancurses::COLOR_PAIR(color.id() as u64);
        self.window.attron(style);
        f();
        self.window.attroff(style);
        // pancurses::attron(current_style);
    }

    fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
        let style = match effect {
            // A_REVERSE, taken from ncurses
            Effect::Reverse => 1 << (10 + 8u32),
            Effect::Simple => pancurses::A_NORMAL,
        };
        self.window.attron(style);
        f();
        self.window.attroff(style);
    }

    fn clear(&self) {
        self.window.clear();
    }

    fn refresh(&mut self) {
        self.window.refresh();
    }

    fn print_at(&self, (x, y): (usize, usize), text: &str) {
        self.window.mvaddstr(y as i32, x as i32, text);
    }

    fn poll_event(&self) -> Event {
        // TODO: there seems to not be any indication
        // of Ctrl/Alt/Shift in these :v
        if let Some(ev) = self.window.getch() {
            match ev {
                pancurses::Input::Character(c) => Event::Char(c),
                pancurses::Input::Unknown(i) => Event::Unknown(i),
                // TODO: I honestly have no fucking idea what KeyCodeYes is
                pancurses::Input::KeyCodeYes => Event::Refresh,
                pancurses::Input::KeyBreak => Event::Key(Key::PauseBreak),
                pancurses::Input::KeyDown => Event::Key(Key::Down),
                pancurses::Input::KeyUp => Event::Key(Key::Up),
                pancurses::Input::KeyLeft => Event::Key(Key::Left),
                pancurses::Input::KeyRight => Event::Key(Key::Right),
                pancurses::Input::KeyHome => Event::Key(Key::Home),
                pancurses::Input::KeyBackspace => Event::Key(Key::Backspace),
                pancurses::Input::KeyF0 => Event::Key(Key::F0),
                pancurses::Input::KeyF1 => Event::Key(Key::F1),
                pancurses::Input::KeyF2 => Event::Key(Key::F2),
                pancurses::Input::KeyF3 => Event::Key(Key::F3),
                pancurses::Input::KeyF4 => Event::Key(Key::F4),
                pancurses::Input::KeyF5 => Event::Key(Key::F5),
                pancurses::Input::KeyF6 => Event::Key(Key::F6),
                pancurses::Input::KeyF7 => Event::Key(Key::F7),
                pancurses::Input::KeyF8 => Event::Key(Key::F8),
                pancurses::Input::KeyF9 => Event::Key(Key::F9),
                pancurses::Input::KeyF10 => Event::Key(Key::F10),
                pancurses::Input::KeyF11 => Event::Key(Key::F11),
                pancurses::Input::KeyF12 => Event::Key(Key::F12),
                pancurses::Input::KeyF13 => Event::Shift(Key::F1),
                pancurses::Input::KeyF14 => Event::Shift(Key::F2),
                pancurses::Input::KeyF15 => Event::Shift(Key::F3),
                // TODO: not sure what those are
                pancurses::Input::KeyDL => Event::Refresh,
                pancurses::Input::KeyIL => Event::Refresh,
                pancurses::Input::KeyDC => Event::Refresh,
                pancurses::Input::KeyIC => Event::Refresh,
                pancurses::Input::KeyEIC => Event::Refresh,
                pancurses::Input::KeyClear => Event::Refresh,
                pancurses::Input::KeyEOS => Event::Refresh,
                pancurses::Input::KeyEOL => Event::Refresh,
                pancurses::Input::KeySF => Event::Refresh,
                pancurses::Input::KeySR => Event::Refresh,
                pancurses::Input::KeyNPage => Event::Refresh,
                pancurses::Input::KeyPPage => Event::Refresh,
                pancurses::Input::KeySTab => Event::Shift(Key::Tab),
                pancurses::Input::KeyCTab => Event::Ctrl(Key::Tab),
                pancurses::Input::KeyCATab => Event::CtrlAlt(Key::Tab),
                pancurses::Input::KeyEnter => Event::Key(Key::Enter),
                // TODO: not sure what those are
                pancurses::Input::KeySReset => Event::Refresh,
                pancurses::Input::KeyReset => Event::Refresh,
                pancurses::Input::KeyPrint => Event::Refresh,
                pancurses::Input::KeyLL => Event::Refresh,
                pancurses::Input::KeyAbort => Event::Refresh,
                pancurses::Input::KeySHelp => Event::Refresh,
                pancurses::Input::KeyLHelp => Event::Refresh,
                pancurses::Input::KeyBTab => Event::Refresh,
                pancurses::Input::KeyBeg => Event::Refresh,
                pancurses::Input::KeyCancel => Event::Refresh,
                pancurses::Input::KeyClose => Event::Refresh,
                pancurses::Input::KeyCommand => Event::Refresh,
                pancurses::Input::KeyCopy => Event::Refresh,
                pancurses::Input::KeyCreate => Event::Refresh,
                pancurses::Input::KeyEnd => Event::Refresh,
                pancurses::Input::KeyExit => Event::Refresh,
                pancurses::Input::KeyFind => Event::Refresh,
                pancurses::Input::KeyHelp => Event::Refresh,
                pancurses::Input::KeyMark => Event::Refresh,
                pancurses::Input::KeyMessage => Event::Refresh,
                pancurses::Input::KeyMove => Event::Refresh,
                pancurses::Input::KeyNext => Event::Refresh,
                pancurses::Input::KeyOpen => Event::Refresh,
                pancurses::Input::KeyOptions => Event::Refresh,
                pancurses::Input::KeyPrevious => Event::Refresh,
                pancurses::Input::KeyRedo => Event::Refresh,
                pancurses::Input::KeyReference => Event::Refresh,
                pancurses::Input::KeyRefresh => Event::Refresh,
                pancurses::Input::KeyReplace => Event::Refresh,
                pancurses::Input::KeyRestart => Event::Refresh,
                pancurses::Input::KeyResume => Event::Refresh,
                pancurses::Input::KeySave => Event::Refresh,
                pancurses::Input::KeySBeg => Event::Refresh,
                pancurses::Input::KeySCancel => Event::Refresh,
                pancurses::Input::KeySCommand => Event::Refresh,
                pancurses::Input::KeySCopy => Event::Refresh,
                pancurses::Input::KeySCreate => Event::Refresh,
                pancurses::Input::KeySDC => Event::Refresh,
                pancurses::Input::KeySDL => Event::Refresh,
                pancurses::Input::KeySelect => Event::Refresh,
                pancurses::Input::KeySEnd => Event::Refresh,
                pancurses::Input::KeySEOL => Event::Refresh,
                pancurses::Input::KeySExit => Event::Refresh,
                pancurses::Input::KeySFind => Event::Refresh,
                pancurses::Input::KeySHome => Event::Refresh,
                pancurses::Input::KeySIC => Event::Refresh,
                pancurses::Input::KeySLeft => Event::Refresh,
                pancurses::Input::KeySMessage => Event::Refresh,
                pancurses::Input::KeySMove => Event::Refresh,
                pancurses::Input::KeySNext => Event::Refresh,
                pancurses::Input::KeySOptions => Event::Refresh,
                pancurses::Input::KeySPrevious => Event::Refresh,
                pancurses::Input::KeySPrint => Event::Refresh,
                pancurses::Input::KeySRedo => Event::Refresh,
                pancurses::Input::KeySReplace => Event::Refresh,
                pancurses::Input::KeySRight => Event::Refresh,
                pancurses::Input::KeySResume => Event::Refresh,
                pancurses::Input::KeySSave => Event::Refresh,
                pancurses::Input::KeySSuspend => Event::Refresh,
                pancurses::Input::KeySUndo => Event::Refresh,
                pancurses::Input::KeySuspend => Event::Refresh,
                pancurses::Input::KeyUndo => Event::Refresh,
                pancurses::Input::KeyResize => Event::Refresh,
                pancurses::Input::KeyEvent => Event::Refresh,
                // TODO: mouse support
                pancurses::Input::KeyMouse => Event::Refresh,
                // TODO: not sure what those are
                pancurses::Input::KeyA1 => Event::Refresh,
                pancurses::Input::KeyA3 => Event::Refresh,
                pancurses::Input::KeyB2 => Event::Refresh,
                pancurses::Input::KeyC1 => Event::Refresh,
                pancurses::Input::KeyC3 => Event::Refresh,
            }
        } else {
            Event::Refresh
        }
    }

    fn set_refresh_rate(&mut self, fps: u32) {
        if fps == 0 {
            self.window.timeout(-1);
        } else {
            self.window.timeout(1000 / fps as i32);
        }
    }
}
<|endoftext|>


<commit_before>//! Asynchronous wrapper of tun interface

use std::{
    io,
    ops::{Deref, DerefMut},
    os::unix::io::{AsRawFd, RawFd},
};

use smoltcp::{
    phy::{Device, DeviceCapabilities, Medium, RxToken, TunTapInterface, TxToken},
    time::Instant,
};
use tokio::io::unix::AsyncFd;

struct SendableTunTapInterface(TunTapInterface);

/// TunTapInterface is not Sendable because it contains a Rc field.
/// The Rc field will be shared between all TxToken.
///
/// But in this wrapper, we won't expose the RxToken and TxToken, so it is safe to Send between threads.
unsafe impl Send for SendableTunTapInterface {}

impl AsRawFd for SendableTunTapInterface {
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}

impl Deref for SendableTunTapInterface {
    type Target = TunTapInterface;

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

impl DerefMut for SendableTunTapInterface {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

pub struct TunInterface {
    iface: AsyncFd<SendableTunTapInterface>,
}

impl TunInterface {
    pub fn new(name: &str) -> io::Result<TunInterface> {
        let iface = SendableTunTapInterface(TunTapInterface::new(name, Medium::Ip)?);
        Ok(TunInterface {
            iface: AsyncFd::new(iface)?,
        })
    }

    pub async fn receive<R, F>(&mut self, timestamp: Instant, consume: F) -> io::Result<R>
    where
        F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
    {
        loop {
            let mut ready = self.iface.readable_mut().await?;
            let result = ready.try_io(|iface| match iface.get_mut().receive() {
                Some(token) => return Ok(token),
                None => Err(io::ErrorKind::WouldBlock.into()),
            });

            match result {
                Ok(Ok((token, _))) => {
                    return token
                        .consume(timestamp, consume)
                        .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
                }
                Ok(Err(err)) => return Err(err),
                Err(..) => continue,
            }
        }
    }

    pub async fn transmit(&mut self, timestamp: Instant, buffer: &[u8]) -> io::Result<()> {
        loop {
            let mut ready = self.iface.writable_mut().await?;

            let result = ready.try_io(|iface| match iface.get_mut().transmit() {
                Some(token) => Ok(token),
                None => Err(io::ErrorKind::WouldBlock.into()),
            });

            match result {
                Ok(Ok(token)) => {
                    return token
                        .consume(timestamp, buffer.len(), |xbuf| {
                            xbuf.copy_from_slice(buffer);
                            Ok(())
                        })
                        .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
                }
                Ok(Err(err)) => return Err(err),
                Err(..) => continue,
            }
        }
    }

    pub fn capabilities(&self) -> DeviceCapabilities {
        self.iface.get_ref().capabilities()
    }
}
<commit_msg>removed unused async_interface<commit_after><|endoftext|>


<commit_before>#![cfg_attr(not(feature = "net"), allow(dead_code))]

use crate::io::interest::Interest;
use crate::runtime::io::{Direction, Handle, ReadyEvent, ScheduledIo};
use crate::util::slab;

use mio::event::Source;
use std::io;
use std::task::{Context, Poll};

cfg_io_driver! {
    /// Associates an I/O resource with the reactor instance that drives it.
    ///
    /// A registration represents an I/O resource registered with a Reactor such
    /// that it will receive task notifications on readiness. This is the lowest
    /// level API for integrating with a reactor.
    ///
    /// The association between an I/O resource is made by calling
    /// [`new_with_interest_and_handle`].
    /// Once the association is established, it remains established until the
    /// registration instance is dropped.
    ///
    /// A registration instance represents two separate readiness streams. One
    /// for the read readiness and one for write readiness. These streams are
    /// independent and can be consumed from separate tasks.
    ///
    /// **Note**: while `Registration` is `Sync`, the caller must ensure that
    /// there are at most two tasks that use a registration instance
    /// concurrently. One task for [`poll_read_ready`] and one task for
    /// [`poll_write_ready`]. While violating this requirement is "safe" from a
    /// Rust memory safety point of view, it will result in unexpected behavior
    /// in the form of lost notifications and tasks hanging.
    ///
    /// ## Platform-specific events
    ///
    /// `Registration` also allows receiving platform-specific `mio::Ready`
    /// events. These events are included as part of the read readiness event
    /// stream. The write readiness event stream is only for `Ready::writable()`
    /// events.
    ///
    /// [`new_with_interest_and_handle`]: method@Self::new_with_interest_and_handle
    /// [`poll_read_ready`]: method@Self::poll_read_ready`
    /// [`poll_write_ready`]: method@Self::poll_write_ready`
    #[derive(Debug)]
    pub(crate) struct Registration {
        /// Handle to the associated driver.
        handle: Handle,

        /// Reference to state stored by the driver.
        shared: slab::Ref<ScheduledIo>,
    }
}

unsafe impl Send for Registration {}
unsafe impl Sync for Registration {}

// ===== impl Registration =====

impl Registration {
    /// Registers the I/O resource with the default reactor, for a specific
    /// `Interest`. `new_with_interest` should be used over `new` when you need
    /// control over the readiness state, such as when a file descriptor only
    /// allows reads. This does not add `hup` or `error` so if you are
    /// interested in those states, you will need to add them to the readiness
    /// state passed to this function.
    ///
    /// # Return
    ///
    /// - `Ok` if the registration happened successfully
    /// - `Err` if an error was encountered during registration
    pub(crate) fn new_with_interest_and_handle(
        io: &mut impl Source,
        interest: Interest,
        handle: Handle,
    ) -> io::Result<Registration> {
        let shared = handle.inner.add_source(io, interest)?;

        Ok(Registration { handle, shared })
    }

    /// Deregisters the I/O resource from the reactor it is associated with.
    ///
    /// This function must be called before the I/O resource associated with the
    /// registration is dropped.
    ///
    /// Note that deregistering does not guarantee that the I/O resource can be
    /// registered with a different reactor. Some I/O resource types can only be
    /// associated with a single reactor instance for their lifetime.
    ///
    /// # Return
    ///
    /// If the deregistration was successful, `Ok` is returned. Any calls to
    /// `Reactor::turn` that happen after a successful call to `deregister` will
    /// no longer result in notifications getting sent for this registration.
    ///
    /// `Err` is returned if an error is encountered.
    pub(crate) fn deregister(&mut self, io: &mut impl Source) -> io::Result<()> {
        self.handle.inner.deregister_source(io)
    }

    pub(crate) fn clear_readiness(&self, event: ReadyEvent) {
        self.shared.clear_readiness(event);
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    pub(crate) fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<ReadyEvent>> {
        self.poll_ready(cx, Direction::Read)
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    pub(crate) fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<ReadyEvent>> {
        self.poll_ready(cx, Direction::Write)
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    #[cfg(not(tokio_wasi))]
    pub(crate) fn poll_read_io<R>(
        &self,
        cx: &mut Context<'_>,
        f: impl FnMut() -> io::Result<R>,
    ) -> Poll<io::Result<R>> {
        self.poll_io(cx, Direction::Read, f)
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    pub(crate) fn poll_write_io<R>(
        &self,
        cx: &mut Context<'_>,
        f: impl FnMut() -> io::Result<R>,
    ) -> Poll<io::Result<R>> {
        self.poll_io(cx, Direction::Write, f)
    }

    /// Polls for events on the I/O resource's `direction` readiness stream.
    ///
    /// If called with a task context, notify the task when a new event is
    /// received.
    fn poll_ready(
        &self,
        cx: &mut Context<'_>,
        direction: Direction,
    ) -> Poll<io::Result<ReadyEvent>> {
        // Keep track of task budget
        let coop = ready!(crate::coop::poll_proceed(cx));
        let ev = ready!(self.shared.poll_readiness(cx, direction));

        if self.handle.inner.is_shutdown() {
            return Poll::Ready(Err(gone()));
        }

        coop.made_progress();
        Poll::Ready(Ok(ev))
    }

    fn poll_io<R>(
        &self,
        cx: &mut Context<'_>,
        direction: Direction,
        mut f: impl FnMut() -> io::Result<R>,
    ) -> Poll<io::Result<R>> {
        loop {
            let ev = ready!(self.poll_ready(cx, direction))?;

            match f() {
                Ok(ret) => {
                    return Poll::Ready(Ok(ret));
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    self.clear_readiness(ev);
                }
                Err(e) => return Poll::Ready(Err(e)),
            }
        }
    }

    pub(crate) fn try_io<R>(
        &self,
        interest: Interest,
        f: impl FnOnce() -> io::Result<R>,
    ) -> io::Result<R> {
        let ev = self.shared.ready_event(interest);

        // Don't attempt the operation if the resource is not ready.
        if ev.ready.is_empty() {
            return Err(io::ErrorKind::WouldBlock.into());
        }

        match f() {
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                self.clear_readiness(ev);
                Err(io::ErrorKind::WouldBlock.into())
            }
            res => res,
        }
    }
}

impl Drop for Registration {
    fn drop(&mut self) {
        // It is possible for a cycle to be created between wakers stored in
        // `ScheduledIo` instances and `Arc<driver::Inner>`. To break this
        // cycle, wakers are cleared. This is an imperfect solution as it is
        // possible to store a `Registration` in a waker. In this case, the
        // cycle would remain.
        //
        // See tokio-rs/tokio#3481 for more details.
        self.shared.clear_wakers();
    }
}

fn gone() -> io::Error {
    io::Error::new(io::ErrorKind::Other, "IO driver has terminated")
}

cfg_io_readiness! {
    impl Registration {
        pub(crate) async fn readiness(&self, interest: Interest) -> io::Result<ReadyEvent> {
            use std::future::Future;
            use std::pin::Pin;

            let fut = self.shared.readiness(interest);
            pin!(fut);

            crate::future::poll_fn(|cx| {
                if self.handle.inner.is_shutdown() {
                    return Poll::Ready(Err(io::Error::new(
                        io::ErrorKind::Other,
                        crate::util::error::RUNTIME_SHUTTING_DOWN_ERROR
                    )));
                }

                Pin::new(&mut fut).poll(cx).map(Ok)
            }).await
        }

        pub(crate) async fn async_io<R>(&self, interest: Interest, mut f: impl FnMut() -> io::Result<R>) -> io::Result<R> {
            loop {
                let event = self.readiness(interest).await?;

                match f() {
                    Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                        self.clear_readiness(event);
                    }
                    x => return x,
                }
            }
        }
    }
}
<commit_msg>io: remove reference to missing functions from `Registration` docs (#4995)<commit_after>#![cfg_attr(not(feature = "net"), allow(dead_code))]

use crate::io::interest::Interest;
use crate::runtime::io::{Direction, Handle, ReadyEvent, ScheduledIo};
use crate::util::slab;

use mio::event::Source;
use std::io;
use std::task::{Context, Poll};

cfg_io_driver! {
    /// Associates an I/O resource with the reactor instance that drives it.
    ///
    /// A registration represents an I/O resource registered with a Reactor such
    /// that it will receive task notifications on readiness. This is the lowest
    /// level API for integrating with a reactor.
    ///
    /// The association between an I/O resource is made by calling
    /// [`new_with_interest_and_handle`].
    /// Once the association is established, it remains established until the
    /// registration instance is dropped.
    ///
    /// A registration instance represents two separate readiness streams. One
    /// for the read readiness and one for write readiness. These streams are
    /// independent and can be consumed from separate tasks.
    ///
    /// **Note**: while `Registration` is `Sync`, the caller must ensure that
    /// there are at most two tasks that use a registration instance
    /// concurrently. One task for [`poll_read_ready`] and one task for
    /// [`poll_write_ready`]. While violating this requirement is "safe" from a
    /// Rust memory safety point of view, it will result in unexpected behavior
    /// in the form of lost notifications and tasks hanging.
    ///
    /// ## Platform-specific events
    ///
    /// `Registration` also allows receiving platform-specific `mio::Ready`
    /// events. These events are included as part of the read readiness event
    /// stream. The write readiness event stream is only for `Ready::writable()`
    /// events.
    ///
    /// [`new_with_interest_and_handle`]: method@Self::new_with_interest_and_handle
    /// [`poll_read_ready`]: method@Self::poll_read_ready`
    /// [`poll_write_ready`]: method@Self::poll_write_ready`
    #[derive(Debug)]
    pub(crate) struct Registration {
        /// Handle to the associated driver.
        handle: Handle,

        /// Reference to state stored by the driver.
        shared: slab::Ref<ScheduledIo>,
    }
}

unsafe impl Send for Registration {}
unsafe impl Sync for Registration {}

// ===== impl Registration =====

impl Registration {
    /// Registers the I/O resource with the reactor for the provided handle, for
    /// a specific `Interest`. This does not add `hup` or `error` so if you are
    /// interested in those states, you will need to add them to the readiness
    /// state passed to this function.
    ///
    /// # Return
    ///
    /// - `Ok` if the registration happened successfully
    /// - `Err` if an error was encountered during registration
    pub(crate) fn new_with_interest_and_handle(
        io: &mut impl Source,
        interest: Interest,
        handle: Handle,
    ) -> io::Result<Registration> {
        let shared = handle.inner.add_source(io, interest)?;

        Ok(Registration { handle, shared })
    }

    /// Deregisters the I/O resource from the reactor it is associated with.
    ///
    /// This function must be called before the I/O resource associated with the
    /// registration is dropped.
    ///
    /// Note that deregistering does not guarantee that the I/O resource can be
    /// registered with a different reactor. Some I/O resource types can only be
    /// associated with a single reactor instance for their lifetime.
    ///
    /// # Return
    ///
    /// If the deregistration was successful, `Ok` is returned. Any calls to
    /// `Reactor::turn` that happen after a successful call to `deregister` will
    /// no longer result in notifications getting sent for this registration.
    ///
    /// `Err` is returned if an error is encountered.
    pub(crate) fn deregister(&mut self, io: &mut impl Source) -> io::Result<()> {
        self.handle.inner.deregister_source(io)
    }

    pub(crate) fn clear_readiness(&self, event: ReadyEvent) {
        self.shared.clear_readiness(event);
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    pub(crate) fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<ReadyEvent>> {
        self.poll_ready(cx, Direction::Read)
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    pub(crate) fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<ReadyEvent>> {
        self.poll_ready(cx, Direction::Write)
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    #[cfg(not(tokio_wasi))]
    pub(crate) fn poll_read_io<R>(
        &self,
        cx: &mut Context<'_>,
        f: impl FnMut() -> io::Result<R>,
    ) -> Poll<io::Result<R>> {
        self.poll_io(cx, Direction::Read, f)
    }

    // Uses the poll path, requiring the caller to ensure mutual exclusion for
    // correctness. Only the last task to call this function is notified.
    pub(crate) fn poll_write_io<R>(
        &self,
        cx: &mut Context<'_>,
        f: impl FnMut() -> io::Result<R>,
    ) -> Poll<io::Result<R>> {
        self.poll_io(cx, Direction::Write, f)
    }

    /// Polls for events on the I/O resource's `direction` readiness stream.
    ///
    /// If called with a task context, notify the task when a new event is
    /// received.
    fn poll_ready(
        &self,
        cx: &mut Context<'_>,
        direction: Direction,
    ) -> Poll<io::Result<ReadyEvent>> {
        // Keep track of task budget
        let coop = ready!(crate::coop::poll_proceed(cx));
        let ev = ready!(self.shared.poll_readiness(cx, direction));

        if self.handle.inner.is_shutdown() {
            return Poll::Ready(Err(gone()));
        }

        coop.made_progress();
        Poll::Ready(Ok(ev))
    }

    fn poll_io<R>(
        &self,
        cx: &mut Context<'_>,
        direction: Direction,
        mut f: impl FnMut() -> io::Result<R>,
    ) -> Poll<io::Result<R>> {
        loop {
            let ev = ready!(self.poll_ready(cx, direction))?;

            match f() {
                Ok(ret) => {
                    return Poll::Ready(Ok(ret));
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    self.clear_readiness(ev);
                }
                Err(e) => return Poll::Ready(Err(e)),
            }
        }
    }

    pub(crate) fn try_io<R>(
        &self,
        interest: Interest,
        f: impl FnOnce() -> io::Result<R>,
    ) -> io::Result<R> {
        let ev = self.shared.ready_event(interest);

        // Don't attempt the operation if the resource is not ready.
        if ev.ready.is_empty() {
            return Err(io::ErrorKind::WouldBlock.into());
        }

        match f() {
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                self.clear_readiness(ev);
                Err(io::ErrorKind::WouldBlock.into())
            }
            res => res,
        }
    }
}

impl Drop for Registration {
    fn drop(&mut self) {
        // It is possible for a cycle to be created between wakers stored in
        // `ScheduledIo` instances and `Arc<driver::Inner>`. To break this
        // cycle, wakers are cleared. This is an imperfect solution as it is
        // possible to store a `Registration` in a waker. In this case, the
        // cycle would remain.
        //
        // See tokio-rs/tokio#3481 for more details.
        self.shared.clear_wakers();
    }
}

fn gone() -> io::Error {
    io::Error::new(io::ErrorKind::Other, "IO driver has terminated")
}

cfg_io_readiness! {
    impl Registration {
        pub(crate) async fn readiness(&self, interest: Interest) -> io::Result<ReadyEvent> {
            use std::future::Future;
            use std::pin::Pin;

            let fut = self.shared.readiness(interest);
            pin!(fut);

            crate::future::poll_fn(|cx| {
                if self.handle.inner.is_shutdown() {
                    return Poll::Ready(Err(io::Error::new(
                        io::ErrorKind::Other,
                        crate::util::error::RUNTIME_SHUTTING_DOWN_ERROR
                    )));
                }

                Pin::new(&mut fut).poll(cx).map(Ok)
            }).await
        }

        pub(crate) async fn async_io<R>(&self, interest: Interest, mut f: impl FnMut() -> io::Result<R>) -> io::Result<R> {
            loop {
                let event = self.readiness(interest).await?;

                match f() {
                    Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                        self.clear_readiness(event);
                    }
                    x => return x,
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use env::Env;
use analysis::bounds::{Bounds, BoundType};
use analysis::parameter::Parameter;
use analysis::ref_mode::RefMode;
use analysis::rust_type::parameter_rust_type;
use analysis::trampolines::Trampoline;
use nameutil;
use super::general::version_condition;
use super::return_value::ToReturnValue;
use super::sys::ffi_type::ffi_type;
use super::trampoline_from_glib::TrampolineFromGlib;
use super::trampoline_to_glib::TrampolineToGlib;
use traits::IntoString;

pub fn generate(w: &mut Write, env: &Env, analysis: &Trampoline,
                in_trait: bool, object_name: &str) -> Result<()> {
    try!(writeln!(w, ""));
    let (bounds, end) = if in_trait {
        ("<T>", "")
    } else {
        ("", " {")
    };

    let params_str = trampoline_parameters(env, analysis);
    let func_str = func_string(env, analysis, None::<(&str, &str)>);
    let ret_str = trampoline_returns(env, analysis);

    try!(version_condition(w, env, analysis.version, false, 0));
    try!(writeln!(w, "unsafe extern \"C\" fn {}{}({}, f: gpointer){}{}",
                  analysis.name, bounds, params_str, ret_str, end));
    if in_trait {
        try!(writeln!(w, "where T: IsA<{}> {{", object_name));
    }
    try!(writeln!(w, "\tcallback_guard!();"));
    try!(writeln!(w, "\tlet f: &Box_<{}> = transmute(f);", func_str));
    let call = trampoline_call_func(env, analysis, in_trait);
    try!(writeln!(w, "\t{}", call));
    try!(writeln!(w, "}}"));

    Ok(())
}

pub fn func_string(env: &Env, analysis: &Trampoline,
                   bound_replace: Option<(&str, &str)>) -> String {
    let param_str = func_parameters(env, analysis, bound_replace);
    let return_str = func_returns(env, analysis);

    format!("Fn({}){} + 'static", param_str, return_str)
}

fn func_parameters(env: &Env, analysis: &Trampoline,
                   bound_replace: Option<(&str, &str)>) -> String {
    let mut param_str = String::with_capacity(100);

    for (pos, par) in analysis.parameters.iter().enumerate() {
        if pos > 0 { param_str.push_str(", ") }
        let s = func_parameter(env, par, &analysis.bounds, bound_replace);
        param_str.push_str(&s);
    }

    param_str
}

fn func_parameter(env: &Env, par: &Parameter, bounds: &Bounds,
                  bound_replace: Option<(&str, &str)>) -> String {
    let mut_str = if par.ref_mode == RefMode::ByRefMut { "mut " } else { "" };

    let type_str: String;
    match bounds.get_parameter_alias_info(&par.name) {
        Some((t, bound_type)) => {
            match bound_type {
                BoundType::IsA => if *par.nullable {
                    type_str = format!("Option<&{}{}>", mut_str, t)
                } else {
                    let t = if let Some((from, to)) = bound_replace {
                        if from == t { to } else { t }
                    } else {
                        t
                    };
                    type_str = format!("&{}{}", mut_str, t)
                },
                BoundType::AsRef  => type_str = t.to_owned(),
            }
        }
        None => {
            let rust_type = parameter_rust_type(env, par.typ, par.direction,
                                                par.nullable, par.ref_mode);
            type_str = rust_type.into_string();
        }
    }
    type_str
}

fn func_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        analysis.ret.to_return_value(&env)
    }
}

fn trampoline_parameters(env: &Env, analysis: &Trampoline) -> String {
    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &analysis.parameters {
        let par_str = trampoline_parameter(env, par);
        parameter_strs.push(par_str);
    }

    parameter_strs.join(", ")
}

fn trampoline_parameter(env: &Env, par: &Parameter) -> String {
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    format!("{}: {}", nameutil::mangle_keywords(&*par.name), ffi_type.into_string())
}

fn trampoline_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        let ffi_type = ffi_type(env, analysis.ret.typ, &analysis.ret.c_type);
        format!(" -> {}", ffi_type.into_string())
    }
}

fn trampoline_call_func(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let params = trampoline_call_parameters(env, analysis, in_trait);
    let ret = if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        analysis.ret.trampoline_to_glib(&env.library)
    };
    format!("f({}){}", params, ret)
}

fn trampoline_call_parameters(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let mut need_downcast = in_trait;
    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &analysis.parameters {
        let par_str = par.trampoline_from_glib(env, need_downcast);
        parameter_strs.push(par_str);
        need_downcast = false;  //Only downcast first parameter
    }

    parameter_strs.join(", ")
}
<commit_msg>Disable mutable parameters in trampoline functions<commit_after>use std::io::{Result, Write};

use env::Env;
use analysis::bounds::{Bounds, BoundType};
use analysis::parameter::Parameter;
use analysis::ref_mode::RefMode;
use analysis::rust_type::parameter_rust_type;
use analysis::trampolines::Trampoline;
use nameutil;
use super::general::version_condition;
use super::return_value::ToReturnValue;
use super::sys::ffi_type::ffi_type;
use super::trampoline_from_glib::TrampolineFromGlib;
use super::trampoline_to_glib::TrampolineToGlib;
use traits::IntoString;

pub fn generate(w: &mut Write, env: &Env, analysis: &Trampoline,
                in_trait: bool, object_name: &str) -> Result<()> {
    try!(writeln!(w, ""));
    let (bounds, end) = if in_trait {
        ("<T>", "")
    } else {
        ("", " {")
    };

    let params_str = trampoline_parameters(env, analysis);
    let func_str = func_string(env, analysis, None::<(&str, &str)>);
    let ret_str = trampoline_returns(env, analysis);

    try!(version_condition(w, env, analysis.version, false, 0));
    try!(writeln!(w, "unsafe extern \"C\" fn {}{}({}, f: gpointer){}{}",
                  analysis.name, bounds, params_str, ret_str, end));
    if in_trait {
        try!(writeln!(w, "where T: IsA<{}> {{", object_name));
    }
    try!(writeln!(w, "\tcallback_guard!();"));
    try!(writeln!(w, "\tlet f: &Box_<{}> = transmute(f);", func_str));
    let call = trampoline_call_func(env, analysis, in_trait);
    try!(writeln!(w, "\t{}", call));
    try!(writeln!(w, "}}"));

    Ok(())
}

pub fn func_string(env: &Env, analysis: &Trampoline,
                   bound_replace: Option<(&str, &str)>) -> String {
    let param_str = func_parameters(env, analysis, bound_replace);
    let return_str = func_returns(env, analysis);

    format!("Fn({}){} + 'static", param_str, return_str)
}

fn func_parameters(env: &Env, analysis: &Trampoline,
                   bound_replace: Option<(&str, &str)>) -> String {
    let mut param_str = String::with_capacity(100);

    for (pos, par) in analysis.parameters.iter().enumerate() {
        if pos > 0 { param_str.push_str(", ") }
        let s = func_parameter(env, par, &analysis.bounds, bound_replace);
        param_str.push_str(&s);
    }

    param_str
}

fn func_parameter(env: &Env, par: &Parameter, bounds: &Bounds,
                  bound_replace: Option<(&str, &str)>) -> String {
    //TODO: restore mutable support
    //let mut_str = if par.ref_mode == RefMode::ByRefMut { "mut " } else { "" };
    let mut_str = "";
    let ref_mode = if par.ref_mode == RefMode::ByRefMut {
        RefMode::ByRef
    } else {
        par.ref_mode
    };

    let type_str: String;
    match bounds.get_parameter_alias_info(&par.name) {
        Some((t, bound_type)) => {
            match bound_type {
                BoundType::IsA => if *par.nullable {
                    type_str = format!("Option<&{}{}>", mut_str, t)
                } else {
                    let t = if let Some((from, to)) = bound_replace {
                        if from == t { to } else { t }
                    } else {
                        t
                    };
                    type_str = format!("&{}{}", mut_str, t)
                },
                BoundType::AsRef  => type_str = t.to_owned(),
            }
        }
        None => {
            let rust_type = parameter_rust_type(env, par.typ, par.direction,
                                                par.nullable, ref_mode);
            type_str = rust_type.into_string();
        }
    }
    type_str
}

fn func_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        analysis.ret.to_return_value(&env)
    }
}

fn trampoline_parameters(env: &Env, analysis: &Trampoline) -> String {
    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &analysis.parameters {
        let par_str = trampoline_parameter(env, par);
        parameter_strs.push(par_str);
    }

    parameter_strs.join(", ")
}

fn trampoline_parameter(env: &Env, par: &Parameter) -> String {
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    format!("{}: {}", nameutil::mangle_keywords(&*par.name), ffi_type.into_string())
}

fn trampoline_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        let ffi_type = ffi_type(env, analysis.ret.typ, &analysis.ret.c_type);
        format!(" -> {}", ffi_type.into_string())
    }
}

fn trampoline_call_func(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let params = trampoline_call_parameters(env, analysis, in_trait);
    let ret = if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        analysis.ret.trampoline_to_glib(&env.library)
    };
    format!("f({}){}", params, ret)
}

fn trampoline_call_parameters(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let mut need_downcast = in_trait;
    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &analysis.parameters {
        let par_str = par.trampoline_from_glib(env, need_downcast);
        parameter_strs.push(par_str);
        need_downcast = false;  //Only downcast first parameter
    }

    parameter_strs.join(", ")
}
<|endoftext|>


<commit_before>use ide_db::{
    assists::{AssistId, AssistKind},
    base_db::AnchoredPathBuf,
};
use syntax::{
    ast::{self},
    AstNode, TextRange,
};

use crate::assist_context::{AssistContext, Assists};

pub(crate) fn promote_mod_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
    let module = ctx.sema.to_module_def(ctx.frange.file_id)?;
    if module.is_mod_rs(ctx.db()) {
        return None;
    }
    let target = TextRange::new(
        source_file.syntax().text_range().start(),
        source_file.syntax().text_range().end(),
    );
    let path = format!("./{}/mod.rs", module.name(ctx.db())?.to_string());
    let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
    acc.add(
        AssistId("promote_mod_file", AssistKind::Refactor),
        "Promote Module to directory",
        target,
        |builder| {
            builder.move_file(ctx.frange.file_id, dst);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn trivial() {
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
$0fn t() {}
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
    }

    #[test]
    fn cursor_can_be_putted_anywhere() {
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
fn t() {}$0
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
fn t()$0 {}
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
fn t($0) {}
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
    }

    #[test]
    fn cannot_promote_mod_rs() {
        check_assist_not_applicable(
            promote_mod_file,
            r#"//- /main.rs
mod a;
//- /a/mod.rs
$0fn t() {}
"#,
        );
    }

    #[test]
    fn cannot_promote_main_and_lib_rs() {
        check_assist_not_applicable(
            promote_mod_file,
            r#"//- /main.rs
$0fn t() {}
"#,
        );
        check_assist_not_applicable(
            promote_mod_file,
            r#"//- /lib.rs
$0fn t() {}
"#,
        );
    }

    #[test]
    fn works_in_mod() {
        // note: /a/b.rs remains untouched
        check_assist(
            promote_mod_file,
            r#"//- /main.rs
mod a;
//- /a.rs
mod b;
$0fn t() {}
//- /a/b.rs
fn t1() {}
"#,
            r#"
//- /a/mod.rs
mod b;
fn t() {}
"#,
        );
    }
}
<commit_msg>Add docs strings<commit_after>use ide_db::{
    assists::{AssistId, AssistKind},
    base_db::AnchoredPathBuf,
};
use syntax::{
    ast::{self},
    AstNode, TextRange,
};

use crate::assist_context::{AssistContext, Assists};

// Assist: promote_mod_file
//
// Moves inline module's contents to a separate file.
//
// ```
// // a.rs
// $0fn t() {}
// ```
// ->
// ```
// // /a/mod.rs
// fn t() {}
// ```
pub(crate) fn promote_mod_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
    let module = ctx.sema.to_module_def(ctx.frange.file_id)?;
    if module.is_mod_rs(ctx.db()) {
        return None;
    }
    let target = TextRange::new(
        source_file.syntax().text_range().start(),
        source_file.syntax().text_range().end(),
    );
    let path = format!("./{}/mod.rs", module.name(ctx.db())?.to_string());
    let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
    acc.add(
        AssistId("promote_mod_file", AssistKind::Refactor),
        "Promote Module to directory",
        target,
        |builder| {
            builder.move_file(ctx.frange.file_id, dst);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn trivial() {
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
$0fn t() {}
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
    }

    #[test]
    fn cursor_can_be_putted_anywhere() {
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
fn t() {}$0
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
fn t()$0 {}
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
        check_assist(
            promote_mod_file,
            r#"
//- /main.rs
mod a;
//- /a.rs
fn t($0) {}
"#,
            r#"
//- /a/mod.rs
fn t() {}
"#,
        );
    }

    #[test]
    fn cannot_promote_mod_rs() {
        check_assist_not_applicable(
            promote_mod_file,
            r#"//- /main.rs
mod a;
//- /a/mod.rs
$0fn t() {}
"#,
        );
    }

    #[test]
    fn cannot_promote_main_and_lib_rs() {
        check_assist_not_applicable(
            promote_mod_file,
            r#"//- /main.rs
$0fn t() {}
"#,
        );
        check_assist_not_applicable(
            promote_mod_file,
            r#"//- /lib.rs
$0fn t() {}
"#,
        );
    }

    #[test]
    fn works_in_mod() {
        // note: /a/b.rs remains untouched
        check_assist(
            promote_mod_file,
            r#"//- /main.rs
mod a;
//- /a.rs
mod b;
$0fn t() {}
//- /a/b.rs
fn t1() {}
"#,
            r#"
//- /a/mod.rs
mod b;
fn t() {}
"#,
        );
    }
}
<|endoftext|>


<commit_before>use crate::{FieldCase, FieldInfo, MessagePath};
use std::collections::HashMap;

#[test]
fn md5_string_is_correct() {
    let mut hashes = HashMap::new();
    hashes.insert(
        MessagePath::new("p1", "xx").expect("Unexpected bad message path"),
        "ABCD".to_owned(),
    );
    hashes.insert(
        MessagePath::new("p2", "xx").expect("Unexpected bad message path"),
        "EFGH".to_owned(),
    );
    assert_eq!(
        FieldInfo::new("int64", "abc", FieldCase::Unit)
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "int64 abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("float32", "abc", FieldCase::Array(3))
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "float32[3] abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("int32", "abc", FieldCase::Vector)
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "int32[] abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("string", "abc", FieldCase::Const("something".into()))
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "string abc=something".to_owned()
    );
    assert_eq!(
        FieldInfo::new("xx", "abc", FieldCase::Vector)
            .unwrap()
            .md5_string("p1", &hashes)
            .unwrap(),
        "ABCD abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("xx", "abc", FieldCase::Array(3))
            .unwrap()
            .md5_string("p1", &hashes)
            .unwrap(),
        "ABCD abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("p2/xx", "abc", FieldCase::Unit)
            .unwrap()
            .md5_string("p1", &hashes)
            .unwrap(),
        "EFGH abc".to_owned()
    );
}

#[test]
fn display() {
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("int64", "abc", FieldCase::Unit).unwrap()
        ),
        "int64 abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("float32", "abc", FieldCase::Array(3)).unwrap()
        ),
        "float32[3] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("int32", "abc", FieldCase::Vector).unwrap()
        ),
        "int32[] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("string", "abc", FieldCase::Const("something".into())).unwrap()
        ),
        "string abc=something".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("xx", "abc", FieldCase::Vector).unwrap()
        ),
        "xx[] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("xx", "abc", FieldCase::Array(3)).unwrap()
        ),
        "xx[3] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("p2/xx", "abc", FieldCase::Unit).unwrap()
        ),
        "p2/xx abc".to_owned()
    );
}
<commit_msg>Test field info serialization<commit_after>use crate::{FieldCase, FieldInfo, MessagePath, Value};
use std::collections::HashMap;

#[test]
fn md5_string_is_correct() {
    let mut hashes = HashMap::new();
    hashes.insert(
        MessagePath::new("p1", "xx").expect("Unexpected bad message path"),
        "ABCD".to_owned(),
    );
    hashes.insert(
        MessagePath::new("p2", "xx").expect("Unexpected bad message path"),
        "EFGH".to_owned(),
    );
    assert_eq!(
        FieldInfo::new("int64", "abc", FieldCase::Unit)
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "int64 abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("float32", "abc", FieldCase::Array(3))
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "float32[3] abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("int32", "abc", FieldCase::Vector)
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "int32[] abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("string", "abc", FieldCase::Const("something".into()))
            .unwrap()
            .md5_string("", &hashes)
            .unwrap(),
        "string abc=something".to_owned()
    );
    assert_eq!(
        FieldInfo::new("xx", "abc", FieldCase::Vector)
            .unwrap()
            .md5_string("p1", &hashes)
            .unwrap(),
        "ABCD abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("xx", "abc", FieldCase::Array(3))
            .unwrap()
            .md5_string("p1", &hashes)
            .unwrap(),
        "ABCD abc".to_owned()
    );
    assert_eq!(
        FieldInfo::new("p2/xx", "abc", FieldCase::Unit)
            .unwrap()
            .md5_string("p1", &hashes)
            .unwrap(),
        "EFGH abc".to_owned()
    );
}

#[test]
fn display() {
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("int64", "abc", FieldCase::Unit).unwrap()
        ),
        "int64 abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("float32", "abc", FieldCase::Array(3)).unwrap()
        ),
        "float32[3] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("int32", "abc", FieldCase::Vector).unwrap()
        ),
        "int32[] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("string", "abc", FieldCase::Const("something".into())).unwrap()
        ),
        "string abc=something".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("xx", "abc", FieldCase::Vector).unwrap()
        ),
        "xx[] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("xx", "abc", FieldCase::Array(3)).unwrap()
        ),
        "xx[3] abc".to_owned()
    );
    assert_eq!(
        format!(
            "{}",
            FieldInfo::new("p2/xx", "abc", FieldCase::Unit).unwrap()
        ),
        "p2/xx abc".to_owned()
    );
}

#[test]
fn serialize_unit_field_case_as_string() {
    assert_eq!(
        serde_json::to_string(&FieldCase::Unit).unwrap(),
        r#""Unit""#,
    );
}

#[test]
fn serialize_vector_field_case_as_string() {
    assert_eq!(
        serde_json::to_string(&FieldCase::Vector).unwrap(),
        r#""Vector""#,
    );
}

#[test]
fn serialize_array_field_case_as_structure_with_length_integer() {
    assert_eq!(
        serde_json::to_string(&FieldCase::Array(12)).unwrap(),
        r#"{"Array":12}"#,
    );
}

#[test]
fn serialize_const_field_case_as_structure_with_value_string() {
    assert_eq!(
        serde_json::to_string(&FieldCase::Const("abc".into())).unwrap(),
        r#"{"Const":"abc"}"#,
    );
}

#[test]
fn deserialize_unit_field_case_from_string() {
    assert_eq!(
        serde_json::from_str::<FieldCase>(r#""Unit""#).unwrap(),
        FieldCase::Unit,
    );
}

#[test]
fn deserialize_vector_field_case_from_string() {
    assert_eq!(
        serde_json::from_str::<FieldCase>(r#""Vector""#).unwrap(),
        FieldCase::Vector,
    );
}

#[test]
fn deserialize_array_field_case_from_structure_with_length_integer() {
    assert_eq!(
        serde_json::from_str::<FieldCase>(r#"{"Array":12}"#).unwrap(),
        FieldCase::Array(12),
    );
}

#[test]
fn deserialize_const_field_case_from_structure_with_value_string() {
    assert_eq!(
        serde_json::from_str::<FieldCase>(r#"{"Const":"abc"}"#).unwrap(),
        FieldCase::Const("abc".into()),
    );
}

#[test]
fn serialize_field_info_as_correct_structure() {
    assert_eq!(
        serde_json::to_value(FieldInfo::new("p2/xx", "abc", FieldCase::Array(12)).unwrap())
            .unwrap(),
        serde_json::from_str::<serde_json::Value>(
            r#"
            {
                "datatype": "p2/xx",
                "name": "abc",
                "case": { "Array": 12 }
            }
            "#,
        )
        .unwrap(),
    );
    assert_eq!(
        serde_json::to_value(
            FieldInfo::new("int16", "abc", FieldCase::Const("33".into())).unwrap()
        )
        .unwrap(),
        serde_json::from_str::<serde_json::Value>(
            r#"
            {
                "datatype": "int16",
                "name": "abc",
                "case": { "Const": "33" }
            }
            "#,
        )
        .unwrap(),
    );
}

#[test]
fn deserialize_field_info_from_correct_structure() {
    assert_eq!(
        serde_json::from_str::<FieldInfo>(
            r#"
            {
                "datatype": "p2/xx",
                "name": "abc",
                "case": { "Array": 12 }
            }
            "#,
        )
        .unwrap(),
        FieldInfo::new("p2/xx", "abc", FieldCase::Array(12)).unwrap(),
    );
    assert_eq!(
        serde_json::from_str::<FieldInfo>(
            r#"
            {
                "datatype": "int16",
                "name": "abc",
                "case": { "Const": "33" }
            }
            "#,
        )
        .unwrap(),
        FieldInfo::new("int16", "abc", FieldCase::Const("33".into())).unwrap(),
    );
}

#[test]
fn deserialize_field_info_ensures_correct_const_value() {
    assert_eq!(
        serde_json::from_str::<FieldInfo>(
            r#"
            {
                "datatype": "int16",
                "name": "abc",
                "case": { "Const": "33" }
            }
            "#,
        )
        .unwrap()
        .const_value()
        .unwrap()
        .clone(),
        Value::I16(33),
    );
    assert!(serde_json::from_str::<FieldInfo>(
        r#"
            {
                "datatype": "int16",
                "name": "abc",
                "case": { "Const": "asdf" }
            }
            "#,
    )
    .is_err());
}
<|endoftext|>


<commit_before>#![feature(plugin)]

#![plugin(clippy)]

#![deny(clippy)]
#![deny(clippy_pedantic)]
#![allow(print_stdout)]

fn main() {
    let mut a = [1, 2, 3, 4, 5];

    let first = a[0]; //can I prevent this from happening? a lint for it? eg. I actually wanted &a[0]

    a[0] = 7;

    println!("The value of first is: {}", first);
}
<commit_msg>ok what?:)<commit_after>#![feature(plugin)]

#![plugin(clippy)]

#![deny(clippy)]
#![deny(clippy_pedantic)]
#![allow(print_stdout)]
#![allow(clone_on_copy)]

fn main() {
    let mut a = [1, 2, 3, 4, 5];

    //implicity Copy trait - the bane of Rust :)
    let first = a[0]; //can I prevent this Copy from happening? a lint for it? eg. I actually wanted &a[0] or a move
    let oldfirst = a[0].clone();//this is acceptable! but implicitly copy like above isn't! TODO: find a way to disable Copy trait!

    a[0] = 7;
    let reffirst:&i32 = &a[0]; //TODO: find out how to keep a ref and still allow assignment - eg. move this line above the assignment line a[0]=7; and have it work!

    println!("The value of first is: {} {} {}", first, oldfirst, reffirst);
}
<|endoftext|>