<commit_before>use ecs::*;
use game::*;
use util::LeakyReserver;
use math::Coord;

struct Env {
    sh: SpatialHashTable,
    ctx: EcsCtx,
    ids: LeakyReserver<EntityId>,
}

impl Env {
    fn new() -> Self {
        Env {
            sh: SpatialHashTable::new(),
            ctx: EcsCtx::new(),
            ids: LeakyReserver::new(),
        }
    }
}

#[test]
fn insert_remove() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let coord = Coord::new(1, 2);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(coord);
        entity.insert_solid();

        entity.id()
    };

    assert!(!env.sh.get(coord).solid());
    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action); // this resets the action so it can be reused
    assert!(env.sh.get(coord).solid());

    action.entity_mut(id).remove_solid();

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);
    assert!(!env.sh.get(coord).solid());
}

#[test]
fn insert_move() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);
    let end_coord = Coord::new(1, 3);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    action.entity_mut(id).insert_position(end_coord);

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(!env.sh.get(start_coord).solid());
    assert!(env.sh.get(end_coord).solid());
}

#[test]
fn remove_position() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    action.entity_mut(id).remove_position();

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(!env.sh.get(start_coord).solid());
}

#[test]
fn insert_solid() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);

        entity.id()
    };

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    action.entity_mut(id).insert_solid();

    assert!(!env.sh.get(start_coord).solid());

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());
}

#[test]
fn track_opacity() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);
    let end_coord = Coord::new(1, 3);

    // initialise with no opacity
    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);

        entity.id()
    };

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.0 * 10.0);

    // add an opacity of 0.5
    action.entity_mut(id).insert_opacity(0.5);

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.5 * 10.0);

    // decrease opacity to 0.2
    action.entity_mut(id).insert_opacity(0.2);

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.2 * 10.0);

    // move the entity
    action.entity_mut(id).insert_position(end_coord);

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);
    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.0 * 10.0);
    assert_eq!((env.sh.get(end_coord).opacity() * 10.0).round(), 0.2 * 10.0);
}

#[test]
fn insert_move_multiple() {
     let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);
    let end_coord = Coord::new(1, 3);

    // add solid entity
    let id_a = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());

    // add second solid entity in same cell
    let id_b = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());

    // move original entity
    action.entity_mut(id_a).insert_position(end_coord);

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());
    assert!(env.sh.get(end_coord).solid());

    // move second entity
    action.entity_mut(id_b).insert_position(end_coord);

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(!env.sh.get(start_coord).solid());
    assert!(env.sh.get(end_coord).solid());

    // move both entities in single action
    action.entity_mut(id_a).insert_position(start_coord);
    action.entity_mut(id_b).insert_position(start_coord);

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());
    assert!(!env.sh.get(end_coord).solid());
}

#[test]
fn entity_set() {
    let mut env = Env::new();

    let mut action = EcsAction::new();

    let coord_a = Coord::new(1, 2);
    let coord_b = Coord::new(1, 3);

    let id_a = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(coord_a);
        entity.id()
    };

    let id_b = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(coord_a);
        entity.id()
    };

    assert!(env.sh.get(coord_a).entity_ids().is_empty());

    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    {
        let entities = env.sh.get(coord_a).entity_ids();
        assert!(entities.contains(id_a));
        assert!(entities.contains(id_b));
        assert!(entities.len() == 2);
    }

    action.entity_mut(id_b).insert_position(coord_b);
    env.sh.update(Turn::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    {
        let entities_a = env.sh.get(coord_a).entity_ids();
        let entities_b = env.sh.get(coord_b).entity_ids();

        assert!(entities_a.len() == 1);
        assert!(entities_b.len() == 1);
        assert!(entities_a.contains(id_a));
        assert!(entities_b.contains(id_b));
    }
}
<commit_msg>Fixed spatial hash tests<commit_after>use ecs::*;
use game::*;
use util::LeakyReserver;
use math::Coord;

struct Env {
    sh: SpatialHashTable,
    ctx: EcsCtx,
    ids: LeakyReserver<EntityId>,
}

impl Env {
    fn new() -> Self {
        Env {
            sh: SpatialHashTable::new(),
            ctx: EcsCtx::new(),
            ids: LeakyReserver::new(),
        }
    }
}

#[test]
fn insert_remove() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let coord = Coord::new(1, 2);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(coord);
        entity.insert_solid();

        entity.id()
    };

    assert!(!env.sh.get(coord).solid());
    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action); // this resets the action so it can be reused
    assert!(env.sh.get(coord).solid());

    action.entity_mut(id).remove_solid();

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);
    assert!(!env.sh.get(coord).solid());
}

#[test]
fn insert_move() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);
    let end_coord = Coord::new(1, 3);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    action.entity_mut(id).insert_position(end_coord);

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(!env.sh.get(start_coord).solid());
    assert!(env.sh.get(end_coord).solid());
}

#[test]
fn remove_position() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    action.entity_mut(id).remove_position();

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(!env.sh.get(start_coord).solid());
}

#[test]
fn insert_solid() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);

    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);

        entity.id()
    };

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    action.entity_mut(id).insert_solid();

    assert!(!env.sh.get(start_coord).solid());

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());
}

#[test]
fn track_opacity() {
    let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);
    let end_coord = Coord::new(1, 3);

    // initialise with no opacity
    let id = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);

        entity.id()
    };

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.0 * 10.0);

    // add an opacity of 0.5
    action.entity_mut(id).insert_opacity(0.5);

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.5 * 10.0);

    // decrease opacity to 0.2
    action.entity_mut(id).insert_opacity(0.2);

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.2 * 10.0);

    // move the entity
    action.entity_mut(id).insert_position(end_coord);

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);
    assert_eq!((env.sh.get(start_coord).opacity() * 10.0).round(), 0.0 * 10.0);
    assert_eq!((env.sh.get(end_coord).opacity() * 10.0).round(), 0.2 * 10.0);
}

#[test]
fn insert_move_multiple() {
     let mut env = Env::new();

    let mut action = EcsAction::new();
    let start_coord = Coord::new(1, 2);
    let end_coord = Coord::new(1, 3);

    // add solid entity
    let id_a = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());

    // add second solid entity in same cell
    let id_b = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(start_coord);
        entity.insert_solid();

        entity.id()
    };

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());

    // move original entity
    action.entity_mut(id_a).insert_position(end_coord);

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());
    assert!(env.sh.get(end_coord).solid());

    // move second entity
    action.entity_mut(id_b).insert_position(end_coord);

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(!env.sh.get(start_coord).solid());
    assert!(env.sh.get(end_coord).solid());

    // move both entities in single action
    action.entity_mut(id_a).insert_position(start_coord);
    action.entity_mut(id_b).insert_position(start_coord);

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    assert!(env.sh.get(start_coord).solid());
    assert!(!env.sh.get(end_coord).solid());
}

