<commit_before>use dungeon::{Dungeon};
use celloption::{CellOptions, Tile, Item, Occupant};
use genotype::{GenoType};
use config::{Config};

use std::iter::{repeat};
use std::collections::{HashMap};
use rand::{Rng, ThreadRng, thread_rng};

#[derive(Clone, Debug)]
pub struct WallPatterns {
    fitness: f64,
    dungeon: Dungeon,
    patterns: Vec<WallPattern>,
    pattern_width: usize,
    pattern_height: usize,
    indices: Vec<usize>,
    items: CellOptions<Item>,
    occupants: CellOptions<Occupant>,
    // statistics
    pub iteration: u32,
    pub ranking: f64
}

#[derive(Clone, Debug)]
struct WallPattern {
    pattern: Vec<Option<Tile>>
}

impl WallPatterns {
    pub fn new(config: &Config,
               width: usize,
               height: usize,
               tiles: CellOptions<Tile>,
               items: CellOptions<Item>,
               occupants: CellOptions<Occupant>) -> WallPatterns {
        // read in the configurations
        let wallpatterns = config.get_table(None, "wallpatterns");
        let tile_vars = config.get_table(Some(wallpatterns), "tiles");
        let pattern_width = config.get_integer(tile_vars, "width") as usize;
        let pattern_height = config.get_integer(tile_vars, "height") as usize;
        let mut mapping = HashMap::new();
        // TODO: function to iterate over toml section settings
        mapping.insert(config.get_char(tile_vars, "floor"), tiles.get("floor").unwrap());
        mapping.insert(config.get_char(tile_vars, "wall"), tiles.get("wall").unwrap());
        mapping.insert(config.get_char(tile_vars, "entrance"), tiles.get("entrance").unwrap());
        mapping.insert(config.get_char(tile_vars, "exit"), tiles.get("exit").unwrap());
        mapping.insert(config.get_char(tile_vars, "door"), tiles.get("door").unwrap());
        let room_vars = config.get_table(Some(wallpatterns), "rooms");
        let rooms = vec!["empty","altar","down_","up___","rand1","rand2","rand3","rand4"];
        let patterns: Vec<WallPattern> = rooms.iter().map(|&r| {
            let description = config.get_array(room_vars, r);
            WallPatterns::construct(&mapping, description, pattern_width, pattern_height)
        }).collect();
        let indices: Vec<usize> = repeat(0).take(patterns.len()).collect();
        let dungeon = Dungeon::new(width, height);
        WallPatterns {
            fitness: 0.0,
            dungeon: dungeon,
            patterns: patterns,
            pattern_width: pattern_width,
            pattern_height: pattern_height,
            indices: indices,
            items: items,
            occupants: occupants,
            iteration: 0,
            ranking: -1.0
        }
    }

    fn construct(mapping: &HashMap<char, &Tile>, description: Vec<String>, width: usize, height: usize) -> WallPattern {
        let mut pattern = Vec::with_capacity(width * height);
        for line in description {
            for ch in line.chars() {
                let tile = mapping.get(&(ch));
                match tile {
                    None => pattern.push(None),
                    Some(&tile) => pattern.push(Some((*tile).clone()))
                }
            }
        }
        WallPattern {
            pattern: pattern
        }
    }
}

impl GenoType for WallPatterns {
    fn mutate(&mut self, rng: &mut ThreadRng) {
        // change up to 33% of indices.
        let length = self.patterns.len();
        let n = (length as f32 * 0.33) as usize;
        for _ in range(0, n) {
            let index = rng.gen_range(1, length);
            self.indices[index] = index;
        }
    }

    fn generate(&mut self, rng: &mut ThreadRng) -> Dungeon {
        let w = self.dungeon.width as i32;
        let h = self.dungeon.height as i32;

        self.dungeon.clone()
    }

    fn statistics(&mut self, stats: &HashMap<String, f64>) {
        match stats.get("iteration") {
            None => (),
            Some(&val) => self.iteration = val as u32
        }
        match stats.get("ranking") {
            None => (),
            Some(&val) => self.ranking = val
        }
    }

    fn last(&self) -> Dungeon {
        self.dungeon.clone()
    }
}
<commit_msg>Draw wall patterns properly.<commit_after>use dungeon::{Dungeon};
use celloption::{CellOptions, Tile, Item, Occupant};
use genotype::{GenoType};
use config::{Config};

use std::iter::{repeat};
use std::collections::{HashMap};
use rand::{Rng, ThreadRng, thread_rng};

#[derive(Clone, Debug)]
pub struct WallPatterns {
    fitness: f64,
    dungeon: Dungeon,
    patterns: Vec<WallPattern>,
    pattern_width: usize,
    pattern_height: usize,
    indices: Vec<usize>,
    items: CellOptions<Item>,
    occupants: CellOptions<Occupant>,
    // statistics
    pub iteration: u32,
    pub ranking: f64
}

#[derive(Clone, Debug)]
struct WallPattern {
    pattern: Vec<Option<Tile>>
}

impl WallPatterns {
    pub fn new(config: &Config,
               width: usize,
               height: usize,
               tiles: CellOptions<Tile>,
               items: CellOptions<Item>,
               occupants: CellOptions<Occupant>) -> WallPatterns {
        // read in the configurations
        let wallpatterns = config.get_table(None, "wallpatterns");
        let tile_vars = config.get_table(Some(wallpatterns), "tiles");
        let pattern_width = config.get_integer(tile_vars, "width") as usize;
        let pattern_height = config.get_integer(tile_vars, "height") as usize;
        let mut mapping = HashMap::new();
        // TODO: function to iterate over toml section settings
        mapping.insert(config.get_char(tile_vars, "floor"), tiles.get("floor").unwrap());
        mapping.insert(config.get_char(tile_vars, "wall"), tiles.get("wall").unwrap());
        mapping.insert(config.get_char(tile_vars, "entrance"), tiles.get("entrance").unwrap());
        mapping.insert(config.get_char(tile_vars, "exit"), tiles.get("exit").unwrap());
        mapping.insert(config.get_char(tile_vars, "door"), tiles.get("door").unwrap());
        let room_vars = config.get_table(Some(wallpatterns), "rooms");
        let rooms = vec!["empty","altar","down_","up___","rand1","rand2","rand3","rand4"];
        let patterns: Vec<WallPattern> = rooms.iter().map(|&r| {
            let description = config.get_array(room_vars, r);
            WallPatterns::construct(&mapping, description, pattern_width, pattern_height)
        }).collect();
        let indices: Vec<usize> = repeat(0).take(patterns.len()).collect();
        let dungeon = Dungeon::new(width, height);
        WallPatterns {
            fitness: 0.0,
            dungeon: dungeon,
            patterns: patterns,
            pattern_width: pattern_width,
            pattern_height: pattern_height,
            indices: indices,
            items: items,
            occupants: occupants,
            iteration: 0,
            ranking: -1.0
        }
    }

    fn construct(mapping: &HashMap<char, &Tile>, description: Vec<String>, width: usize, height: usize) -> WallPattern {
        let mut pattern = Vec::with_capacity(width * height);
        for line in description {
            for ch in line.chars() {
                let tile = mapping.get(&(ch));
                match tile {
                    None => pattern.push(None),
                    Some(&tile) => pattern.push(Some((*tile).clone()))
                }
            }
        }
        WallPattern {
            pattern: pattern
        }
    }
}

impl GenoType for WallPatterns {
    fn mutate(&mut self, rng: &mut ThreadRng) {
        // change up to 33% of indices.
        let length = self.patterns.len();
        let n = (length as f32 * 0.33) as usize;
        for _ in range(0, n) {
            let index = rng.gen_range(1, length);
            self.indices[index] = index;
        }
    }

    fn generate(&mut self, rng: &mut ThreadRng) -> Dungeon {
        let w = self.dungeon.width as i32;
        let h = self.dungeon.height as i32;
        let n = self.patterns.len();
        // draw the patterns according to the indices we have.
        for i in 0..self.dungeon.width {
            let x: usize = i / self.pattern_width;
            let inner_x = i % self.pattern_width;
            for j in 0..self.dungeon.height {
                let y: usize = j / self.pattern_height;
                let index = self.indices[(y * self.pattern_width + x) % n];
                let ref pattern = self.patterns[index];
                // here, we have to invert due to a mismatch between how we draw the patterns and opengl coords
                let inner_y = self.pattern_height - (j % self.pattern_height) - 1;
                self.dungeon.cells[i][j].tile = pattern.pattern[inner_y * self.pattern_width + inner_x].clone();
            }
        }
        self.dungeon.clone()
    }