#[test]
fn entity_set() {
    let mut env = Env::new();

    let mut action = EcsAction::new();

    let coord_a = Coord::new(1, 2);
    let coord_b = Coord::new(1, 3);

    let id_a = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(coord_a);
        entity.id()
    };

    let id_b = {
        let mut entity = action.entity_mut(env.ids.reserve());
        entity.insert_position(coord_a);
        entity.id()
    };

    assert!(env.sh.get(coord_a).entity_ids().is_empty());

    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    {
        let entities = env.sh.get(coord_a).entity_ids();
        assert!(entities.contains(id_a));
        assert!(entities.contains(id_b));
        assert!(entities.len() == 2);
    }

    action.entity_mut(id_b).insert_position(coord_b);
    env.sh.update(ActionEnv::new(&env.ctx, 0), &action);
    env.ctx.commit(&mut action);

    {
        let entities_a = env.sh.get(coord_a).entity_ids();
        let entities_b = env.sh.get(coord_b).entity_ids();

        assert!(entities_a.len() == 1);
        assert!(entities_b.len() == 1);
        assert!(entities_a.contains(id_a));
        assert!(entities_b.contains(id_b));
    }
}
<|endoftext|>


<commit_before>use image::{RgbImage, ImageBuffer};
use discrete_transforms::dct_2d::Dct2D;
use itertools::Itertools;

#[derive(Debug)]
pub struct StegObject {
    steg_image: RgbImage,
    tiles: Vec<u8>,
    message_length: u32,
    dct_tiles: Vec<f64>,
    quantized_tiles: Vec<i32>,
    message_bits: Vec<u8>,
    message: String
}

impl StegObject {
    pub fn new() -> StegObject {
        StegObject {
            steg_image: ImageBuffer::new(0, 0),
            tiles: vec![],
            message_length: 0,
            dct_tiles: vec![],
            quantized_tiles: vec![],
            message_bits: vec![],
            message: String::new()
        }
    }

    pub fn set_steg_image(&mut self, input_path: &'static str) -> &mut Self {
        self.steg_image = image::open(input_path).unwrap().as_rgb8().unwrap().clone();

        self
    }

    pub fn set_message_length(&mut self, length: u32 ) -> &mut Self{
        self.message_length = length;

        self
    }

    pub fn decode(&mut self) {
        self.tile_image();

        let mut dct = Dct2D::new();

        for chunk in &self.tiles.iter().chunks(64) {
            let input = chunk.map(|x| *x as f64).collect_vec();

            dct.set_input(input);

            self.dct_tiles.extend(&dct.forward());
        }

        self.quantize();
        self.create_message();
    }

    fn tile_image(&mut self) {
        let (width, height) = self.steg_image.dimensions();
        let mut count = 0;

        for row_index in 0..(height / 8) as u32 {
            for col_index in 0..(width / 8) as u32 {
                for channel in 0..3 {
                    if count == self.message_length {
                        break
                    }

                    for row in 0..8 {
                        for column in 0..8 {
                            let pixel = self.steg_image.get_pixel(column + (col_index * 8),
                                                                     row + (row_index * 8));

                            pixel_count += 1;

                            self.tiles.push(pixel.data[channel]);
                        }
                    }

                    count += 1;
                }
            }
        }
    }

    fn quantize(&mut self) {
        for x in 0..self.dct_tiles.len() / 64 {
            let quantized_coeff = self.dct_tiles[x * 64].round() / 16.0;

            self.quantized_tiles.push(quantized_coeff.round() as i32);
        }
    }

    fn create_message(&mut self) {
        for chunk in &self.quantized_tiles.iter().chunks(8) {
            let mut byte = 0_u8;

            let mut message_bits = chunk.map(|b| (*b % 2) as u8).collect_vec();

            message_bits.reverse();

            for (index, bit) in message_bits.into_iter().enumerate() {
                let temp = bit << index as u8;
                byte = byte + temp;
            }

            self.message.push_str(&String::from_utf8(vec![byte; 1]).unwrap());
        }

        println!("{:?}", self.message);
    }
}

#[test]
fn test_decode() {
    let mut steg_object = StegObject::new();

    steg_object.set_message_length(8);
    steg_object.set_steg_image("output.png");
    steg_object.decode();
}<commit_msg>Remove unused code<commit_after>use image::{RgbImage, ImageBuffer};
use discrete_transforms::dct_2d::Dct2D;
use itertools::Itertools;

#[derive(Debug)]
pub struct StegObject {
    steg_image: RgbImage,
    tiles: Vec<u8>,
    message_length: u32,
    dct_tiles: Vec<f64>,
    quantized_tiles: Vec<i32>,
    message_bits: Vec<u8>,
    message: String
}

impl StegObject {
    pub fn new() -> StegObject {
        StegObject {
            steg_image: ImageBuffer::new(0, 0),
            tiles: vec![],
            message_length: 0,
            dct_tiles: vec![],
            quantized_tiles: vec![],
            message_bits: vec![],
            message: String::new()
        }
    }

    pub fn set_steg_image(&mut self, input_path: &'static str) -> &mut Self {
        self.steg_image = image::open(input_path).unwrap().as_rgb8().unwrap().clone();

        self
    }

    pub fn set_message_length(&mut self, length: u32 ) -> &mut Self{
        self.message_length = length;

        self
    }

    pub fn decode(&mut self) {
        self.tile_image();

        let mut dct = Dct2D::new();

        for chunk in &self.tiles.iter().chunks(64) {
            let input = chunk.map(|x| *x as f64).collect_vec();

            dct.set_input(input);

            self.dct_tiles.extend(&dct.forward());
        }

        self.quantize();
        self.create_message();
    }

    fn tile_image(&mut self) {
        let (width, height) = self.steg_image.dimensions();
        let mut count = 0;

        for row_index in 0..(height / 8) as u32 {
            for col_index in 0..(width / 8) as u32 {
                for channel in 0..3 {
                    if count == self.message_length {
                        break
                    }

                    for row in 0..8 {
                        for column in 0..8 {
                            let pixel = self.steg_image.get_pixel(column + (col_index * 8),
                                                                     row + (row_index * 8));

                            self.tiles.push(pixel.data[channel]);
                        }
                    }

                    count += 1;
                }
            }
        }
    }

    fn quantize(&mut self) {
        for x in 0..self.dct_tiles.len() / 64 {
            let quantized_coeff = self.dct_tiles[x * 64].round() / 16.0;

            self.quantized_tiles.push(quantized_coeff.round() as i32);
        }
    }

    fn create_message(&mut self) {
        for chunk in &self.quantized_tiles.iter().chunks(8) {
            let mut byte = 0_u8;

            let mut message_bits = chunk.map(|b| (*b % 2) as u8).collect_vec();

            message_bits.reverse();

            for (index, bit) in message_bits.into_iter().enumerate() {
                let temp = bit << index as u8;
                byte = byte + temp;
            }

            self.message.push_str(&String::from_utf8(vec![byte; 1]).unwrap());
        }

        println!("{:?}", self.message);
    }
}

#[test]
fn test_decode() {
    let mut steg_object = StegObject::new();

    steg_object.set_message_length(8);
    steg_object.set_steg_image("output.png");
    steg_object.decode();
}<|endoftext|>


<commit_before>use super::btree::{BPlusTree, RTCursor as BPlusTreeCursor};
use super::sstable::*;
use super::*;
use client::AsyncClient;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::segs::MAX_SEGMENT_SIZE;
use std::collections::BTreeSet;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{mem, ptr};