    fn statistics(&mut self, stats: &HashMap<String, f64>) {
        match stats.get("iteration") {
            None => (),
            Some(&val) => self.iteration = val as u32
        }
        match stats.get("ranking") {
            None => (),
            Some(&val) => self.ranking = val
        }
    }

    fn last(&self) -> Dungeon {
        self.dungeon.clone()
    }
}
<|endoftext|>


<commit_before>use wire::peer_info::PeerState;
use metainfo::MetaInfo;
use wire::action::PeerAction;
use wire::msg::PeerMsg;
use wire::action::PeerStreamAction;
use std::collections::HashMap;
use bit_vec::BitVec;
use file::PartialFile;
use file::PartialFileTrait;
use wire::action::PeerId;

pub trait Strategy {
    fn query(&mut self, pending: Vec<&Order>, done: Vec<OrderResult>, peers: Vec<&PeerState>, file: &PartialFile) -> Vec<Order>;
    fn on_handshake(&mut self, id: PeerId) -> Vec<Order>;
    fn on_choke(&mut self, id: PeerId) -> Vec<Order>;
    fn on_unchoke(&mut self, id: PeerId) -> Vec<Order>;
    fn on_interested(&mut self, id: PeerId) -> Vec<Order>;
    fn on_not_interested(&mut self, id: PeerId) -> Vec<Order>;
    fn on_have(&mut self, id: PeerId, piece_index: usize) -> Vec<Order>;
    fn on_bitfield(&mut self, id: PeerId, bitfield: BitVec) ->  Vec<Order>;
    fn on_request(&mut self, id: PeerId, index: u32, begin: u32, length: u32) -> Vec<Order>;
    fn on_piece(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order>;
    fn on_cancel(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order>;
    fn on_port(&mut self, id: PeerId, port: u16) -> Vec<Order>;
}

pub struct NormalStrategy {
    orders: HashMap<OrderId, OrderInfo>,
    peers: HashMap<PeerId, PeerState>,
    pieces_to_request: BitVec,
    next_order_id: usize,
    num_pieces: usize,
    piece_length: u64,
    partial_file: PartialFile
}

impl NormalStrategy {
    pub fn new (metainfo: MetaInfo) -> NormalStrategy {
        let num_pieces = metainfo.info.pieces.len();
        let partial_file = PartialFile::new(&metainfo.info);
        let piece_length = partial_file.piece_length();

        NormalStrategy {
            orders: HashMap::new(),
            peers: HashMap::new(),
            pieces_to_request: BitVec::from_elem(num_pieces, true),
            next_order_id: 0,
            partial_file: partial_file,
            num_pieces: num_pieces,
            piece_length: piece_length,
        }
    }

    pub fn request_pieces<F: PartialFileTrait>(&mut self, peers: Vec<&PeerState>, partial_file: &F) -> Vec<PeerAction> {
        let mut actions = Vec::new();
        let ready_peers = peers.iter().filter(|peer| !peer.peer_choking && !peer.am_choking && peer.has_handshake);
        for peer in ready_peers {
            let id = peer.peer_id;
            let mut missing = partial_file.bit_array();

            missing.negate();
            let mut them = peer.file.bit_array();
            missing.intersect(&them);
            missing.intersect(&self.pieces_to_request);

            //now have eligible pieces to request
            let mut pieces = missing.into_iter().enumerate().filter(|&(_, x)| x).map(|(i, _)| i as u64).collect::<Vec<u64>>();
            let piece_len = self.piece_length;
            let mut bytes_requested = 0;
            let mut pieces_request = 0;

            const MAX_BLOCK_SIZE: u64 = 2 << 14;
            const MAX_BYTES_PER_REQUEST: u64 = 1024 * 512;
            const MAX_PIECES_PEER: usize = 10;

            let mut msgs = Vec::new();
            for (piece_count, piece_index) in pieces.into_iter().enumerate() {
                if bytes_requested > MAX_BYTES_PER_REQUEST || piece_count > MAX_PIECES_PEER {
                    break;
                }
                if piece_len > MAX_BLOCK_SIZE {
                    let mut offset = 0;
                    while offset < piece_len {
                        if (offset + MAX_BLOCK_SIZE > piece_len) {
                            msgs.push(PeerMsg::Request(piece_index as u32, offset as u32,
                                MAX_BLOCK_SIZE as u32));
                        } else {
                            msgs.push(PeerMsg::Request(piece_index as u32, offset as u32,
                                MAX_BLOCK_SIZE as u32));
                        }
                        offset += MAX_BLOCK_SIZE;
                    }
                } else {
                    msgs.push(PeerMsg::Request(piece_index as u32, 0, piece_len as u32));
                }
                self.pieces_to_request.set(piece_index as usize, false);
            }

            let req_actions = PeerAction(id, PeerStreamAction::SendMessages(msgs));
            actions.push(req_actions);
        }
        actions
        //Vec::new()
    }

    fn _get_piece_from_req(&mut self, index: usize, begin: u32, offset: u32) -> Option<PeerMsg> {
        if self.partial_file.has_piece(index as usize) {
            let piece = self.partial_file.get_piece_mut(index as usize);
            return match piece.get_offset(begin as usize, offset as usize) {
                Some(piece_data) => {
                    let msg = PeerMsg::Piece(begin, offset, Vec::from(piece_data));
                    Some(msg)
                }
                _ => None,
            };
        }
        None
    }
}

impl Strategy for NormalStrategy {
    fn on_handshake(&mut self, id: PeerId) -> Vec<Order> {
        let peer = PeerState::new(self.num_pieces, id);
        self.peers.insert(id, peer);
        vec![]

    }
    fn on_choke(&mut self, id: PeerId) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_choking = true,
            None => {}
        };
        vec![]
    }
    fn on_unchoke(&mut self, id: PeerId) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_choking = false,
            None => {}
        };
        vec![]

    }
    fn on_interested(&mut self, id: PeerId) -> Vec<Order>  {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_interested = true,
            None => {}
        };
        vec![]

    }
    fn on_not_interested(&mut self, id: PeerId) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_interested = false,
            None => {}
        };
        vec![]
    }

    fn on_have(&mut self, id: PeerId, piece_index: usize) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.file.set(piece_index as usize, true),
            None => {}
        };
        vec![]
    }

    fn on_bitfield(&mut self, id: PeerId, bitfield: BitVec) ->  Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => {
                    let limit = peer.file.bit_array().len();
                    for (i, bit) in bitfield.iter().enumerate()  {
                        if i >= limit {
                            break;
                        }
                        peer.file.set(i, bit);
                    }
                },
            None => {}
        };
        vec![]
    }
    fn on_request(&mut self, id: PeerId, index: u32, begin: u32, length: u32) -> Vec<Order> {
        let piece_result = self._get_piece_from_req(index as usize, begin, length);
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => {
                let response = piece_result;
                match response {
                    Some(r) => unimplemented!(),
                    _ => Vec::new(),
                }
            },
            _ => Vec::new()
        }
    }

    fn on_piece(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order> {
        self.partial_file.add_piece(index as usize, begin as usize, block);
        Vec::new()
    }

    fn on_cancel(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order> {
        Vec::new()
    }

    fn on_port(&mut self, id: PeerId, port: u16) -> Vec<Order> {
        Vec::new()
    }

    fn query(&mut self, pending: Vec<&Order>, done: Vec<OrderResult>, peers: Vec<&PeerState>, file: &PartialFile)
        -> Vec<Order> {
        let actions = self.request_pieces(peers, file);
        let mut orders = Vec::new();

        for action in actions {
            orders.push(Order {order_id: self.next_order_id, action: action, status: OrderStatus::NotStarted});
            self.next_order_id += 1;
        }

        orders
    }
}

struct OrderInfo;
type OrderId = usize;

pub struct OrderResult {
    status: OrderStatus,
    order_id: OrderId
}

pub struct Order {
    status: OrderStatus,
    order_id: OrderId,
    pub action: PeerAction
}

impl Order {
    pub fn complete(&self, status: OrderStatus) -> OrderResult {
        OrderResult { order_id: self.order_id, status: status}
    }

    pub fn id(&self) -> OrderId {
        self.order_id
    }

    pub fn status(&self) -> OrderStatus {
        self.status
    }

    pub fn set_status(&mut self, status: OrderStatus) {
        self.status = status;
    }
}

#[derive(Eq, PartialEq, Clone, Copy)]
pub enum OrderStatus {
    NotStarted,
    InProgress,
    Failed,
    Done
}
<commit_msg>Change stuff<commit_after>use wire::peer_info::PeerState;
use metainfo::MetaInfo;
use wire::action::PeerAction;
use wire::msg::PeerMsg;
use wire::action::PeerStreamAction;
use std::collections::HashMap;
use bit_vec::BitVec;
use file::PartialFile;
use file::PartialFileTrait;
use wire::action::PeerId;

pub trait Strategy {
    fn query(&mut self, pending: Vec<&Order>, done: Vec<OrderResult>, peers: Vec<&PeerState>, file: &PartialFile) -> Vec<Order>;
    fn on_handshake(&mut self, id: PeerId) -> Vec<Order>;
    fn on_choke(&mut self, id: PeerId) -> Vec<Order>;
    fn on_unchoke(&mut self, id: PeerId) -> Vec<Order>;
    fn on_interested(&mut self, id: PeerId) -> Vec<Order>;
    fn on_not_interested(&mut self, id: PeerId) -> Vec<Order>;
    fn on_have(&mut self, id: PeerId, piece_index: usize) -> Vec<Order>;
    fn on_bitfield(&mut self, id: PeerId, bitfield: BitVec) ->  Vec<Order>;
    fn on_request(&mut self, id: PeerId, index: u32, begin: u32, length: u32) -> Vec<Order>;
    fn on_piece(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order>;
    fn on_cancel(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order>;
    fn on_port(&mut self, id: PeerId, port: u16) -> Vec<Order>;
}

const MAX_BLOCK_SIZE: u64 = 2 << 14;
const MAX_BYTES_PER_REQUEST: u64 = 1024 * 512;
const MAX_PIECES_PEER: usize = 10;

pub struct NormalStrategy {
    orders: HashMap<OrderId, OrderInfo>,
    peers: HashMap<PeerId, PeerState>,
    pieces_to_request: BitVec,
    next_order_id: usize,
    num_pieces: usize,
    piece_length: u64,
    partial_file: PartialFile
}

impl NormalStrategy {
    pub fn new (metainfo: MetaInfo) -> NormalStrategy {
        let num_pieces = metainfo.info.pieces.len();
        let partial_file = PartialFile::new(&metainfo.info);
        let piece_length = partial_file.piece_length();

        NormalStrategy {
            orders: HashMap::new(),
            peers: HashMap::new(),
            pieces_to_request: BitVec::from_elem(num_pieces, true),
            next_order_id: 0,
            partial_file: partial_file,
            num_pieces: num_pieces,
            piece_length: piece_length,
        }
    }

    pub fn request_pieces<F: PartialFileTrait>(&mut self, peers: Vec<&PeerState>, partial_file: &F) -> Vec<PeerAction> {
        let mut actions = Vec::new();
        let ready_peers = peers.iter().filter(|peer| !peer.peer_choking && !peer.am_choking && peer.has_handshake);
        for peer in ready_peers {
            let id = peer.peer_id;
            let mut missing = partial_file.bit_array();

            missing.negate();
            let mut them = peer.file.bit_array();
            missing.intersect(&them);
            missing.intersect(&self.pieces_to_request);

            //now have eligible pieces to request
            let mut pieces = missing.into_iter().enumerate().filter(|&(_, x)| x).map(|(i, _)| i as u64).collect::<Vec<u64>>();
            let piece_len = self.piece_length;
            let mut bytes_requested = 0;
            let mut pieces_request = 0;

            let mut msgs = Vec::new();
            for (piece_count, piece_index) in pieces.into_iter().enumerate() {
                if bytes_requested > MAX_BYTES_PER_REQUEST || piece_count > MAX_PIECES_PEER {
                    break;
                }
                let mut pieces = NormalStrategy::piece_request(piece_index, piece_len, MAX_BLOCK_SIZE);
                self.pieces_to_request.set(piece_index as usize, false);
                msgs.append(&mut pieces);
            }

            let req_actions = PeerAction(id, PeerStreamAction::SendMessages(msgs));
            actions.push(req_actions);
        }
        actions
    }

    fn piece_request(piece_index: u64, piece_len: u64, max_block_size: u64) -> Vec<PeerMsg> {
        let mut msgs = Vec::new();
        let mut bytes_requested = 0;

        if piece_len > max_block_size {
            let mut offset = 0;
            while offset < piece_len {
                if (offset + max_block_size > piece_len) {
                    msgs.push(PeerMsg::Request(piece_index as u32, offset as u32,
                        max_block_size as u32));
                } else {
                    msgs.push(PeerMsg::Request(piece_index as u32, offset as u32,
                        max_block_size as u32));
                }
                offset += max_block_size;
            }
        } else {
            msgs.push(PeerMsg::Request(piece_index as u32, 0, piece_len as u32));
        }

        msgs
    }

    fn _get_piece_from_req(&mut self, index: usize, begin: u32, offset: u32) -> Option<PeerMsg> {
        if self.partial_file.has_piece(index as usize) {
            let piece = self.partial_file.get_piece_mut(index as usize);
            return match piece.get_offset(begin as usize, offset as usize) {
                Some(piece_data) => {
                    let msg = PeerMsg::Piece(begin, offset, Vec::from(piece_data));
                    Some(msg)
                }
                _ => None,
            };
        }
        None
    }
}

impl Strategy for NormalStrategy {
    fn on_handshake(&mut self, id: PeerId) -> Vec<Order> {
        let peer = PeerState::new(self.num_pieces, id);
        self.peers.insert(id, peer);
        vec![]

    }
    fn on_choke(&mut self, id: PeerId) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_choking = true,
            None => {}
        };
        vec![]
    }
    fn on_unchoke(&mut self, id: PeerId) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_choking = false,
            None => {}
        };
        vec![]

    }
    fn on_interested(&mut self, id: PeerId) -> Vec<Order>  {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_interested = true,
            None => {}
        };
        vec![]

    }
    fn on_not_interested(&mut self, id: PeerId) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => peer.peer_interested = false,
            None => {}
        };
        vec![]
    }

    fn on_have(&mut self, id: PeerId, piece_index: usize) -> Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => {
                peer.file.set(piece_index as usize, true);
                if !peer.partial_file.get(piece_index) {
                    let p_msgs = NormalStrategy::piece_request(piece_index, piece_len, MAX_BLOCK_SIZE);
                }
            }
            None => {}
        };
        vec![]
    }

    fn on_bitfield(&mut self, id: PeerId, bitfield: BitVec) ->  Vec<Order> {
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => {
                    let limit = peer.file.bit_array().len();
                    for (i, bit) in bitfield.iter().enumerate()  {
                        if i >= limit {
                            break;
                        }
                        peer.file.set(i, bit);
                    }
                },
            None => {}
        };
        vec![]
    }
    fn on_request(&mut self, id: PeerId, index: u32, begin: u32, length: u32) -> Vec<Order> {
        let piece_result = self._get_piece_from_req(index as usize, begin, length);
        match self.peers.get_mut(&id) {
            Some(ref mut peer) => {
                let response = piece_result;
                match response {
                    Some(r) => unimplemented!(),
                    _ => Vec::new(),
                }
            },
            _ => Vec::new()
        }
    }

    fn on_piece(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order> {
        self.partial_file.add_piece(index as usize, begin as usize, block);
        Vec::new()
    }

    fn on_cancel(&mut self, id: PeerId, index: u32, begin: u32, block: Vec<u8>) -> Vec<Order> {
        Vec::new()
    }

    fn on_port(&mut self, id: PeerId, port: u16) -> Vec<Order> {
        Vec::new()
    }

    fn query(&mut self, pending: Vec<&Order>, done: Vec<OrderResult>, peers: Vec<&PeerState>, file: &PartialFile)
        -> Vec<Order> {
        let actions = self.request_pieces(peers, file);
        let mut orders = Vec::new();

        for action in actions {
            orders.push(make_order(action));
            self.next_order_id += 1;
        }

        orders
    }

    fn _make_order(&mut self, action: PeerStreamAction) {
        Order {order_id: self.next_order_id, action: action, status: OrderStatus::NotStarted}
    }

}

struct OrderInfo;
type OrderId = usize;

pub struct OrderResult {
    status: OrderStatus,
    order_id: OrderId
}

pub struct Order {
    status: OrderStatus,
    order_id: OrderId,
    pub action: PeerAction
}

impl Order {
    pub fn complete(&self, status: OrderStatus) -> OrderResult {
        OrderResult { order_id: self.order_id, status: status}
    }

    pub fn id(&self) -> OrderId {
        self.order_id
    }

    pub fn status(&self) -> OrderStatus {
        self.status
    }

    pub fn set_status(&mut self, status: OrderStatus) {
        self.status = status;
    }
}

#[derive(Eq, PartialEq, Clone, Copy)]
pub enum OrderStatus {
    NotStarted,
    InProgress,
    Failed,
    Done
}
<|endoftext|>


<commit_before>use error::Error;
use std::net;
use std::env;
use std::io::Write;

pub fn get_master_stream() -> Result<net::TcpStream, Error> {
    let mut args = env::args();
    args.next();

    let hostname: String = args.next().unwrap_or({
        return Err(Error::WorkerError);
    });
    let port: u16 = args.next()
                        .unwrap_or({
                            return Err(Error::WorkerError);
                        })
                        .parse()
                        .ok()
                        .unwrap_or({
                            return Err(Error::WorkerError);
                        });
    let secret: u8 = args.next()
                         .unwrap_or({
                             return Err(Error::WorkerError);
                         })
                         .parse()
                         .ok()
                         .unwrap_or({
                             return Err(Error::WorkerError);
                         });

    let mut stream = try!(net::TcpStream::connect((&hostname[..], port)));
    let sbuf: [u8; 1] = [secret];
    try!(stream.write_all(&sbuf[..]));
    try!(stream.flush());

    Ok(stream)
}
<commit_msg>fixes worker_socket<commit_after>use error::Error;
use std::net;
use std::env;
use std::io::Write;