const LEVEL_M_MAX_ELEMENTS_COUNT: usize = LEVEL_M * LEVEL_M * LEVEL_M;
const LEVEL_ELEMENTS_MULTIPLIER: usize = 10;
const LEVEL_DIFF_MULTIPLIER: usize = 10;
const LEVEL_M: usize = super::btree::NUM_KEYS;
const LEVEL_1: usize = LEVEL_M * LEVEL_DIFF_MULTIPLIER;
const LEVEL_2: usize = LEVEL_1 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_3: usize = LEVEL_2 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_4: usize = LEVEL_3 * LEVEL_DIFF_MULTIPLIER;

type LevelTrees = Vec<Box<SSLevelTree>>;

macro_rules! with_levels {
    ($($sym:ident, $level_size:ident;)*) => {
        $(
            type $sym = [EntryKey; $level_size];
            impl_sspage_slice!($sym, EntryKey, $level_size);
        )*

        fn init_lsm_level_trees(neb_client: &Arc<AsyncClient>) -> (LevelTrees, Vec<usize>, Vec<usize>) {
            let mut trees = LevelTrees::new();
            let mut max_elements_list = Vec::new();
            let mut max_elements = LEVEL_M_MAX_ELEMENTS_COUNT;
            let mut page_sizes = Vec::new();
            $(
                max_elements *= LEVEL_ELEMENTS_MULTIPLIER;
                trees.push(box LevelTree::<$sym>::new(neb_client));
                max_elements_list.push(max_elements);
                page_sizes.push($level_size);
                const_assert!($level_size * KEY_SIZE <= MAX_SEGMENT_SIZE);
            )*
            return (trees, max_elements_list, page_sizes);
        }
    };
}

with_levels! {
    L1, LEVEL_1;
    L2, LEVEL_2;
    L3, LEVEL_3;
    L4, LEVEL_4;
}

pub struct LSMTree {
    pub level_m: BPlusTree,
    trees: LevelTrees,
    // use Vec here for convenience
    max_sizes: Vec<usize>,
    page_sizes: Vec<usize>,
}

unsafe impl Send for LSMTree {}
unsafe impl Sync for LSMTree {}

impl LSMTree {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        let (trees, max_sizes, page_sizes) = init_lsm_level_trees(neb_client);
        let lsm_tree = Arc::new(LSMTree {
            level_m: BPlusTree::new(neb_client),
            trees,
            max_sizes,
            page_sizes,
        });
        let tree_clone = lsm_tree.clone();
        thread::spawn(move || {
            tree_clone.sentinel();
        });
        lsm_tree
    }

    pub fn insert(&self, mut key: EntryKey, id: &Id) {
        key_with_id(&mut key, id);
        self.level_m.insert(&key)
    }

    pub fn remove(&self, mut key: EntryKey, id: &Id) -> bool {
        key_with_id(&mut key, id);
        let m_deleted = self.level_m.remove(&key);
        let levels_deleted = self
            .trees
            .iter()
            .map(|tree| tree.mark_deleted(&key))
            .collect_vec() // collect here to prevent short circuit
            .into_iter()
            .any(|d| d);
        m_deleted || levels_deleted
    }

    pub fn seek(&self, mut key: EntryKey, ordering: Ordering) -> LSMTreeCursor {
        match ordering {
            Ordering::Forward => key_with_id(&mut key, &Id::unit_id()),
            Ordering::Backward => key_with_id(&mut key, &Id::new(::std::u64::MAX, ::std::u64::MAX)),
        };
        let mut cursors: Vec<Box<Cursor>> = vec![box self.level_m.seek(&key, ordering)];
        for tree in &self.trees {
            cursors.push(tree.seek(&key, ordering));
        }
        return LSMTreeCursor::new(
            cursors,
            self.trees.iter().map(|t| t.tombstones()).collect_vec(),
        );
    }

    fn sentinel(&self) {
        self.check_and_merge(
            LEVEL_M_MAX_ELEMENTS_COUNT,
            self.page_sizes[0],
            &mut BTreeSet::new(),
            &self.level_m,
            &*self.trees[0],
        );
        for i in 0..self.trees.len() - 1 {
            let upper = &*self.trees[i];
            let lower = &*self.trees[i + 1];
            let upper_tombstons_ref = upper.tombstones();
            let mut upper_tombstones = upper_tombstons_ref.write();
            self.check_and_merge(
                self.max_sizes[i],
                self.page_sizes[i + 1],
                &mut *upper_tombstones,
                upper,
                lower,
            );
        }
        thread::sleep(Duration::from_millis(100));
    }

    fn check_and_merge<U, L>(
        &self,
        max_elements: usize,
        upper_page_size: usize,
        upper_tombstones: &mut TombstonesInner,
        upper_level: &U,
        lower_level: &L,
    ) where
        U: MergeableTree + ?Sized,
        L: SSLevelTree + ?Sized,
    {
        let elements = upper_level.elements();
        if elements > max_elements {
            debug!(
                "upper level have elements {} exceeds {}, start level merging",
                elements, max_elements
            );
            let entries_to_merge = upper_page_size;
            let guard = upper_level.prepare_level_merge();
            let mut pages = vec![guard.last_page()];
            let mut collected_entries = pages.last().unwrap().keys().len();
            while collected_entries < entries_to_merge {
                let next_page = pages.last().unwrap().next();
                collected_entries += next_page.keys().len();
                pages.push(next_page);
            }
            let mut entries = vec![];
            for page in &pages {
                entries.append(&mut Vec::from(page.keys()));
            }
            debug!("going to merge {} entries", entries.len());
            lower_level.merge(entries.as_mut_slice(), upper_tombstones);
            guard.remove_pages(pages.iter().map(|p| p.keys()).collect_vec().as_slice())
        }
    }

    pub fn len(&self) -> usize {
        let mem_len = self.level_m.len();
        let levels_len_sum = self.trees.iter().map(|tree| tree.len()).sum::<usize>();
        return mem_len + levels_len_sum;
    }
}

pub struct LSMTreeCursor {
    level_cursors: Vec<Box<Cursor>>,
    tombstones: Vec<Arc<Tombstones>>,
}

impl LSMTreeCursor {
    fn new(cursors: Vec<Box<Cursor>>, tombstones: Vec<Arc<Tombstones>>) -> Self {
        LSMTreeCursor {
            tombstones,
            level_cursors: cursors,
        }
    }

    fn next_candidate(&mut self) -> (bool, usize) {
        // TODO: redo this part
        let min_tree = self
            .level_cursors
            .iter()
            .enumerate()
            .map(|(i, cursor)| (i, cursor.current()))
            .filter_map(|(i, current)| current.map(|current_val| (i, current_val)))
            .min_by_key(|(i, val)| val.clone())
            .map(|(id, _)| id);
        if let Some(id) = min_tree {
            let min_has_next = self.level_cursors[id].next();
            if !min_has_next {
                let next = self
                    .level_cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(level, cursor)| cursor.current().map(|key| (id, key)))
                    .min_by_key(|(level, key)| key.clone());
                if let Some((id, _)) = next {
                    return (true, id);
                }
            } else {
                return (true, id);
            }
        }
        return (false, 0);
    }
}

impl Cursor for LSMTreeCursor {
    fn next(&mut self) -> bool {
        loop {
            let (has_next, candidate_level) = self.next_candidate();
            if !has_next {
                break;
            }
            if candidate_level == 0 {
                return has_next;
            }
            let candidate_key = self.level_cursors[candidate_level].current().unwrap();
            if self.tombstones[candidate_level + 1]
                .read()
                .contains(candidate_key)
            {
                // marked in tombstone, skip
                continue;
            }
            return true;
        }
        return false;
    }