pub fn get_master_stream() -> Result<net::TcpStream, Error> {
    let mut args = env::args();
    args.next();

    let hostname: String = args.next().unwrap();
    let port: u16 = args.next()
                        .unwrap().parse()
                        .ok()
                        .unwrap();
    let secret: u8 = args.next()
                         .unwrap()
                         .parse()
                         .ok()
                         .unwrap();

    let mut stream = try!(net::TcpStream::connect((&hostname[..], port)));
    let sbuf: [u8; 1] = [secret];
    try!(stream.write_all(&sbuf[..]));
    try!(stream.flush());

    Ok(stream)
}
<|endoftext|>


<commit_before>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        not(feature = "no_jemalloc"),
    ),
    global_allocator
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops", total - last);

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let merge_max = cas_max + args.flag_merge_prop;
    let scan_max = merge_max + args.flag_scan_prop;

    let bytes = |len| -> Vec<u8> {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes: [u8; std::mem::size_of::<usize>()] =
            unsafe { std::mem::transmute(i) };

        i_bytes.into_iter().cycle().take(len).cloned().collect()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, bytes(args.flag_val_len)).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old_k = bytes(args.flag_val_len);

                let old = if rng.gen::<bool>() {
                    Some(old_k.as_slice())
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    Some(bytes(args.flag_val_len))
                } else {
                    None
                };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                tree.merge(&key, bytes(args.flag_val_len)).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args().into_iter()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(1_000_000_000)
        .flush_every_ms(Some(200))
        .snapshot_after_ops(100_000_000_000)
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(!args.flag_burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<commit_msg>add rss info for linux on stress2<commit_after>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        not(feature = "no_jemalloc"),
    ),
    global_allocator
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let merge_max = cas_max + args.flag_merge_prop;
    let scan_max = merge_max + args.flag_scan_prop;

    let bytes = |len| -> Vec<u8> {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes: [u8; std::mem::size_of::<usize>()] =
            unsafe { std::mem::transmute(i) };

        i_bytes.into_iter().cycle().take(len).cloned().collect()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, bytes(args.flag_val_len)).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old_k = bytes(args.flag_val_len);

                let old = if rng.gen::<bool>() {
                    Some(old_k.as_slice())
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    Some(bytes(args.flag_val_len))
                } else {
                    None
                };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                tree.merge(&key, bytes(args.flag_val_len)).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args().into_iter()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(200))
        .snapshot_after_ops(100_000_000_000)
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(!args.flag_burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<|endoftext|>


<commit_before>/*!
    A calculator that use the grid layout of NWG.
    It does not actually do anything though...
*/

extern crate native_windows_gui as nwg;
use nwg::NativeUi;

#[derive(Default)]
pub struct Calculator {
    window: nwg::Window,
}

impl Calculator {

    fn exit(&self) {
        nwg::stop_thread_dispatch();
    }

}

//
// ALL of this stuff is handled by native-windows-derive
//
mod calculator_ui {
    use native_windows_gui as nwg;
    use super::*;
    use std::rc::Rc;
    use std::ops::Deref;

    pub struct CalculatorUi {
        inner: Calculator
    }

    impl nwg::NativeUi<Calculator, CalculatorUi> for Calculator {
        fn build_ui(mut data: Calculator) -> Result<Rc<CalculatorUi>, nwg::SystemError> {
            use nwg::Event as E;

            // Controls
            nwg::Window::builder()
                .size((300, 315))
                .position((300, 300))
                .title("The calculator")
                .build(&mut data.window)?;

            // Wrap-up
            let ui = Rc::new(CalculatorUi { inner: data });

            // Events
            let window_handles = [&ui.window.handle];
            for handle in window_handles.iter() {
                let evt_ui = ui.clone();
                let handle_events = move |evt, _evt_data, handle| {
                    match evt {
                        E::OnWindowClose => {
                            if handle == evt_ui.window.handle {
                                Calculator::exit(&evt_ui.inner);
                            }
                        },
                        _ => {}
                    }
                };

                nwg::bind_event_handler(handle, handle_events);
            }

            return Ok(ui);
        }
    }

    impl Deref for CalculatorUi {
        type Target = Calculator;

        fn deref(&self) -> &Calculator {
            &self.inner
        }
    }

}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");

    let _app = Calculator::build_ui(Default::default()).expect("Failed to build UI");

    nwg::dispatch_thread_events();
}
<commit_msg>calculator buttons<commit_after>/*!
    A calculator that use the grid layout of NWG.
*/

extern crate native_windows_gui as nwg;
use nwg::NativeUi;

#[derive(Default)]
pub struct Calculator {
    window: nwg::Window,

    //layout: GridLayout,

    input: nwg::TextInput,

    btn0: nwg::Button,
    btn1: nwg::Button,
    btn2: nwg::Button,
    btn3: nwg::Button,
    btn4: nwg::Button,
    btn5: nwg::Button,
    btn6: nwg::Button,
    btn7: nwg::Button,
    btn8: nwg::Button,
    btn9: nwg::Button,

    btn_plus: nwg::Button,
    btn_minus: nwg::Button,
    btn_mult: nwg::Button,
    btn_divide: nwg::Button,
    btn_process: nwg::Button,
    btn_clear: nwg::Button,
}

impl Calculator {

    fn exit(&self) {
        nwg::stop_thread_dispatch();
    }

}

//
// ALL of this stuff is handled by native-windows-derive
//
mod calculator_ui {
    use native_windows_gui as nwg;
    use super::*;
    use std::rc::Rc;
    use std::ops::Deref;

    pub struct CalculatorUi {
        inner: Calculator
    }

    impl nwg::NativeUi<Calculator, CalculatorUi> for Calculator {
        fn build_ui(mut data: Calculator) -> Result<Rc<CalculatorUi>, nwg::SystemError> {
            use nwg::Event as E;

            // Controls
            nwg::Window::builder()
                .size((300, 150))
                .position((300, 300))
                .title("Calculator")
                .build(&mut data.window)?;

            nwg::TextInput::builder()
                .text("")
                .readonly(true)
                .parent(&data.window)
                .build(&mut data.input)?;

            nwg::Button::builder().text("0").parent(&data.window).build(&mut data.btn0)?;
            nwg::Button::builder().text("1").parent(&data.window).build(&mut data.btn1)?;
            nwg::Button::builder().text("2").parent(&data.window).build(&mut data.btn2)?;
            nwg::Button::builder().text("3").parent(&data.window).build(&mut data.btn3)?;
            nwg::Button::builder().text("4").parent(&data.window).build(&mut data.btn4)?;
            nwg::Button::builder().text("5").parent(&data.window).build(&mut data.btn5)?;
            nwg::Button::builder().text("6").parent(&data.window).build(&mut data.btn6)?;
            nwg::Button::builder().text("7").parent(&data.window).build(&mut data.btn7)?;
            nwg::Button::builder().text("8").parent(&data.window).build(&mut data.btn8)?;
            nwg::Button::builder().text("9").parent(&data.window).build(&mut data.btn9)?;

            nwg::Button::builder().text("+").parent(&data.window).build(&mut data.btn_plus)?;
            nwg::Button::builder().text("-").parent(&data.window).build(&mut data.btn_minus)?;
            nwg::Button::builder().text("*").parent(&data.window).build(&mut data.btn_mult)?;
            nwg::Button::builder().text("/").parent(&data.window).build(&mut data.btn_divide)?;
            nwg::Button::builder().text("Done").parent(&data.window).build(&mut data.btn_process)?;
            nwg::Button::builder().text("Clear").parent(&data.window).build(&mut data.btn_clear)?;

            // Wrap-up
            let ui = Rc::new(CalculatorUi { inner: data });

            // Events
            let window_handles = [&ui.window.handle];
            for handle in window_handles.iter() {
                let evt_ui = ui.clone();
                let handle_events = move |evt, _evt_data, handle| {
                    match evt {
                        E::OnWindowClose => {
                            if handle == evt_ui.window.handle {
                                Calculator::exit(&evt_ui.inner);
                            }
                        },
                        _ => {}
                    }
                };

                nwg::bind_event_handler(handle, handle_events);
            }

            // Layouts
            nwg::GridLayout::builder()
                .parent(&ui.window)
                .spacing(2)
                .min_size([150, 140])
                .child_item(nwg::GridLayoutItem::new(&ui.input, 0, 0, 5, 1))
                .child(0, 1, &ui.btn1)
                .child(1, 1, &ui.btn2)
                .child(2, 1, &ui.btn3)
                .child(0, 2, &ui.btn4)
                .child(1, 2, &ui.btn5)
                .child(2, 2, &ui.btn6)
                .child(0, 3, &ui.btn7)
                .child(1, 3, &ui.btn8)
                .child(2, 3, &ui.btn9)
                .child(3, 1, &ui.btn_plus)
                .child(4, 1, &ui.btn_minus)
                .child(3, 2, &ui.btn_mult)
                .child(4, 2, &ui.btn_divide)
                .child_item(nwg::GridLayoutItem::new(&ui.btn_clear, 3, 3, 2, 1))
                .child_item(nwg::GridLayoutItem::new(&ui.btn_process, 3, 4, 2, 1))
                .child_item(nwg::GridLayoutItem::new(&ui.btn0, 0, 4, 3, 1))
                .build();

            return Ok(ui);
        }
    }

    impl Deref for CalculatorUi {
        type Target = Calculator;

        fn deref(&self) -> &Calculator {
            &self.inner
        }
    }

}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");

    let _app = Calculator::build_ui(Default::default()).expect("Failed to build UI");

    nwg::dispatch_thread_events();
}
<|endoftext|>


<commit_before>//! This module contains reusable components for encoding and decoding text in DICOM
//! data structures, including support for character repertoires.
//!
//! The Character Repertoires supported by DICOM are:
//! - ISO 8859
//! - JIS X 0201-1976 Code for Information Interchange
//! - JIS X 0208-1990 Code for the Japanese Graphic Character set for information interchange
//! - JIS X 0212-1990 Code of the supplementary Japanese Graphic Character set for information interchange
//! - KS X 1001 (registered as ISO-IR 149) for Korean Language
//! - TIS 620-2533 (1990) Thai Characters Code for Information Interchange
//! - ISO 10646-1, 10646-2, and their associated supplements and extensions for Unicode character set
//! - GB 18030
//! - GB2312
//!
//! At the moment, text encoding support is limited.
//! Please see [`SpecificCharacterSet`] for a complete enumeration
//! of all supported character encoding in the crate.
//!
//! [`SpecificCharacterSet`]: ./enum.SpecificCharacterSet.html

use crate::error::{Result, TextEncodingError};
use encoding::all::{GB18030, ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, UTF_8};
use encoding::{DecoderTrap, EncoderTrap, Encoding, RawDecoder, StringWriter};
use std::fmt::Debug;

/// A holder of encoding and decoding mechanisms for text in DICOM content,
/// which according to the standard, depends on the specific character set.
pub trait TextCodec {
    /// Obtain the defined term (unique name) of the text encoding,
    /// which may be used as the value of a
    /// Specific Character Set (0008, 0005) element to refer to this codec.
    ///
    /// Should contain no leading or trailing spaces.
    /// This method may be useful for testing purposes, considering that
    /// `TextCodec` is often used as a trait object.
    fn name(&self) -> &'static str;

    /// Decode the given byte buffer as a single string. The resulting string
    /// _may_ contain backslash characters ('\') to delimit individual values,
    /// and should be split later on if required.
    fn decode(&self, text: &[u8]) -> Result<String>;

    /// Encode a text value into a byte vector. The input string can
    /// feature multiple text values by using the backslash character ('\')
    /// as the value delimiter.
    fn encode(&self, text: &str) -> Result<Vec<u8>>;
}

impl<T: ?Sized> TextCodec for Box<T>
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        self.as_ref().name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        self.as_ref().decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        self.as_ref().encode(text)
    }
}

impl<'a, T: ?Sized> TextCodec for &'a T
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        (**self).name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        (**self).decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        (**self).encode(text)
    }
}

/// Type alias for a type erased text codec.
///
/// It is important because stateful decoders may need to change the expected
/// text encoding format at run-time.
pub type DynamicTextCodec = Box<dyn TextCodec>;

/// An enum type for all currently supported character sets.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum SpecificCharacterSet {
    /// **ISO-IR 6**: the default character set.
    Default,
    /// **ISO-IR 101** (ISO-8859-1): Right-hand part of the Latin alphabet no. 1,
    /// the Western Europe character set.
    IsoIr100,
    /// **ISO-IR 101** (ISO-8859-2): Right-hand part of the Latin alphabet no. 2,
    /// the Central/Eastern Europe character set.
    IsoIr101,
    /// **ISO-IR 109** (ISO-8859-3): Right-hand part of the Latin alphabet no. 3,
    /// the South Europe character set.
    IsoIr109,
    /// **ISO-IR 110** (ISO-8859-4): Right-hand part of the Latin alphabet no. 4,
    /// the North Europe character set.
    IsoIr110,
    /// **ISO-IR 144** (ISO-8859-5): The Latin/Cyrillic character set.
    IsoIr144,
    /// **ISO-IR 192**: The Unicode character set based on the UTF-8 encoding.
    IsoIr192,
    /// **GB18030**: The Simplified Chinese character set.
    GB18030,
    // Support for more text encodings is tracked in issue #40.
}

impl Default for SpecificCharacterSet {
    fn default() -> Self {
        SpecificCharacterSet::Default
    }
}

impl SpecificCharacterSet {
    pub fn from_code(uid: &str) -> Option<Self> {
        use self::SpecificCharacterSet::*;
        match uid.trim_end() {
            "Default" | "ISO_IR_6" | "ISO_IR 6" | "ISO 2022 IR 6" => Some(Default),
            "ISO_IR_100" | "ISO_IR 100" | "ISO 2022 IR 100" => Some(IsoIr100),
            "ISO_IR_101" | "ISO_IR 101" | "ISO 2022 IR 101" => Some(IsoIr101),
            "ISO_IR_109" | "ISO_IR 109" | "ISO 2022 IR 109" => Some(IsoIr109),
            "ISO_IR_110" | "ISO_IR 110" | "ISO 2022 IR 110" => Some(IsoIr110),
            "ISO_IR_144" | "ISO_IR 144" | "ISO 2022 IR 144" => Some(IsoIr144),
            "ISO_IR_192" | "ISO_IR 192" => Some(IsoIr192),
            "GB18030" => Some(GB18030),
            _ => None,
        }
    }

    /// Retrieve the respective text codec.
    pub fn codec(self) -> Option<DynamicTextCodec> {
        match self {
            SpecificCharacterSet::Default => Some(Box::new(DefaultCharacterSetCodec)),
            SpecificCharacterSet::IsoIr100 => Some(Box::new(IsoIr100CharacterSetCodec)),
            SpecificCharacterSet::IsoIr101 => Some(Box::new(IsoIr101CharacterSetCodec)),
            SpecificCharacterSet::IsoIr109 => Some(Box::new(IsoIr109CharacterSetCodec)),
            SpecificCharacterSet::IsoIr110 => Some(Box::new(IsoIr110CharacterSetCodec)),
            SpecificCharacterSet::IsoIr144 => Some(Box::new(IsoIr144CharacterSetCodec)),
            SpecificCharacterSet::IsoIr192 => Some(Box::new(Utf8CharacterSetCodec)),
            SpecificCharacterSet::GB18030 => Some(Box::new(Gb18030CharacterSetCodec)),
        }
    }
}