    fn current(&self) -> Option<&EntryKey> {
        self.level_cursors.iter().filter_map(|c| c.current()).min()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use byteorder::BigEndian;
    use byteorder::WriteBytesExt;
    use client;
    use futures::prelude::*;
    use rand::distributions::Uniform;
    use rand::thread_rng;
    use rand::Rng;
    use rayon::prelude::*;
    use server::NebServer;
    use server::ServerOptions;
    use std::env;
    use std::io::Cursor as StdCursor;

    fn u64_to_slice(n: u64) -> [u8; 8] {
        let mut key_slice = [0u8; 8];
        {
            let mut cursor = StdCursor::new(&mut key_slice[..]);
            cursor.write_u64::<BigEndian>(n);
        };
        key_slice
    }

    #[test]
    pub fn insertions() {
        env_logger::init();
        let server_group = "sstable_index_init";
        let server_addr = String::from("127.0.0.1:5600");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 4 * 1024 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], server_group).unwrap(),
        );
        client.new_schema_with_id(super::get_schema()).wait();
        let tree = LSMTree::new(&client);
        let num = env::var("LSM_TREE_TEST_ITEMS")
            // this value cannot do anything useful to the test
            // must arrange a long-term test to cover every levels
            .unwrap_or("1000".to_string())
            .parse::<u64>()
            .unwrap();

        let tree_clone = tree.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_secs(10));
            let tree_len = tree_clone.len();
            debug!(
                "LSM-Tree now have {}/{} elements, total {:.2}%",
                tree_len,
                num,
                tree_len as f32 / num as f32 * 100.0
            );
        });

        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
            let i = *i;
            let id = Id::new(0, i);
            let key_slice = u64_to_slice(i);
            let key = SmallVec::from_slice(&key_slice);
            tree.insert(key, &id);
        });

        if tree.len() > LEVEL_M_MAX_ELEMENTS_COUNT {
            debug!("Sleep 5 minute for level merge");
            thread::sleep(Duration::from_secs(5 * 60));
        }
        debug!("Start validations");
        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
            let mut rng = rand::rngs::OsRng::new().unwrap();
            let die_range = Uniform::new_inclusive(1, 6);
            let mut roll_die = rng.sample_iter(&die_range);
            let i = *i;
            let id = Id::new(0, i);
            let key_slice = u64_to_slice(i);
            let mut key = SmallVec::from_slice(&key_slice);
            debug!("checking: {}", i);
            let mut cursor = tree.seek(key.clone(), Ordering::Forward);
            key_with_id(&mut key, &id);
            assert_eq!(cursor.current(), Some(&key), "{}", i);
            if roll_die.next().unwrap() == 6 {
                for j in i..num {
                    let id = Id::new(0, j);
                    let key_slice = u64_to_slice(j);
                    let mut key = SmallVec::from_slice(&key_slice);
                    key_with_id(&mut key, &id);
                    assert_eq!(cursor.current(), Some(&key), "{}/{}", i, j);
                    assert_eq!(cursor.next(), j != num - 1, "{}/{}", i, j);
                }
            }
        });
    }
}
<commit_msg>infinite loop on checking size<commit_after>use super::btree::{BPlusTree, RTCursor as BPlusTreeCursor};
use super::sstable::*;
use super::*;
use client::AsyncClient;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::segs::MAX_SEGMENT_SIZE;
use std::collections::BTreeSet;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{mem, ptr};

const LEVEL_M_MAX_ELEMENTS_COUNT: usize = LEVEL_M * LEVEL_M * LEVEL_M;
const LEVEL_ELEMENTS_MULTIPLIER: usize = 10;
const LEVEL_DIFF_MULTIPLIER: usize = 10;
const LEVEL_M: usize = super::btree::NUM_KEYS;
const LEVEL_1: usize = LEVEL_M * LEVEL_DIFF_MULTIPLIER;
const LEVEL_2: usize = LEVEL_1 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_3: usize = LEVEL_2 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_4: usize = LEVEL_3 * LEVEL_DIFF_MULTIPLIER;

type LevelTrees = Vec<Box<SSLevelTree>>;

macro_rules! with_levels {
    ($($sym:ident, $level_size:ident;)*) => {
        $(
            type $sym = [EntryKey; $level_size];
            impl_sspage_slice!($sym, EntryKey, $level_size);
        )*

        fn init_lsm_level_trees(neb_client: &Arc<AsyncClient>) -> (LevelTrees, Vec<usize>, Vec<usize>) {
            let mut trees = LevelTrees::new();
            let mut max_elements_list = Vec::new();
            let mut max_elements = LEVEL_M_MAX_ELEMENTS_COUNT;
            let mut page_sizes = Vec::new();
            $(
                max_elements *= LEVEL_ELEMENTS_MULTIPLIER;
                trees.push(box LevelTree::<$sym>::new(neb_client));
                max_elements_list.push(max_elements);
                page_sizes.push($level_size);
                const_assert!($level_size * KEY_SIZE <= MAX_SEGMENT_SIZE);
            )*
            return (trees, max_elements_list, page_sizes);
        }
    };
}

with_levels! {
    L1, LEVEL_1;
    L2, LEVEL_2;
    L3, LEVEL_3;
    L4, LEVEL_4;
}

pub struct LSMTree {
    pub level_m: BPlusTree,
    trees: LevelTrees,
    // use Vec here for convenience
    max_sizes: Vec<usize>,
    page_sizes: Vec<usize>,
}

unsafe impl Send for LSMTree {}
unsafe impl Sync for LSMTree {}