fn decode_text_trap(
    _decoder: &mut dyn RawDecoder,
    input: &[u8],
    output: &mut dyn StringWriter,
) -> bool {
    let c = input[0];
    let o0 = c & 7;
    let o1 = (c & 56) >> 3;
    let o2 = (c & 192) >> 6;
    output.write_char('\\');
    output.write_char((o2 + b'0') as char);
    output.write_char((o1 + b'0') as char);
    output.write_char((o0 + b'0') as char);
    true
}

/// Create and implement a character set type using the `encoding` crate.
macro_rules! decl_character_set {
    ($typ: ident, $term: literal, $val: expr) => {
        #[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
        #[doc = "Data type for the "]
        #[doc = $term]
        #[doc = "character set encoding."]
        pub struct $typ;

        impl TextCodec for $typ {
            fn name(&self) -> &'static str {
                $term
            }

            fn decode(&self, text: &[u8]) -> Result<String> {
                $val
                    .decode(text, DecoderTrap::Call(decode_text_trap))
                    .map_err(|e| TextEncodingError::new(e).into())
            }

            fn encode(&self, text: &str) -> Result<Vec<u8>> {
                $val
                    .encode(text, EncoderTrap::Strict)
                    .map_err(|e| TextEncodingError::new(e).into())
            }
        }
    };
}

/// Data type representing the default character set.
#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
pub struct DefaultCharacterSetCodec;

impl TextCodec for DefaultCharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 6"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        // Using 8859-1 because it is a superset. Reiterations of this impl
        // should check for invalid character codes (#40).
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

decl_character_set!(IsoIr100CharacterSetCodec, "ISO_IR 100", ISO_8859_1);
decl_character_set!(IsoIr101CharacterSetCodec, "ISO_IR 101", ISO_8859_2);
decl_character_set!(IsoIr109CharacterSetCodec, "ISO_IR 109", ISO_8859_3);
decl_character_set!(IsoIr110CharacterSetCodec, "ISO_IR 110", ISO_8859_4);
decl_character_set!(IsoIr144CharacterSetCodec, "ISO_IR 144", ISO_8859_5);
decl_character_set!(Utf8CharacterSetCodec, "ISO_IR 192", UTF_8);
decl_character_set!(Gb18030CharacterSetCodec, "GB18030", GB18030);

/// The result of a text validation procedure (please see [`validate_iso_8859`]).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TextValidationOutcome {
    /// The text is fully valid and can be safely decoded.
    Ok,
    /// Some characters may have to be replaced, other than that the text can be safely decoded.
    BadCharacters,
    /// The text cannot be decoded.
    NotOk,
}

/// Check whether the given byte slice contains valid text from the default character repertoire.
pub fn validate_iso_8859(text: &[u8]) -> TextValidationOutcome {
    if ISO_8859_1.decode(text, DecoderTrap::Strict).is_err() {
        match ISO_8859_1.decode(text, DecoderTrap::Call(decode_text_trap)) {
            Ok(_) => TextValidationOutcome::BadCharacters,
            Err(_) => TextValidationOutcome::NotOk,
        }
    } else {
        TextValidationOutcome::Ok
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date value representation.
pub fn validate_da(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| c >= b'0' && c <= b'9') {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Time value representation.
pub fn validate_tm(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'\\' | b'.' | b'-' | b' ' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date Time value representation.
pub fn validate_dt(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'.' | b'-' | b'+' | b' ' | b'\\' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Code String value representation.
pub fn validate_cs(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b' ' | b'_' => true,
        c => (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'Z'),
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

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

    #[test]
    fn iso_ir_6_baseline() {
        let codec = SpecificCharacterSet::Default
            .codec()
            .expect("Must be fully supported");
        assert_eq!(codec.decode(b"Smith^John").unwrap(), "Smith^John");
    }

    #[test]
    fn iso_ir_192_baseline() {
        let codec = SpecificCharacterSet::IsoIr192
            .codec()
            .expect("Should be fully supported");
        assert_eq!(
            codec.decode("Simões^John".as_bytes()).unwrap(),
            "Simões^John",
        );
        assert_eq!(
            codec.decode("Иванков^Андрей".as_bytes()).unwrap(),
            "Иванков^Андрей",
        );
    }

    #[test]
    fn iso_ir_100_baseline() {
        let codec = SpecificCharacterSet::IsoIr100
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"Sim\xF5es^Jo\xE3o").unwrap(), "Simões^João");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }

    #[test]
    fn iso_ir_101_baseline() {
        let codec = SpecificCharacterSet::IsoIr101
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }

    #[test]
    fn iso_ir_144_baseline() {
        let codec = SpecificCharacterSet::IsoIr144
            .codec()
            .expect("Should be fully supported");
        assert_eq!(
            codec
                .decode(b"\xb8\xd2\xd0\xdd\xda\xde\xd2^\xb0\xdd\xd4\xe0\xd5\xd9")
                .unwrap(),
            "Иванков^Андрей",
        );
    }
}
<commit_msg>[encoding] Test text codecs bidirectionally<commit_after>//! This module contains reusable components for encoding and decoding text in DICOM
//! data structures, including support for character repertoires.
//!
//! The Character Repertoires supported by DICOM are:
//! - ISO 8859
//! - JIS X 0201-1976 Code for Information Interchange
//! - JIS X 0208-1990 Code for the Japanese Graphic Character set for information interchange
//! - JIS X 0212-1990 Code of the supplementary Japanese Graphic Character set for information interchange
//! - KS X 1001 (registered as ISO-IR 149) for Korean Language
//! - TIS 620-2533 (1990) Thai Characters Code for Information Interchange
//! - ISO 10646-1, 10646-2, and their associated supplements and extensions for Unicode character set
//! - GB 18030
//! - GB2312
//!
//! At the moment, text encoding support is limited.
//! Please see [`SpecificCharacterSet`] for a complete enumeration
//! of all supported character encoding in the crate.
//!
//! [`SpecificCharacterSet`]: ./enum.SpecificCharacterSet.html

use crate::error::{Result, TextEncodingError};
use encoding::all::{GB18030, ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, UTF_8};
use encoding::{DecoderTrap, EncoderTrap, Encoding, RawDecoder, StringWriter};
use std::fmt::Debug;

/// A holder of encoding and decoding mechanisms for text in DICOM content,
/// which according to the standard, depends on the specific character set.
pub trait TextCodec {
    /// Obtain the defined term (unique name) of the text encoding,
    /// which may be used as the value of a
    /// Specific Character Set (0008, 0005) element to refer to this codec.
    ///
    /// Should contain no leading or trailing spaces.
    /// This method may be useful for testing purposes, considering that
    /// `TextCodec` is often used as a trait object.
    fn name(&self) -> &'static str;

    /// Decode the given byte buffer as a single string. The resulting string
    /// _may_ contain backslash characters ('\') to delimit individual values,
    /// and should be split later on if required.
    fn decode(&self, text: &[u8]) -> Result<String>;

    /// Encode a text value into a byte vector. The input string can
    /// feature multiple text values by using the backslash character ('\')
    /// as the value delimiter.
    fn encode(&self, text: &str) -> Result<Vec<u8>>;
}

impl<T: ?Sized> TextCodec for Box<T>
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        self.as_ref().name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        self.as_ref().decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        self.as_ref().encode(text)
    }
}

impl<'a, T: ?Sized> TextCodec for &'a T
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        (**self).name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        (**self).decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        (**self).encode(text)
    }
}

/// Type alias for a type erased text codec.
///
/// It is important because stateful decoders may need to change the expected
/// text encoding format at run-time.
pub type DynamicTextCodec = Box<dyn TextCodec>;

/// An enum type for all currently supported character sets.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum SpecificCharacterSet {
    /// **ISO-IR 6**: the default character set.
    Default,
    /// **ISO-IR 101** (ISO-8859-1): Right-hand part of the Latin alphabet no. 1,
    /// the Western Europe character set.
    IsoIr100,
    /// **ISO-IR 101** (ISO-8859-2): Right-hand part of the Latin alphabet no. 2,
    /// the Central/Eastern Europe character set.
    IsoIr101,
    /// **ISO-IR 109** (ISO-8859-3): Right-hand part of the Latin alphabet no. 3,
    /// the South Europe character set.
    IsoIr109,
    /// **ISO-IR 110** (ISO-8859-4): Right-hand part of the Latin alphabet no. 4,
    /// the North Europe character set.
    IsoIr110,
    /// **ISO-IR 144** (ISO-8859-5): The Latin/Cyrillic character set.
    IsoIr144,
    /// **ISO-IR 192**: The Unicode character set based on the UTF-8 encoding.
    IsoIr192,
    /// **GB18030**: The Simplified Chinese character set.
    GB18030,
    // Support for more text encodings is tracked in issue #40.
}

impl Default for SpecificCharacterSet {
    fn default() -> Self {
        SpecificCharacterSet::Default
    }
}

impl SpecificCharacterSet {
    pub fn from_code(uid: &str) -> Option<Self> {
        use self::SpecificCharacterSet::*;
        match uid.trim_end() {
            "Default" | "ISO_IR_6" | "ISO_IR 6" | "ISO 2022 IR 6" => Some(Default),
            "ISO_IR_100" | "ISO_IR 100" | "ISO 2022 IR 100" => Some(IsoIr100),
            "ISO_IR_101" | "ISO_IR 101" | "ISO 2022 IR 101" => Some(IsoIr101),
            "ISO_IR_109" | "ISO_IR 109" | "ISO 2022 IR 109" => Some(IsoIr109),
            "ISO_IR_110" | "ISO_IR 110" | "ISO 2022 IR 110" => Some(IsoIr110),
            "ISO_IR_144" | "ISO_IR 144" | "ISO 2022 IR 144" => Some(IsoIr144),
            "ISO_IR_192" | "ISO_IR 192" => Some(IsoIr192),
            "GB18030" => Some(GB18030),
            _ => None,
        }
    }

    /// Retrieve the respective text codec.
    pub fn codec(self) -> Option<DynamicTextCodec> {
        match self {
            SpecificCharacterSet::Default => Some(Box::new(DefaultCharacterSetCodec)),
            SpecificCharacterSet::IsoIr100 => Some(Box::new(IsoIr100CharacterSetCodec)),
            SpecificCharacterSet::IsoIr101 => Some(Box::new(IsoIr101CharacterSetCodec)),
            SpecificCharacterSet::IsoIr109 => Some(Box::new(IsoIr109CharacterSetCodec)),
            SpecificCharacterSet::IsoIr110 => Some(Box::new(IsoIr110CharacterSetCodec)),
            SpecificCharacterSet::IsoIr144 => Some(Box::new(IsoIr144CharacterSetCodec)),
            SpecificCharacterSet::IsoIr192 => Some(Box::new(Utf8CharacterSetCodec)),
            SpecificCharacterSet::GB18030 => Some(Box::new(Gb18030CharacterSetCodec)),
        }
    }
}

fn decode_text_trap(
    _decoder: &mut dyn RawDecoder,
    input: &[u8],
    output: &mut dyn StringWriter,
) -> bool {
    let c = input[0];
    let o0 = c & 7;
    let o1 = (c & 56) >> 3;
    let o2 = (c & 192) >> 6;
    output.write_char('\\');
    output.write_char((o2 + b'0') as char);
    output.write_char((o1 + b'0') as char);
    output.write_char((o0 + b'0') as char);
    true
}

/// Create and implement a character set type using the `encoding` crate.
macro_rules! decl_character_set {
    ($typ: ident, $term: literal, $val: expr) => {
        #[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
        #[doc = "Data type for the "]
        #[doc = $term]
        #[doc = "character set encoding."]
        pub struct $typ;

        impl TextCodec for $typ {
            fn name(&self) -> &'static str {
                $term
            }

            fn decode(&self, text: &[u8]) -> Result<String> {
                $val
                    .decode(text, DecoderTrap::Call(decode_text_trap))
                    .map_err(|e| TextEncodingError::new(e).into())
            }

            fn encode(&self, text: &str) -> Result<Vec<u8>> {
                $val
                    .encode(text, EncoderTrap::Strict)
                    .map_err(|e| TextEncodingError::new(e).into())
            }
        }
    };
}

/// Data type representing the default character set.
#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
pub struct DefaultCharacterSetCodec;

impl TextCodec for DefaultCharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 6"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        // Using 8859-1 because it is a superset. Reiterations of this impl
        // should check for invalid character codes (#40).
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

decl_character_set!(IsoIr100CharacterSetCodec, "ISO_IR 100", ISO_8859_1);
decl_character_set!(IsoIr101CharacterSetCodec, "ISO_IR 101", ISO_8859_2);
decl_character_set!(IsoIr109CharacterSetCodec, "ISO_IR 109", ISO_8859_3);
decl_character_set!(IsoIr110CharacterSetCodec, "ISO_IR 110", ISO_8859_4);
decl_character_set!(IsoIr144CharacterSetCodec, "ISO_IR 144", ISO_8859_5);
decl_character_set!(Utf8CharacterSetCodec, "ISO_IR 192", UTF_8);
decl_character_set!(Gb18030CharacterSetCodec, "GB18030", GB18030);

/// The result of a text validation procedure (please see [`validate_iso_8859`]).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TextValidationOutcome {
    /// The text is fully valid and can be safely decoded.
    Ok,
    /// Some characters may have to be replaced, other than that the text can be safely decoded.
    BadCharacters,
    /// The text cannot be decoded.
    NotOk,
}