impl LSMTree {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        let (trees, max_sizes, page_sizes) = init_lsm_level_trees(neb_client);
        let lsm_tree = Arc::new(LSMTree {
            level_m: BPlusTree::new(neb_client),
            trees,
            max_sizes,
            page_sizes,
        });
        let tree_clone = lsm_tree.clone();
        thread::spawn(move || {
            tree_clone.sentinel();
        });
        lsm_tree
    }

    pub fn insert(&self, mut key: EntryKey, id: &Id) {
        key_with_id(&mut key, id);
        self.level_m.insert(&key)
    }

    pub fn remove(&self, mut key: EntryKey, id: &Id) -> bool {
        key_with_id(&mut key, id);
        let m_deleted = self.level_m.remove(&key);
        let levels_deleted = self
            .trees
            .iter()
            .map(|tree| tree.mark_deleted(&key))
            .collect_vec() // collect here to prevent short circuit
            .into_iter()
            .any(|d| d);
        m_deleted || levels_deleted
    }

    pub fn seek(&self, mut key: EntryKey, ordering: Ordering) -> LSMTreeCursor {
        match ordering {
            Ordering::Forward => key_with_id(&mut key, &Id::unit_id()),
            Ordering::Backward => key_with_id(&mut key, &Id::new(::std::u64::MAX, ::std::u64::MAX)),
        };
        let mut cursors: Vec<Box<Cursor>> = vec![box self.level_m.seek(&key, ordering)];
        for tree in &self.trees {
            cursors.push(tree.seek(&key, ordering));
        }
        return LSMTreeCursor::new(
            cursors,
            self.trees.iter().map(|t| t.tombstones()).collect_vec(),
        );
    }

    fn sentinel(&self) {
        self.check_and_merge(
            LEVEL_M_MAX_ELEMENTS_COUNT,
            self.page_sizes[0],
            &mut BTreeSet::new(),
            &self.level_m,
            &*self.trees[0],
        );
        for i in 0..self.trees.len() - 1 {
            let upper = &*self.trees[i];
            let lower = &*self.trees[i + 1];
            let upper_tombstons_ref = upper.tombstones();
            let mut upper_tombstones = upper_tombstons_ref.write();
            self.check_and_merge(
                self.max_sizes[i],
                self.page_sizes[i + 1],
                &mut *upper_tombstones,
                upper,
                lower,
            );
        }
        thread::sleep(Duration::from_millis(100));
    }

    fn check_and_merge<U, L>(
        &self,
        max_elements: usize,
        upper_page_size: usize,
        upper_tombstones: &mut TombstonesInner,
        upper_level: &U,
        lower_level: &L,
    ) where
        U: MergeableTree + ?Sized,
        L: SSLevelTree + ?Sized,
    {
        let elements = upper_level.elements();
        if elements > max_elements {
            debug!(
                "upper level have elements {} exceeds {}, start level merging",
                elements, max_elements
            );
            let entries_to_merge = upper_page_size;
            let guard = upper_level.prepare_level_merge();
            let mut pages = vec![guard.last_page()];
            let mut collected_entries = pages.last().unwrap().keys().len();
            while collected_entries < entries_to_merge {
                let next_page = pages.last().unwrap().next();
                collected_entries += next_page.keys().len();
                pages.push(next_page);
            }
            let mut entries = vec![];
            for page in &pages {
                entries.append(&mut Vec::from(page.keys()));
            }
            debug!("going to merge {} entries", entries.len());
            lower_level.merge(entries.as_mut_slice(), upper_tombstones);
            guard.remove_pages(pages.iter().map(|p| p.keys()).collect_vec().as_slice())
        }
    }

    pub fn len(&self) -> usize {
        let mem_len = self.level_m.len();
        let levels_len_sum = self.trees.iter().map(|tree| tree.len()).sum::<usize>();
        return mem_len + levels_len_sum;
    }
}

pub struct LSMTreeCursor {
    level_cursors: Vec<Box<Cursor>>,
    tombstones: Vec<Arc<Tombstones>>,
}

impl LSMTreeCursor {
    fn new(cursors: Vec<Box<Cursor>>, tombstones: Vec<Arc<Tombstones>>) -> Self {
        LSMTreeCursor {
            tombstones,
            level_cursors: cursors,
        }
    }

    fn next_candidate(&mut self) -> (bool, usize) {
        // TODO: redo this part
        let min_tree = self
            .level_cursors
            .iter()
            .enumerate()
            .map(|(i, cursor)| (i, cursor.current()))
            .filter_map(|(i, current)| current.map(|current_val| (i, current_val)))
            .min_by_key(|(i, val)| val.clone())
            .map(|(id, _)| id);
        if let Some(id) = min_tree {
            let min_has_next = self.level_cursors[id].next();
            if !min_has_next {
                let next = self
                    .level_cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(level, cursor)| cursor.current().map(|key| (id, key)))
                    .min_by_key(|(level, key)| key.clone());
                if let Some((id, _)) = next {
                    return (true, id);
                }
            } else {
                return (true, id);
            }
        }
        return (false, 0);
    }
}

impl Cursor for LSMTreeCursor {
    fn next(&mut self) -> bool {
        loop {
            let (has_next, candidate_level) = self.next_candidate();
            if !has_next {
                break;
            }
            if candidate_level == 0 {
                return has_next;
            }
            let candidate_key = self.level_cursors[candidate_level].current().unwrap();
            if self.tombstones[candidate_level + 1]
                .read()
                .contains(candidate_key)
            {
                // marked in tombstone, skip
                continue;
            }
            return true;
        }
        return false;
    }

    fn current(&self) -> Option<&EntryKey> {
        self.level_cursors.iter().filter_map(|c| c.current()).min()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use byteorder::BigEndian;
    use byteorder::WriteBytesExt;
    use client;
    use futures::prelude::*;
    use rand::distributions::Uniform;
    use rand::thread_rng;
    use rand::Rng;
    use rayon::prelude::*;
    use server::NebServer;
    use server::ServerOptions;
    use std::env;
    use std::io::Cursor as StdCursor;

    fn u64_to_slice(n: u64) -> [u8; 8] {
        let mut key_slice = [0u8; 8];
        {
            let mut cursor = StdCursor::new(&mut key_slice[..]);
            cursor.write_u64::<BigEndian>(n);
        };
        key_slice
    }

    #[test]
    pub fn insertions() {
        env_logger::init();
        let server_group = "sstable_index_init";
        let server_addr = String::from("127.0.0.1:5600");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 4 * 1024 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], server_group).unwrap(),
        );
        client.new_schema_with_id(super::get_schema()).wait();
        let tree = LSMTree::new(&client);
        let num = env::var("LSM_TREE_TEST_ITEMS")
            // this value cannot do anything useful to the test
            // must arrange a long-term test to cover every levels
            .unwrap_or("1000".to_string())
            .parse::<u64>()
            .unwrap();

        let tree_clone = tree.clone();
        thread::spawn(move || {
            loop {
                thread::sleep(Duration::from_secs(10));
                let tree_len = tree_clone.len();
                debug!(
                    "LSM-Tree now have {}/{} elements, total {:.2}%",
                    tree_len,
                    num,
                    tree_len as f32 / num as f32 * 100.0
                );
            }
        });

        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
            let i = *i;
            let id = Id::new(0, i);
            let key_slice = u64_to_slice(i);
            let key = SmallVec::from_slice(&key_slice);
            tree.insert(key, &id);
        });

        if tree.len() > LEVEL_M_MAX_ELEMENTS_COUNT {
            debug!("Sleep 5 minute for level merge");
            thread::sleep(Duration::from_secs(5 * 60));
        }
        debug!("Start validations");
        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
            let mut rng = rand::rngs::OsRng::new().unwrap();
            let die_range = Uniform::new_inclusive(1, 6);
            let mut roll_die = rng.sample_iter(&die_range);
            let i = *i;
            let id = Id::new(0, i);
            let key_slice = u64_to_slice(i);
            let mut key = SmallVec::from_slice(&key_slice);
            debug!("checking: {}", i);
            let mut cursor = tree.seek(key.clone(), Ordering::Forward);
            key_with_id(&mut key, &id);
            assert_eq!(cursor.current(), Some(&key), "{}", i);
            if roll_die.next().unwrap() == 6 {
                for j in i..num {
                    let id = Id::new(0, j);
                    let key_slice = u64_to_slice(j);
                    let mut key = SmallVec::from_slice(&key_slice);
                    key_with_id(&mut key, &id);
                    assert_eq!(cursor.current(), Some(&key), "{}/{}", i, j);
                    assert_eq!(cursor.next(), j != num - 1, "{}/{}", i, j);
                }
            }
        });
    }
}
<|endoftext|>


<commit_before><commit_msg>ready to attack<commit_after><|endoftext|>


<commit_before><commit_msg>use std::mem to call mem::swap<commit_after><|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! 64-bit IDT gate implementation
use ::segment;
use super::{GateFlags};
use super::super::{InterruptHandler, ErrorCodeHandler};

use core::{convert, mem};
use core::marker::PhantomData;

impl GateFlags {

    /// Returns a new trap gate
    pub const fn new_trap() -> Self {
        GateFlags { bits: super::TRAP_GATE_32.bits | super::PRESENT.bits }
    }

    /// Returns a new call gate
    pub const fn new_task() -> Self {
        GateFlags { bits: super::TASK_GATE_32.bits | super::PRESENT.bits }
    }

    /// Returns a new interrupt gate
    pub const fn new_interrupt() -> Self {
        GateFlags { bits: super::INT_GATE_32.bits | super::PRESENT.bits }
    }

}

/// An IDT entry is called a gate.
///
/// Based on [code](http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure)
/// from the OS Dev Wiki.
///
/// Refer also to "6.14.1 64-Bit Mode IDT"  and "Table 3-2. System-Segment and
/// Gate-Descriptor Types" in the _Intel® 64 and IA-32 Architectures
/// Software Developer’s Manual_
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct Gate<H = InterruptHandler>
    { /// bits 0 - 15 of the offset
      pub offset_lower: u16
    , /// code segment selector (GDT or LDT)
      pub selector: segment::Selector
    , /// always zero
      _zero: u8
    , /// indicates the gate's type and attributes.
      /// the second half indicates the type:
      ///   + `0b1100`: Call gate
      ///   + `0b1110`: Interrupt gate
      ///   + `0b1111`: Trap Gate
      pub flags: GateFlags
    , /// bits 16 - 31 of the offset
      pub offset_mid: u16
    , /// bits 32 - 63 of the offset
      pub offset_upper: u32
    , /// always zero (according to the spec, this is "reserved")
      _reserved: u32
    , _handler_type: PhantomData<H>
    }

impl<H> Gate<H> {

    /// Creates a new IDT gate marked as `absent`.
    ///
    /// This is basically just for filling the new IDT table
    /// with valid (but useless) gates upon init.
    ///
    /// Actually triggering an absent interrupt will send a General Protection
    /// fault (13).
    pub const fn absent() -> Self {
       Gate { offset_lower: 0
            , selector: segment::Selector::from_raw(0)
            , _zero: 0
            , flags: GateFlags { bits: 0 }
            , offset_mid: 0
            , offset_upper: 0
            , _reserved: 0
            , _handler_type: PhantomData
            }
    }

    pub fn set_handler(&mut self, handler: H) -> &mut Self {
        let (low, mid, high): (u16, u16, u32)
            = unsafe{ mem::transmute(handler) };

        self.offset_lower = low;
        self.offset_mid = mid;
        self.offset_high = high;

        self
    }

}

impl<H> Default for Gate<H> {
    fn default() -> Self {
        Gate { offset_lower: 0
             , selector: segment::Selector::from_raw(0)
             , _zero: 0
             , flags: GateFlags { bits: 0 }
             , offset_mid: 0
             , offset_upper: 0
             , _reserved: 0
             , _handler_type: PhantomData
             }
    }
}

impl convert::From<InterruptHandler> for Gate<InterruptHandler> {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    fn from(handler: InterruptHandler) -> Self {
        unsafe { // trust me on this, `mem::transmute()` is glorious black magic
                let (low, mid, high): (u16, u16, u32) = mem::transmute(handler);

            Gate { offset_lower: low
                 , offset_mid: mid
                 , offset_upper: high
                 , selector: segment::Selector::from_cs()
                 , flags: GateFlags::new_interrupt()
                 , ..Default::default()
                 }
        }
    }
}

impl convert::From<ErrorCodeHandler> for Gate<ErrorCodeHandler> {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    fn from(handler: ErrorCodeHandler) -> Self {
        unsafe { // trust me on this, `mem::transmute()` is glorious black magic
                let (low, mid, high): (u16, u16, u32) = mem::transmute(handler);

            Gate { offset_lower: low
                 , offset_mid: mid
                 , offset_upper: high
                 , selector: segment::Selector::from_cs()
                 , flags: GateFlags::new_interrupt()
                 , ..Default::default()
                 }
        }
    }
}

impl convert::From<*const u8> for Gate {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    ///
    /// This should probably not be used, if it can possibly be avoided.
    //  TODO: it would be really nice if we didn't need this any more.
    //        after the Revolution, once handlers are created in Rust-land with
    //        naked functions...
    fn from(handler: *const u8) -> Self {
        unsafe {
            let (low, mid, high): (u16, u16, u32) = mem::transmute(handler);

            Gate { offset_lower: low
                 , offset_mid: mid
                 , offset_upper: high
                 , selector: segment::Selector::from_cs()
                 , flags: GateFlags::new_interrupt()
                 , ..Default::default()
                 }
        }
    }
}
<commit_msg>fix(gate64): use of field name "offset_high" rather than offset_upper<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! 64-bit IDT gate implementation
use ::segment;
use super::{GateFlags};
use super::super::{InterruptHandler, ErrorCodeHandler};

use core::{convert, mem};
use core::marker::PhantomData;

impl GateFlags {

    /// Returns a new trap gate
    pub const fn new_trap() -> Self {
        GateFlags { bits: super::TRAP_GATE_32.bits | super::PRESENT.bits }
    }

    /// Returns a new call gate
    pub const fn new_task() -> Self {
        GateFlags { bits: super::TASK_GATE_32.bits | super::PRESENT.bits }
    }

    /// Returns a new interrupt gate
    pub const fn new_interrupt() -> Self {
        GateFlags { bits: super::INT_GATE_32.bits | super::PRESENT.bits }
    }

}

/// An IDT entry is called a gate.
///
/// Based on [code](http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure)
/// from the OS Dev Wiki.
///
/// Refer also to "6.14.1 64-Bit Mode IDT"  and "Table 3-2. System-Segment and
/// Gate-Descriptor Types" in the _Intel® 64 and IA-32 Architectures
/// Software Developer’s Manual_
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct Gate<H = InterruptHandler>
    { /// bits 0 - 15 of the offset
      pub offset_lower: u16
    , /// code segment selector (GDT or LDT)
      pub selector: segment::Selector
    , /// always zero
      _zero: u8
    , /// indicates the gate's type and attributes.
      /// the second half indicates the type:
      ///   + `0b1100`: Call gate
      ///   + `0b1110`: Interrupt gate
      ///   + `0b1111`: Trap Gate
      pub flags: GateFlags
    , /// bits 16 - 31 of the offset
      pub offset_mid: u16
    , /// bits 32 - 63 of the offset
      pub offset_upper: u32
    , /// always zero (according to the spec, this is "reserved")
      _reserved: u32
    , _handler_type: PhantomData<H>
    }

impl<H> Gate<H> {

    /// Creates a new IDT gate marked as `absent`.
    ///
    /// This is basically just for filling the new IDT table
    /// with valid (but useless) gates upon init.
    ///
    /// Actually triggering an absent interrupt will send a General Protection
    /// fault (13).
    pub const fn absent() -> Self {
       Gate { offset_lower: 0
            , selector: segment::Selector::from_raw(0)
            , _zero: 0
            , flags: GateFlags { bits: 0 }
            , offset_mid: 0
            , offset_upper: 0
            , _reserved: 0
            , _handler_type: PhantomData
            }
    }