/// Check whether the given byte slice contains valid text from the default character repertoire.
pub fn validate_iso_8859(text: &[u8]) -> TextValidationOutcome {
    if ISO_8859_1.decode(text, DecoderTrap::Strict).is_err() {
        match ISO_8859_1.decode(text, DecoderTrap::Call(decode_text_trap)) {
            Ok(_) => TextValidationOutcome::BadCharacters,
            Err(_) => TextValidationOutcome::NotOk,
        }
    } else {
        TextValidationOutcome::Ok
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date value representation.
pub fn validate_da(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| c >= b'0' && c <= b'9') {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Time value representation.
pub fn validate_tm(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'\\' | b'.' | b'-' | b' ' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date Time value representation.
pub fn validate_dt(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'.' | b'-' | b'+' | b' ' | b'\\' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Code String value representation.
pub fn validate_cs(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b' ' | b'_' => true,
        c => (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'Z'),
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

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

    fn test_codec<T>(codec: T, string: &str, bytes: &[u8])
    where
        T: TextCodec,
    {
        assert_eq!(codec.encode(string).expect("encoding"), bytes);
        assert_eq!(codec.decode(bytes).expect("decoding"), string);
    }

    #[test]
    fn iso_ir_6_baseline() {
        let codec = SpecificCharacterSet::Default
            .codec()
            .expect("Must be fully supported");
        test_codec(codec, "Smith^John", b"Smith^John");
    }

    #[test]
    fn iso_ir_192_baseline() {
        let codec = SpecificCharacterSet::IsoIr192
            .codec()
            .expect("Should be fully supported");
        test_codec(&codec, "Simões^John", "Simões^John".as_bytes());
        test_codec(codec, "Иванков^Андрей", "Иванков^Андрей".as_bytes());
    }

    #[test]
    fn iso_ir_100_baseline() {
        let codec = SpecificCharacterSet::IsoIr100
            .codec()
            .expect("Should be fully supported");
        test_codec(&codec, "Simões^João", b"Sim\xF5es^Jo\xE3o");
        test_codec(codec, "Günther^Hans", b"G\xfcnther^Hans");
    }

    #[test]
    fn iso_ir_101_baseline() {
        let codec = SpecificCharacterSet::IsoIr101
            .codec()
            .expect("Should be fully supported");
        test_codec(codec, "Günther^Hans", b"G\xfcnther^Hans");
    }

    #[test]
    fn iso_ir_144_baseline() {
        let codec = SpecificCharacterSet::IsoIr144
            .codec()
            .expect("Should be fully supported");
        test_codec(
            codec,
            "Иванков^Андрей",
            b"\xb8\xd2\xd0\xdd\xda\xde\xd2^\xb0\xdd\xd4\xe0\xd5\xd9",
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix bug.<commit_after><|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait A {
    fn a_method();
}

trait B: A {
    fn b_method();
}

trait C: B {
    fn c_method() {
        self.a_method();
    }
}

fn main() {}

<commit_msg>xfail transitive inheritance test -- I guess this doesn't work yet<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-test
trait A {
    fn a_method();
}

trait B: A {
    fn b_method();
}

trait C: B {
    fn c_method() {
        self.a_method();
    }
}

fn main() {}

<|endoftext|>


<commit_before>use crate::{
    analysis,
    chunk::Chunk,
    env::Env,
    nameutil::{use_glib_type, use_gtk_type},
};

pub struct Builder<'a> {
    name: String,
    in_trait: bool,
    var_name: String,
    is_get: bool,
    is_child_property: bool,
    type_: String,
    env: &'a Env,
}

#[allow(clippy::wrong_self_convention)]
impl<'a> Builder<'a> {
    pub fn new(env: &'a Env) -> Self {
        Self {
            env,
            name: Default::default(),
            in_trait: Default::default(),
            var_name: Default::default(),
            is_get: Default::default(),
            is_child_property: Default::default(),
            type_: Default::default(),
        }
    }

    pub fn new_for_child_property(env: &'a Env) -> Self {
        Self {
            is_child_property: true,
            env,
            name: Default::default(),
            in_trait: Default::default(),
            var_name: Default::default(),
            is_get: Default::default(),
            type_: Default::default(),
        }
    }

    pub fn name(&mut self, name: &str) -> &mut Self {
        self.name = name.into();
        self
    }

    pub fn in_trait(&mut self, value: bool) -> &mut Self {
        self.in_trait = value;
        self
    }

    pub fn var_name(&mut self, name: &str) -> &mut Self {
        self.var_name = name.into();
        self
    }

    pub fn is_get(&mut self, value: bool) -> &mut Self {
        self.is_get = value;
        self
    }

    pub fn type_(&mut self, type_: &str) -> &mut Self {
        self.type_ = type_.into();
        self
    }

    pub fn generate(&self) -> Chunk {
        let chunks = if self.is_get {
            self.chunks_for_get()
        } else {
            self.chunks_for_set()
        };
        Chunk::BlockHalf(chunks)
    }

    fn chunks_for_get(&self) -> Vec<Chunk> {
        if self.is_child_property {
            // TODO: make use of safe bindings for child properties setter
            self.child_property_setter()
        } else {
            let self_ = if self.in_trait {
                "self.as_ref()"
            } else {
                "self"
            };

            vec![Chunk::Custom(format!(
                "{}::property({}, \"{}\")",
                use_glib_type(self.env, "ObjectExt"),
                self_,
                self.name
            ))]
        }
    }

    fn chunks_for_set(&self) -> Vec<Chunk> {
        if self.is_child_property {
            // TODO: make use of safe bindings for child properties getter
            self.child_property_getter()
        } else {
            let self_ = if self.in_trait {
                "self.as_ref()"
            } else {
                "self"
            };

            vec![Chunk::Custom(format!(
                "{}::set_property({},\"{}\", &{})",
                use_glib_type(self.env, "ObjectExt"),
                self_,
                self.name,
                self.var_name
            ))]
        }
    }

    fn child_property_setter(&self) -> Vec<Chunk> {
        let mut body = Vec::new();

        let mut params = Vec::new();
        let cast_target = use_gtk_type(self.env, "ffi::GtkContainer");
        if self.in_trait {
            params.push(Chunk::Custom(format!(
                "self.to_glib_none().0 as *mut {}",
                cast_target
            )));
        } else {
            params.push(Chunk::Custom(format!(
                "self.as_ptr() as *mut {}",
                cast_target
            )));
        }
        params.push(Chunk::Custom("item.to_glib_none().0 as *mut _".into()));

        params.push(Chunk::Custom(format!(
            "b\"{}\\0\".as_ptr() as *const _",
            self.name
        )));
        params.push(Chunk::Custom("value.to_glib_none_mut().0".into()));

        let ffi_call = Chunk::FfiCall {
            name: use_gtk_type(self.env, "ffi::gtk_container_child_get_property"),
            params,
        };

        body.push(Chunk::Let {
            name: "value".into(),
            is_mut: true,
            value: Box::new(Chunk::Custom(format!(
                "glib::Value::from_type(<{} as StaticType>::static_type())",
                self.type_
            ))),
            type_: None,
        });

        body.push(Chunk::FfiCallConversion {
            ret: analysis::return_value::Info::default(),
            array_length_name: None,
            call: Box::new(ffi_call),
        });

        body.push(Chunk::Custom(format!(
            "value.get().expect(\"Return Value for property `{}` getter\")",
            self.name,
        )));
        vec![Chunk::Unsafe(body)]
    }

    fn child_property_getter(&self) -> Vec<Chunk> {
        let mut body = Vec::new();

        let mut params = Vec::new();
        let cast_target = use_gtk_type(self.env, "ffi::GtkContainer");
        if self.in_trait {
            params.push(Chunk::Custom(format!(
                "self.to_glib_none().0 as *mut {}",
                cast_target
            )));
        } else {
            params.push(Chunk::Custom(format!(
                "self.as_ptr() as *mut {}",
                cast_target
            )));
        }
        params.push(Chunk::Custom("item.to_glib_none().0 as *mut _".into()));
        params.push(Chunk::Custom(format!(
            "b\"{}\\0\".as_ptr() as *const _",
            self.name
        )));
        params.push(Chunk::Custom(format!(
            "{}.to_value().to_glib_none().0",
            self.var_name
        )));

        let ffi_call = Chunk::FfiCall {
            name: use_gtk_type(self.env, "ffi::gtk_container_child_set_property"),
            params,
        };
        body.push(Chunk::FfiCallConversion {
            ret: analysis::return_value::Info::default(),
            array_length_name: None,
            call: Box::new(ffi_call),
        });
        vec![Chunk::Unsafe(body)]
    }
}
<commit_msg>codgen: go through the safe bindings for child properties<commit_after>use crate::{
    chunk::Chunk,
    env::Env,
    nameutil::{use_glib_type, use_gtk_type},
};

pub struct Builder<'a> {
    name: String,
    in_trait: bool,
    var_name: String,
    is_get: bool,
    is_child_property: bool,
    type_: String,
    env: &'a Env,
}

#[allow(clippy::wrong_self_convention)]
impl<'a> Builder<'a> {
    pub fn new(env: &'a Env) -> Self {
        Self {
            env,
            name: Default::default(),
            in_trait: Default::default(),
            var_name: Default::default(),
            is_get: Default::default(),
            is_child_property: Default::default(),
            type_: Default::default(),
        }
    }

    pub fn new_for_child_property(env: &'a Env) -> Self {
        Self {
            is_child_property: true,
            env,
            name: Default::default(),
            in_trait: Default::default(),
            var_name: Default::default(),
            is_get: Default::default(),
            type_: Default::default(),
        }
    }

    pub fn name(&mut self, name: &str) -> &mut Self {
        self.name = name.into();
        self
    }

    pub fn in_trait(&mut self, value: bool) -> &mut Self {
        self.in_trait = value;
        self
    }

    pub fn var_name(&mut self, name: &str) -> &mut Self {
        self.var_name = name.into();
        self
    }

    pub fn is_get(&mut self, value: bool) -> &mut Self {
        self.is_get = value;
        self
    }

    pub fn type_(&mut self, type_: &str) -> &mut Self {
        self.type_ = type_.into();
        self
    }

    pub fn generate(&self) -> Chunk {
        let chunks = if self.is_get {
            self.chunks_for_get()
        } else {
            self.chunks_for_set()
        };
        Chunk::BlockHalf(chunks)
    }

    fn chunks_for_get(&self) -> Vec<Chunk> {
        if self.is_child_property {
            let self_ = if self.in_trait {
                "self.as_ref()"
            } else {
                "self"
            };

            vec![Chunk::Custom(format!(
                "{}::child_property({}, &item.clone().upcast(),\"{}\")",
                use_gtk_type(self.env, "prelude::ContainerExtManual"),
                self_,
                self.name,
            ))]
        } else {
            let self_ = if self.in_trait {
                "self.as_ref()"
            } else {
                "self"
            };

            vec![Chunk::Custom(format!(
                "{}::property({}, \"{}\")",
                use_glib_type(self.env, "ObjectExt"),
                self_,
                self.name
            ))]
        }
    }

    fn chunks_for_set(&self) -> Vec<Chunk> {
        if self.is_child_property {
            let self_ = if self.in_trait {
                "self.as_ref()"
            } else {
                "self"
            };

            vec![Chunk::Custom(format!(
                "{}::child_set_property({}, &item.clone().upcast(),\"{}\", &{})",
                use_gtk_type(self.env, "prelude::ContainerExtManual"),
                self_,
                self.name,
                self.var_name
            ))]
        } else {
            let self_ = if self.in_trait {
                "self.as_ref()"
            } else {
                "self"
            };

            vec![Chunk::Custom(format!(
                "{}::set_property({},\"{}\", &{})",
                use_glib_type(self.env, "ObjectExt"),
                self_,
                self.name,
                self.var_name
            ))]
        }
    }
}
<|endoftext|>