    pub fn set_handler(&mut self, handler: H) -> &mut Self {
        let (low, mid, high): (u16, u16, u32)
            = unsafe{ mem::transmute(handler) };

        self.offset_lower = low;
        self.offset_mid = mid;
        self.offset_upper = high;

        self
    }

}

impl<H> Default for Gate<H> {
    fn default() -> Self {
        Gate { offset_lower: 0
             , selector: segment::Selector::from_raw(0)
             , _zero: 0
             , flags: GateFlags { bits: 0 }
             , offset_mid: 0
             , offset_upper: 0
             , _reserved: 0
             , _handler_type: PhantomData
             }
    }
}

impl convert::From<InterruptHandler> for Gate<InterruptHandler> {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    fn from(handler: InterruptHandler) -> Self {
        unsafe { // trust me on this, `mem::transmute()` is glorious black magic
                let (low, mid, high): (u16, u16, u32) = mem::transmute(handler);

            Gate { offset_lower: low
                 , offset_mid: mid
                 , offset_upper: high
                 , selector: segment::Selector::from_cs()
                 , flags: GateFlags::new_interrupt()
                 , ..Default::default()
                 }
        }
    }
}

impl convert::From<ErrorCodeHandler> for Gate<ErrorCodeHandler> {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    fn from(handler: ErrorCodeHandler) -> Self {
        unsafe { // trust me on this, `mem::transmute()` is glorious black magic
                let (low, mid, high): (u16, u16, u32) = mem::transmute(handler);

            Gate { offset_lower: low
                 , offset_mid: mid
                 , offset_upper: high
                 , selector: segment::Selector::from_cs()
                 , flags: GateFlags::new_interrupt()
                 , ..Default::default()
                 }
        }
    }
}

impl convert::From<*const u8> for Gate {

    /// Creates a new IDT gate pointing at the given handler function.
    ///
    /// The `handler` function must have been created with valid interrupt
    /// calling conventions.
    ///
    /// This should probably not be used, if it can possibly be avoided.
    //  TODO: it would be really nice if we didn't need this any more.
    //        after the Revolution, once handlers are created in Rust-land with
    //        naked functions...
    fn from(handler: *const u8) -> Self {
        unsafe {
            let (low, mid, high): (u16, u16, u32) = mem::transmute(handler);

            Gate { offset_lower: low
                 , offset_mid: mid
                 , offset_upper: high
                 , selector: segment::Selector::from_cs()
                 , flags: GateFlags::new_interrupt()
                 , ..Default::default()
                 }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>wip: remove explicit qsym, and dupes<commit_after><|endoftext|>


<commit_before><commit_msg>Add stubs module<commit_after><|endoftext|>


<commit_before><commit_msg>added u64 from and tosql<commit_after><|endoftext|>


<commit_before>use std::io;
use std::process::{Command, Stdio};
use std::{thread, time};
use {ErrorKind, Result};

fn run_self_test(address: String) -> io::Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(client_address);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            format!("{:#?}", e),
        ))
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() {
    assert!(run_self_test("unix:/tmp/org.varlink.certification".into()).is_ok());
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() {
    assert!(run_self_test("unix:@org.varlink.certification".into()).is_ok());
}

#[test]
fn test_tcp() {
    assert!(run_self_test("tcp:0.0.0.0:23456".into()).is_ok());
}

fn get_exec() -> Result<String> {
    if ::std::path::Path::new("../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("./target/debug/varlink-certification").exists() {
        return Ok("exec:./target/debug/varlink-certification".into());
    }

    let mut child = Command::new("cargo")
        .arg("install")
        .arg("--force")
        .arg("--path=varlink-certification")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    match child.wait() {
        Ok(e) if e.success() => return Ok("exec:varlink-certification".into()),
        _ => {}
    }

    let mut child = Command::new("cargo")
        .arg("install")
        .arg("--force")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    match child.wait() {
        Ok(e) if e.success() => return Ok("exec:varlink-certification".into()),
        _ => {}
    }
    Err(ErrorKind::Io_Error(io::ErrorKind::NotFound).into())
}

#[test]
fn test_exec() {
    match get_exec() {
        Err(_) => {
            eprintln!("test test::test_exec ... skipping, no varlink-certification binary found");
            return;
        }
        Ok(address) => assert!(::run_client(address).is_ok()),
    }
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<commit_msg>varlink-certification: test_exec() try one more parent dir<commit_after>use std::io;
use std::process::{Command, Stdio};
use std::{thread, time};
use {ErrorKind, Result};

fn run_self_test(address: String) -> io::Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(client_address);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            format!("{:#?}", e),
        ))
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() {
    assert!(run_self_test("unix:/tmp/org.varlink.certification".into()).is_ok());
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() {
    assert!(run_self_test("unix:@org.varlink.certification".into()).is_ok());
}

#[test]
fn test_tcp() {
    assert!(run_self_test("tcp:0.0.0.0:23456".into()).is_ok());
}

fn get_exec() -> Result<String> {
    if ::std::path::Path::new("../../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("./target/debug/varlink-certification").exists() {
        return Ok("exec:./target/debug/varlink-certification".into());
    }

    let mut child = Command::new("cargo")
        .arg("install")
        .arg("--force")
        .arg("--path=varlink-certification")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    match child.wait() {
        Ok(e) if e.success() => return Ok("exec:varlink-certification".into()),
        _ => {}
    }

    let mut child = Command::new("cargo")
        .arg("install")
        .arg("--force")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    match child.wait() {
        Ok(e) if e.success() => return Ok("exec:varlink-certification".into()),
        _ => {}
    }
    Err(ErrorKind::Io_Error(io::ErrorKind::NotFound).into())
}

#[test]
fn test_exec() {
    match get_exec() {
        Err(_) => {
            eprintln!("test test::test_exec ... skipping, no varlink-certification binary found");
            return;
        }
        Ok(address) => assert!(::run_client(address).is_ok()),
    }
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<|endoftext|>


<commit_before>use std::io;
use std::process::{Command, Stdio};
use std::{thread, time};
use {ErrorKind, Result};

fn run_self_test(address: String) -> io::Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(client_address);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            format!("{:#?}", e),
        ))
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() {
    assert!(run_self_test("unix:/tmp/org.varlink.certification".into()).is_ok());
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() {
    assert!(run_self_test("unix:@org.varlink.certification".into()).is_ok());
}

#[test]
fn test_tcp() {
    assert!(run_self_test("tcp:0.0.0.0:23456".into()).is_ok());
}

fn get_exec() -> Result<String> {
    if ::std::path::Path::new("../../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../target/debug/varlink-certification").exists() {
        return Ok("exec:../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("./target/debug/varlink-certification").exists() {
        return Ok("exec:./target/debug/varlink-certification".into());
    }

    let mut child = Command::new("cargo")
        .arg("install")
        .arg("--force")
        .arg("--path=varlink-certification")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    match child.wait() {
        Ok(e) if e.success() => return Ok("exec:varlink-certification".into()),
        _ => {}
    }

    let mut child = Command::new("cargo")
        .arg("install")
        .arg("--force")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    match child.wait() {
        Ok(e) if e.success() => return Ok("exec:varlink-certification".into()),
        _ => {}
    }
    Err(ErrorKind::Io_Error(io::ErrorKind::NotFound).into())
}

#[test]
fn test_exec() {
    match get_exec() {
        Err(_) => {
            eprintln!("test test::test_exec ... skipping, no varlink-certification binary found");
            return;
        }
        Ok(address) => assert!(::run_client(address).is_ok()),
    }
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<commit_msg>varlink-certification/src/test.rs: only build, don't install<commit_after>use std::io;
use std::process::{Command, Stdio};
use std::{thread, time};
use {ErrorKind, Result};

fn run_self_test(address: String) -> io::Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(client_address);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            format!("{:#?}", e),
        ))
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() {
    assert!(run_self_test("unix:/tmp/org.varlink.certification".into()).is_ok());
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() {
    assert!(run_self_test("unix:@org.varlink.certification".into()).is_ok());
}

#[test]
fn test_tcp() {
    assert!(run_self_test("tcp:0.0.0.0:23456".into()).is_ok());
}

fn get_exec() -> Result<String> {
    let mut child = Command::new("cargo")
        .arg("build")
        .arg("--package=varlink-certification")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    child.wait();

    if ::std::path::Path::new("../../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../target/debug/varlink-certification").exists() {
        return Ok("exec:../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("./target/debug/varlink-certification").exists() {
        return Ok("exec:./target/debug/varlink-certification".into());
    }

    Err(ErrorKind::Io_Error(io::ErrorKind::NotFound).into())
}

#[test]
fn test_exec() {
    match get_exec() {
        Err(_) => {
            eprintln!("test test::test_exec ... skipping, no varlink-certification binary found");
            return;
        }
        Ok(address) => assert!(::run_client(address).is_ok()),
    }
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::fmt;
use std::io;
use std::sync::Mutex;

doc_rt_core! {
    /// Task failed to execute to completion.
    pub struct JoinError {
        repr: Repr,
    }
}

enum Repr {
    Cancelled,
    Panic(Mutex<Box<dyn Any + Send + 'static>>),
}

impl JoinError {
    #[doc(hidden)]
    #[deprecated]
    pub fn cancelled() -> JoinError {
        Self::cancelled2()
    }

    pub(crate) fn cancelled2() -> JoinError {
        JoinError {
            repr: Repr::Cancelled,
        }
    }

    #[doc(hidden)]
    #[deprecated]
    pub fn panic(err: Box<dyn Any + Send + 'static>) -> JoinError {
        Self::panic2(err)
    }

    pub(crate) fn panic2(err: Box<dyn Any + Send + 'static>) -> JoinError {
        JoinError {
            repr: Repr::Panic(Mutex::new(err)),
        }
    }
}

impl fmt::Display for JoinError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self.repr {
            Repr::Cancelled => write!(fmt, "cancelled"),
            Repr::Panic(_) => write!(fmt, "panic"),
        }
    }
}

impl fmt::Debug for JoinError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self.repr {
            Repr::Cancelled => write!(fmt, "JoinError::Cancelled"),
            Repr::Panic(_) => write!(fmt, "JoinError::Panic(...)"),
        }
    }
}

impl std::error::Error for JoinError {}

impl From<JoinError> for io::Error {
    fn from(src: JoinError) -> io::Error {
        io::Error::new(
            io::ErrorKind::Other,
            match src.repr {
                Repr::Cancelled => "task was cancelled",
                Repr::Panic(_) => "task panicked",
            },
        )
    }
}
<commit_msg>task: add methods for inspecting JoinErrors (#2051)<commit_after>use std::any::Any;
use std::fmt;
use std::io;
use std::sync::Mutex;

doc_rt_core! {
    /// Task failed to execute to completion.
    pub struct JoinError {
        repr: Repr,
    }
}

enum Repr {
    Cancelled,
    Panic(Mutex<Box<dyn Any + Send + 'static>>),
}

impl JoinError {
    #[doc(hidden)]
    #[deprecated]
    pub fn cancelled() -> JoinError {
        Self::cancelled2()
    }

    pub(crate) fn cancelled2() -> JoinError {
        JoinError {
            repr: Repr::Cancelled,
        }
    }

    #[doc(hidden)]
    #[deprecated]
    pub fn panic(err: Box<dyn Any + Send + 'static>) -> JoinError {
        Self::panic2(err)
    }

    pub(crate) fn panic2(err: Box<dyn Any + Send + 'static>) -> JoinError {
        JoinError {
            repr: Repr::Panic(Mutex::new(err)),
        }
    }

    /// Returns true if the error was caused by the task being cancelled
    pub fn is_cancelled(&self) -> bool {
        match &self.repr {
            Repr::Cancelled => true,
            _ => false,
        }
    }

    /// Returns true if the error was caused by the task panicking
    ///
    /// # Examples
    ///
    /// ```
    /// use std::panic;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let err = tokio::spawn(async {
    ///         panic!("boom");
    ///     }).await.unwrap_err();
    ///
    ///     assert!(err.is_panic());
    /// }
    /// ```
    pub fn is_panic(&self) -> bool {
        match &self.repr {
            Repr::Panic(_) => true,
            _ => false,
        }
    }

    /// Consumes the join error, returning the object with which the task panicked.
    ///
    /// # Panics
    ///
    /// `into_panic()` panics if the `Error` does not represent the underlying
    /// task terminating with a panic. Use `is_panic` to check the error reason
    /// or `try_into_panic` for a variant that does not panic.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let err = tokio::spawn(async {
    ///         panic!("boom");
    ///     }).await.unwrap_err();
    ///
    ///     if err.is_panic() {
    ///         // Resume the panic on the main task
    ///         panic::resume_unwind(err.into_panic());
    ///     }
    /// }
    /// ```
    pub fn into_panic(self) -> Box<dyn Any + Send + 'static> {
        self.try_into_panic()
            .expect("`JoinError` reason is not a panic.")
    }

    /// Consumes the join error, returning the object with which the task
    /// panicked if the task terminated due to a panic. Otherwise, `self` is
    /// returned.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let err = tokio::spawn(async {
    ///         panic!("boom");
    ///     }).await.unwrap_err();
    ///
    ///     if let Ok(reason) = err.try_into_panic() {
    ///         // Resume the panic on the main task
    ///         panic::resume_unwind(reason);
    ///     }
    /// }
    /// ```
    pub fn try_into_panic(self) -> Result<Box<dyn Any + Send + 'static>, JoinError> {
        match self.repr {
            Repr::Panic(p) => Ok(p.into_inner().expect("Extracting panic from mutex")),
            _ => Err(self),
        }
    }
}

impl fmt::Display for JoinError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self.repr {
            Repr::Cancelled => write!(fmt, "cancelled"),
            Repr::Panic(_) => write!(fmt, "panic"),
        }
    }
}

impl fmt::Debug for JoinError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self.repr {
            Repr::Cancelled => write!(fmt, "JoinError::Cancelled"),
            Repr::Panic(_) => write!(fmt, "JoinError::Panic(...)"),
        }
    }
}

impl std::error::Error for JoinError {}

impl From<JoinError> for io::Error {
    fn from(src: JoinError) -> io::Error {
        io::Error::new(
            io::ErrorKind::Other,
            match src.repr {
                Repr::Cancelled => "task was cancelled",
                Repr::Panic(_) => "task panicked",
            },
        )
    }
}
<|endoftext|>