<commit_before>use std::rc::Rc;
use game_map::{RoomId, GameMap};
use combat::CombatState;
use platform;

const PAUSE_MS: u64 = 2500;
const CHEATING_FOOD_DIVISOR: i32 = 4;
const INITIAL_STRENGTH: i32 = 100;
const INITIAL_WEALTH: i32 = 75;
const STRENGTH_PER_FOOD: i32 = 5;
const TALLY_PER_MOVE: i32 = 1;
const STRENGTH_LOSS_PER_MOVE: i32 = 5;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum GameMode {
  AskName,
  Primary,
  Inventory,
  EatFood,
  Combat(CombatState),
  Finished,

  #[cfg(debug_assertions)]
  Debug,
}

// We have our input callbacks have a GameState explicitly passed
// into them instead of expecting 'self' to be captured into their
// closure, because the latter leads to all kinds of lifetime
// headaches.
type InputCallback = Fn(&mut GameState, String);

pub struct GameState {
  pub map: GameMap,
  pub curr_mode: GameMode,
  pub shown_hint: bool,
  pub player_name: String,
  pub strength: i32,
  pub wealth: i32,
  pub food: i32,
  pub tally: i32,
  pub monsters_killed: i32,
  pub sword: bool,
  pub amulet: bool,
  pub axe: bool,
  pub suit: bool,
  pub light: bool,
  pub curr_room: RoomId,
  pub show_desc: bool,
  input_callback: Option<Rc<InputCallback>>,
}

impl GameState {
  pub fn new() -> Self {
    Self {
      map: GameMap::new(),
      player_name: String::from(""),
      curr_mode: GameMode::AskName,
      curr_room: RoomId::Entrance,
      shown_hint: false,
      strength: INITIAL_STRENGTH,
      wealth: INITIAL_WEALTH,
      food: 0,
      tally: 0,
      monsters_killed: 0,
      sword: false,
      amulet: false,
      axe: false,
      suit: false,
      light: false,
      show_desc: true,
      input_callback: None,
    }
  }

  pub fn read_input<F>(&mut self, cb: F)
      where F: 'static + Fn(&mut GameState, String) {
    assert!(self.input_callback.is_none(),
            "Program must not already be waiting for input");
    self.input_callback = Some(Rc::new(cb));
  }

  pub fn can_player_see(&self) -> bool {
    self.curr_room == RoomId::Entrance || self.light
  }

  pub fn set_mode(&mut self, mode: GameMode) {
    self.show_desc = true;
    self.curr_mode = mode;
  }

  pub fn print_wealth(&self) {
    print!("You have ");
    if self.wealth > 0 {
      println!("${}.", self.wealth);
    } else {
      println!("no money.");
    }
  }

  pub fn print_food(&self) {
    println!("Your provisions sack holds {} unit{} of food.",
             self.food, if self.food == 1 { "" } else { "s" });
  }

  fn get_score(&self) -> i32 {
    3  * self.tally +
    5  * self.strength +
    2  * self.wealth +
    1  * self.food +
    30 * self.monsters_killed
  }

  pub fn finish_game(&mut self) {
    self.curr_mode = GameMode::Finished;
    println!("Your score is {}.\n", self.get_score());
    println!("Farewell.");
  }

  pub fn is_finished(&self) -> bool {
    self.curr_mode == GameMode::Finished
  }

  pub fn accuse_player_of_cheating(&mut self) {
    println!("YOU HAVE TRIED TO CHEAT ME!");
    self.wealth = 0;
    self.light = false;
    self.axe = false;
    self.sword = false;
    self.food = self.food / CHEATING_FOOD_DIVISOR;
    self.amulet = false;
    self.suit = false;
    Self::pause();
  }

  pub fn pause() {
    platform::hide_prompt();
    platform::sleep(PAUSE_MS);
  }

  fn die(&mut self) {
    println!("You have died.........");
    Self::pause();
    self.finish_game();
  }

  fn tick_ask_name_mode(&mut self) {
    platform::show_prompt("What is your name, explorer? ");

    self.read_input(|state, input| {
      if input.len() == 0 {
        println!("Pardon me?");
      } else {
        platform::hide_prompt();
        state.player_name = input;
        state.set_mode(GameMode::Primary);
      }
    });
  }

  fn tick_eat_food_mode(&mut self) {
    if self.show_desc {
      self.print_food();
      println!("");
      self.show_desc = false;
    }

    platform::show_prompt("How many do you want to eat? ");

    platform::read_input().map(|input| {
      match input.parse::<i32>() {
        Ok(amount) => {
          if amount < 0 {
            println!("GIVE ME A POSITIVE INTEGER.");
          } else if amount == 0 {
            println!("Fine, be that way.");
            Self::pause();
            self.set_mode(GameMode::Primary);
          } else if amount > self.food {
            self.accuse_player_of_cheating();
            self.set_mode(GameMode::Primary);
          } else {
            platform::hide_prompt();
            println!("After some munching, you feel stronger.");
            self.food -= amount;
            self.strength += amount * STRENGTH_PER_FOOD;
            self.set_mode(GameMode::Primary);
            Self::pause();
          }
        },
        Err(_) => {
          println!("That does not even look like a number, {}.",
                   self.player_name);
        }
      }
    });
  }

  pub fn process_move(&mut self) {
    self.tally += TALLY_PER_MOVE;
    self.strength -= STRENGTH_LOSS_PER_MOVE;
  }

  pub fn tick(&mut self) {
    let mut input_cb: Option<Rc<InputCallback>> = None;

    if let Some(ref cb) = self.input_callback {
      input_cb = Some(cb.clone());
    }

    if let Some(ref cb) = input_cb {
      match platform::read_input() {
        Some(input) => {
          self.input_callback = None;
          cb(self, input);
        },
        None => {
          // We're probably running in the browser and there's currently
          // no input to process, so just return.
          return;
        }
      }
    }

    if self.strength < 1 { self.die() }

    match self.curr_mode {
      GameMode::AskName => { self.tick_ask_name_mode() },
      GameMode::Primary => { self.tick_primary_mode() },
      GameMode::Inventory => { self.tick_inventory_mode() },
      GameMode::EatFood => { self.tick_eat_food_mode() },
      GameMode::Combat(state) => { self.tick_combat_mode(&state) },
      GameMode::Finished => {},

      #[cfg(debug_assertions)]
      GameMode::Debug => { self.tick_debug_mode() },
    }
  }
}
<commit_msg>Make tick_eat_food_mode use input callback.<commit_after>use std::rc::Rc;
use game_map::{RoomId, GameMap};
use combat::CombatState;
use platform;

const PAUSE_MS: u64 = 2500;
const CHEATING_FOOD_DIVISOR: i32 = 4;
const INITIAL_STRENGTH: i32 = 100;
const INITIAL_WEALTH: i32 = 75;
const STRENGTH_PER_FOOD: i32 = 5;
const TALLY_PER_MOVE: i32 = 1;
const STRENGTH_LOSS_PER_MOVE: i32 = 5;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum GameMode {
  AskName,
  Primary,
  Inventory,
  EatFood,
  Combat(CombatState),
  Finished,

  #[cfg(debug_assertions)]
  Debug,
}

// We have our input callbacks have a GameState explicitly passed
// into them instead of expecting 'self' to be captured into their
// closure, because the latter leads to all kinds of lifetime
// headaches.
type InputCallback = Fn(&mut GameState, String);

pub struct GameState {
  pub map: GameMap,
  pub curr_mode: GameMode,
  pub shown_hint: bool,
  pub player_name: String,
  pub strength: i32,
  pub wealth: i32,
  pub food: i32,
  pub tally: i32,
  pub monsters_killed: i32,
  pub sword: bool,
  pub amulet: bool,
  pub axe: bool,
  pub suit: bool,
  pub light: bool,
  pub curr_room: RoomId,
  pub show_desc: bool,
  input_callback: Option<Rc<InputCallback>>,
}

impl GameState {
  pub fn new() -> Self {
    Self {
      map: GameMap::new(),
      player_name: String::from(""),
      curr_mode: GameMode::AskName,
      curr_room: RoomId::Entrance,
      shown_hint: false,
      strength: INITIAL_STRENGTH,
      wealth: INITIAL_WEALTH,
      food: 0,
      tally: 0,
      monsters_killed: 0,
      sword: false,
      amulet: false,
      axe: false,
      suit: false,
      light: false,
      show_desc: true,
      input_callback: None,
    }
  }

  pub fn read_input<F>(&mut self, cb: F)
      where F: 'static + Fn(&mut GameState, String) {
    assert!(self.input_callback.is_none(),
            "Program must not already be waiting for input");
    self.input_callback = Some(Rc::new(cb));
  }

  pub fn can_player_see(&self) -> bool {
    self.curr_room == RoomId::Entrance || self.light
  }

  pub fn set_mode(&mut self, mode: GameMode) {
    self.show_desc = true;
    self.curr_mode = mode;
  }

  pub fn print_wealth(&self) {
    print!("You have ");
    if self.wealth > 0 {
      println!("${}.", self.wealth);
    } else {
      println!("no money.");
    }
  }

  pub fn print_food(&self) {
    println!("Your provisions sack holds {} unit{} of food.",
             self.food, if self.food == 1 { "" } else { "s" });
  }

  fn get_score(&self) -> i32 {
    3  * self.tally +
    5  * self.strength +
    2  * self.wealth +
    1  * self.food +
    30 * self.monsters_killed
  }

  pub fn finish_game(&mut self) {
    self.curr_mode = GameMode::Finished;
    println!("Your score is {}.\n", self.get_score());
    println!("Farewell.");
  }

  pub fn is_finished(&self) -> bool {
    self.curr_mode == GameMode::Finished
  }

  pub fn accuse_player_of_cheating(&mut self) {
    println!("YOU HAVE TRIED TO CHEAT ME!");
    self.wealth = 0;
    self.light = false;
    self.axe = false;
    self.sword = false;
    self.food = self.food / CHEATING_FOOD_DIVISOR;
    self.amulet = false;
    self.suit = false;
    Self::pause();
  }

  pub fn pause() {
    platform::hide_prompt();
    platform::sleep(PAUSE_MS);
  }

  fn die(&mut self) {
    println!("You have died.........");
    Self::pause();
    self.finish_game();
  }

  fn tick_ask_name_mode(&mut self) {
    platform::show_prompt("What is your name, explorer? ");

    self.read_input(|state, input| {
      if input.len() == 0 {
        println!("Pardon me?");
      } else {
        platform::hide_prompt();
        state.player_name = input;
        state.set_mode(GameMode::Primary);
      }
    });
  }

  fn tick_eat_food_mode(&mut self) {
    if self.show_desc {
      self.print_food();
      println!("");
      self.show_desc = false;
    }

    platform::show_prompt("How many do you want to eat? ");

    self.read_input(|state, input| {
      match input.parse::<i32>() {
        Ok(amount) => {
          if amount < 0 {
            println!("GIVE ME A POSITIVE INTEGER.");
          } else if amount == 0 {
            println!("Fine, be that way.");
            Self::pause();
            state.set_mode(GameMode::Primary);
          } else if amount > state.food {
            state.accuse_player_of_cheating();
            state.set_mode(GameMode::Primary);
          } else {
            platform::hide_prompt();
            println!("After some munching, you feel stronger.");
            state.food -= amount;
            state.strength += amount * STRENGTH_PER_FOOD;
            state.set_mode(GameMode::Primary);
            Self::pause();
          }
        },
        Err(_) => {
          println!("That does not even look like a number, {}.",
                   state.player_name);
        }
      }
    });
  }

  pub fn process_move(&mut self) {
    self.tally += TALLY_PER_MOVE;
    self.strength -= STRENGTH_LOSS_PER_MOVE;
  }

  pub fn tick(&mut self) {
    let mut input_cb: Option<Rc<InputCallback>> = None;

    if let Some(ref cb) = self.input_callback {
      input_cb = Some(cb.clone());
    }

    if let Some(ref cb) = input_cb {
      match platform::read_input() {
        Some(input) => {
          self.input_callback = None;
          cb(self, input);
        },
        None => {
          // We're probably running in the browser and there's currently
          // no input to process, so just return.
          return;
        }
      }
    }

    if self.strength < 1 { self.die() }

    match self.curr_mode {
      GameMode::AskName => { self.tick_ask_name_mode() },
      GameMode::Primary => { self.tick_primary_mode() },
      GameMode::Inventory => { self.tick_inventory_mode() },
      GameMode::EatFood => { self.tick_eat_food_mode() },
      GameMode::Combat(state) => { self.tick_combat_mode(&state) },
      GameMode::Finished => {},

      #[cfg(debug_assertions)]
      GameMode::Debug => { self.tick_debug_mode() },
    }
  }
}
<|endoftext|>


<commit_before>#![allow(unused)]
extern crate rz80;
extern crate time;
extern crate minifb;

use std::cell::RefCell;
use minifb::{Window, Key, Scale, WindowOptions};
use rz80::*;

const FB_WIDTH: usize=256;          // Z1013 framebuffer width
const FB_HEIGHT: usize=256;         // Z1013 framebuffer height
const Z1013_MAX_KEYS: usize=128;
const Z1013_FREQ_KHZ: i64=2000;     // frequency (2MHz = 2000 kHz)

const DEV_PIO: usize=0;
const DEV_PIO_A: usize=0;
const DEV_PIO_B: usize=1;
const NUM_DEVS: usize=2;

static Z1013_MON_A2: &'static [u8] = include_bytes!("z1013_mon_a2.bin");
static Z1013_FONT:   &'static [u8] = include_bytes!("z1013_font.bin");

struct Z1013 {
    kbd_column_nr_requested: usize,
    kbd_8x8_requested: bool,
    next_kbd_column_bits: u64,
    kbd_column_bits: u64,
    key_map: [u64; Z1013_MAX_KEYS],
}

impl Z1013 {
    pub fn new() -> Z1013 {
        let mut z1013 = Z1013 {
            kbd_column_nr_requested: 0,
            kbd_8x8_requested: false,
            next_kbd_column_bits: 0,
            kbd_column_bits: 0,
            key_map: [0; Z1013_MAX_KEYS],
        };
        z1013.init_keymap_8x8();
        z1013
    }

    fn kbd_bit(col: usize, line: usize, num_lines: usize) -> u64 {
        (1u64<<line)<<(col*num_lines)
    }

    fn init_key(&mut self, ascii: u8, col: usize, line: usize, shift:usize, num_lines: usize) {
        let mask =
            Z1013::kbd_bit(col, line, num_lines) |
            if shift != 0 {Z1013::kbd_bit(7, 6, num_lines)} else {0};
        self.key_map[ascii as usize] = mask;
    }

    fn init_keymap_8x8(&mut self) {

        // 8x8 keyboard matrix with 2 shift-layers
        let layers_8x8 =
            b"13579-  \
              QETUO@  \
              ADGJL*  \
              YCBM.^  \
              24680[  \
              WRZIP]  \
              SFHK+\\  \
              XVN,/_  \
              !#%')=  \
              qetuo`  \
              adgjl:  \
              ycbm>~  \
              \"$&( {  \
              wrzip}  \
              sfhk;|  \
              xvn<?   ";
        for shift in 0..2 {
            for line in 0..8 {
                for col in 0..8 {
                    let c = layers_8x8[shift*64 + line*8 + col];
                    if 0x20 != c {
                        self.init_key(c, col, line, shift, 8);
                    }
                }
            }
        }

        // special keys
        self.init_key(0x20, 6, 4, 0, 8);    // space
        self.init_key(0x08, 6, 2, 0, 8);    // cursor left
        self.init_key(0x09, 6, 3, 0, 8);    // cursor right
        self.init_key(0x0A, 6, 7, 0, 8);    // cursor down
        self.init_key(0x0B, 6, 6, 0, 8);    // cursor up
        self.init_key(0x0D, 6, 1, 0, 8);    // enter

        // Ctrl+C (== STOP/BREAK)
        self.key_map[0x03] = Z1013::kbd_bit(6, 5, 8) | Z1013::kbd_bit(1, 3, 4);
    }

    pub fn poweron(&mut self, cpu: &mut CPU) {

        // reset the hardware
        self.init_keymap_8x8();
        self.kbd_column_nr_requested = 0;
        self.kbd_8x8_requested = false;
        self.next_kbd_column_bits = 0;
        self.kbd_column_bits = 0;

        // map memory (64 KByte RAM incl. vid-mem, and 2 KByte ROM)
        cpu.mem.unmap_all();
        cpu.mem.map(1, 0x00000, 0x0000, true, 1<<16);
        cpu.mem.map_bytes(0, 0x10000, 0xF000, false, &Z1013_MON_A2);

        // start execution at address 0xF000
        cpu.reg.set_pc(0xF000);
    }

    pub fn reset(&mut self, cpu: &mut CPU) {
        self.kbd_column_nr_requested = 0;
        self.next_kbd_column_bits = 0;
        self.kbd_column_bits = 0;
        cpu.reg.set_pc(0xF000);
    }

    pub fn put_key(&mut self, ascii: u8) {
        let key_index = (ascii as usize) & (Z1013_MAX_KEYS-1);
        match ascii {
            0 => {
                self.next_kbd_column_bits = 0;
            },
            _ => {
                self.next_kbd_column_bits = self.key_map[key_index];
            }
        }
    }
}

struct System {
    pub cpu: RefCell<CPU>,
    pub pio: RefCell<PIO>,
    pub daisy: RefCell<Daisychain>,
    pub z1013: RefCell<Z1013>,
}

impl Bus for System {

    fn cpu_outp(&self, port: RegT, val: RegT) {
        match port & 0xFF {
            // PIO-A data
            0x00 => {
                // println!("PIO-A write data {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_A, val);
            },
            // PIO-A, control
            0x01 => {
                // println!("PIO-A write control {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_A, val);
            },
            // PIO-B, data
            0x02 => {
                // println!("PIO-B write data {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_B, val);
            },
            // PIO-B, data
            0x03 => {
                // println!("PIO-B write control {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_B, val);
            },
            // keyboard column
            0x08 => {
                // println!("keyboard column {:x}", val);
                let mut z1013 = self.z1013.borrow_mut();
                if val == 0 {
                    z1013.kbd_column_bits = z1013.next_kbd_column_bits;
                }
                z1013.kbd_column_nr_requested = val as usize;
            },
            _ => {
                println!("CPU OUT: {:x}", val);
            }
        }
    }

    fn cpu_inp(&self, port: RegT) -> RegT {
        match port & 0xFF {
            // PIO-A data
            0x00 => {
                // println!("PIO-A read data");
                self.pio.borrow_mut().read_data(self, PIO_A)
            },
            // PIO-A control
            0x01 => {
                // println!("PIO-A read control");
                self.pio.borrow_mut().read_control()
            },
            // PIO-B read data
            0x02 => {
                // println!("PIO-B read data");
                self.pio.borrow_mut().read_data(self, PIO_B)
            },
            // PIO-B read control
            0x03 => {
                // println!("PIO-B read control");
                self.pio.borrow_mut().read_control()
            },
            _ => {
                println!("CPU IN: {:x}", port);
                0xFF
            }
        }
    }

    fn pio_outp(&self, pio: usize, chn: usize, data: RegT) {
        if chn == PIO_B {
            // println!("PIO-B out {:x}", data);
            let mut z1013 = self.z1013.borrow_mut();
            z1013.kbd_8x8_requested = 0 != (data & (1<<4));
        }
        else {
            println!("PIO-A output (unused)");
        }
    }

    fn pio_inp(&self, pio: usize, chn: usize) -> RegT {
        if chn == PIO_B {
            // println!("PIO-B in");
            let z1013 = self.z1013.borrow();
            let col = z1013.kbd_column_nr_requested & 7;
            let mut val = z1013.kbd_column_bits >> (col*8);
            if z1013.kbd_8x8_requested {
                val >>= 4;
            }
            val = 0xF & !(val & 0xF);
            val as RegT
        }
        else {
            println!("PIO-A input (unused)");
            0xFF
        }
    }

    fn irq(&self, ctrl_id: usize, vec: u8) {
        println!("IRQ");
    }
    fn irq_cpu(&self) {
        println!("IRQ CPU");
    }

    fn irq_ack(&self) -> RegT {
        println!("IRQ ACK");
        0
    }
    fn irq_reti(&self) {
        println!("IRQ RETI");
    }

}

impl System {
    pub fn new() -> System {
        System {
            cpu: RefCell::new(CPU::new()),
            pio: RefCell::new(PIO::new(DEV_PIO)),
            daisy: RefCell::new(Daisychain::new(NUM_DEVS)),
            z1013: RefCell::new(Z1013::new()),
        }
    }

    pub fn poweron(&self) {
        let mut z1013 = self.z1013.borrow_mut();
        let mut cpu = self.cpu.borrow_mut();
        z1013.poweron(&mut cpu);
    }

    pub fn reset(&self) {
        let mut cpu = self.cpu.borrow_mut();
        let mut pio = self.pio.borrow_mut();
        let mut daisy = self.daisy.borrow_mut();
        let mut z1013 = self.z1013.borrow_mut();
        cpu.reset();
        pio.reset();
        daisy.reset();
        z1013.reset(&mut cpu);
    }

    pub fn step(&self, micro_seconds: i64) {
        let num_cycles = (Z1013_FREQ_KHZ * micro_seconds) / 1000;
        let mut cur_cycles = 0;
        let mut cpu = self.cpu.borrow_mut();
        while cur_cycles < num_cycles {
            cur_cycles += cpu.step(self);
        }
    }

    pub fn decode_video(&self, fb: &mut [u32]) {
        let mut i: usize = 0;
        let cpu = self.cpu.borrow();
        let vid_mem = &cpu.mem.heap[0xEC00..0xF000];
        for y in 0..32 {
            for py in 0..8 {
                for x in 0..32 {
                    let chr = vid_mem[(y<<5)+x] as usize;
                    let bits = Z1013_FONT[(chr<<3)|py];
                    for px in 0..8 {
                        fb[i] = if (bits & (1<<(7-px))) != 0 {0xFFFFFFFF} else {0xFF000000};
                        i += 1;
                    }
                }
            }
        }
    }

    pub fn put_key(&mut self, ascii: u8) {
        let mut z1013 = self.z1013.borrow_mut();
        z1013.put_key(ascii);
    }
}

fn create_window() -> Window {
    match Window::new("rz80 Z1013 Example",
               FB_WIDTH, FB_HEIGHT,
               WindowOptions {
                   resize: true,
                   scale: Scale::X2,
                   ..WindowOptions::default()
               }) {
        Ok(win) => win,
        Err(err) => panic!("Unable to create minifb window: {}", err)
    }
}

fn main() {
    let mut system = System::new();
    let mut window = create_window();
    let mut frame_buffer = [0u32; FB_WIDTH*FB_HEIGHT];
    let micro_seconds_per_frame: i64 = 1000000 / 60;
    system.poweron();
    while window.is_open() && !window.is_key_down(Key::Escape) {
        if window.is_key_down(Key::A) {
            println!("KEY!");
            system.put_key(b'A');
        }
        else {
            system.put_key(0);
        }
        system.step(micro_seconds_per_frame);
        system.decode_video(&mut frame_buffer);
        window.update_with_buffer(&frame_buffer);
    }
}

<commit_msg>Disable window resize for now<commit_after>#![allow(unused)]
extern crate rz80;
extern crate time;
extern crate minifb;

use std::cell::RefCell;
use minifb::{Window, Key, Scale, WindowOptions};
use rz80::*;

const FB_WIDTH: usize=256;          // Z1013 framebuffer width
const FB_HEIGHT: usize=256;         // Z1013 framebuffer height
const Z1013_MAX_KEYS: usize=128;
const Z1013_FREQ_KHZ: i64=2000;     // frequency (2MHz = 2000 kHz)

const DEV_PIO: usize=0;
const DEV_PIO_A: usize=0;
const DEV_PIO_B: usize=1;
const NUM_DEVS: usize=2;

static Z1013_MON_A2: &'static [u8] = include_bytes!("z1013_mon_a2.bin");
static Z1013_FONT:   &'static [u8] = include_bytes!("z1013_font.bin");

struct Z1013 {
    kbd_column_nr_requested: usize,
    kbd_8x8_requested: bool,
    next_kbd_column_bits: u64,
    kbd_column_bits: u64,
    key_map: [u64; Z1013_MAX_KEYS],
}

impl Z1013 {
    pub fn new() -> Z1013 {
        let mut z1013 = Z1013 {
            kbd_column_nr_requested: 0,
            kbd_8x8_requested: false,
            next_kbd_column_bits: 0,
            kbd_column_bits: 0,
            key_map: [0; Z1013_MAX_KEYS],
        };
        z1013.init_keymap_8x8();
        z1013
    }

    fn kbd_bit(col: usize, line: usize, num_lines: usize) -> u64 {
        (1u64<<line)<<(col*num_lines)
    }

    fn init_key(&mut self, ascii: u8, col: usize, line: usize, shift:usize, num_lines: usize) {
        let mask =
            Z1013::kbd_bit(col, line, num_lines) |
            if shift != 0 {Z1013::kbd_bit(7, 6, num_lines)} else {0};
        self.key_map[ascii as usize] = mask;
    }

    fn init_keymap_8x8(&mut self) {

        // 8x8 keyboard matrix with 2 shift-layers
        let layers_8x8 =
            b"13579-  \
              QETUO@  \
              ADGJL*  \
              YCBM.^  \
              24680[  \
              WRZIP]  \
              SFHK+\\  \
              XVN,/_  \
              !#%')=  \
              qetuo`  \
              adgjl:  \
              ycbm>~  \
              \"$&( {  \
              wrzip}  \
              sfhk;|  \
              xvn<?   ";
        for shift in 0..2 {
            for line in 0..8 {
                for col in 0..8 {
                    let c = layers_8x8[shift*64 + line*8 + col];
                    if 0x20 != c {
                        self.init_key(c, col, line, shift, 8);
                    }
                }
            }
        }

        // special keys
        self.init_key(0x20, 6, 4, 0, 8);    // space
        self.init_key(0x08, 6, 2, 0, 8);    // cursor left
        self.init_key(0x09, 6, 3, 0, 8);    // cursor right
        self.init_key(0x0A, 6, 7, 0, 8);    // cursor down
        self.init_key(0x0B, 6, 6, 0, 8);    // cursor up
        self.init_key(0x0D, 6, 1, 0, 8);    // enter

        // Ctrl+C (== STOP/BREAK)
        self.key_map[0x03] = Z1013::kbd_bit(6, 5, 8) | Z1013::kbd_bit(1, 3, 4);
    }

    pub fn poweron(&mut self, cpu: &mut CPU) {

        // reset the hardware
        self.init_keymap_8x8();
        self.kbd_column_nr_requested = 0;
        self.kbd_8x8_requested = false;
        self.next_kbd_column_bits = 0;
        self.kbd_column_bits = 0;

        // map memory (64 KByte RAM incl. vid-mem, and 2 KByte ROM)
        cpu.mem.unmap_all();
        cpu.mem.map(1, 0x00000, 0x0000, true, 1<<16);
        cpu.mem.map_bytes(0, 0x10000, 0xF000, false, &Z1013_MON_A2);

        // start execution at address 0xF000
        cpu.reg.set_pc(0xF000);
    }

    pub fn reset(&mut self, cpu: &mut CPU) {
        self.kbd_column_nr_requested = 0;
        self.next_kbd_column_bits = 0;
        self.kbd_column_bits = 0;
        cpu.reg.set_pc(0xF000);
    }

    pub fn put_key(&mut self, ascii: u8) {
        let key_index = (ascii as usize) & (Z1013_MAX_KEYS-1);
        match ascii {
            0 => {
                self.next_kbd_column_bits = 0;
            },
            _ => {
                self.next_kbd_column_bits = self.key_map[key_index];
            }
        }
    }
}

struct System {
    pub cpu: RefCell<CPU>,
    pub pio: RefCell<PIO>,
    pub daisy: RefCell<Daisychain>,
    pub z1013: RefCell<Z1013>,
}

impl Bus for System {

    fn cpu_outp(&self, port: RegT, val: RegT) {
        match port & 0xFF {
            // PIO-A data
            0x00 => {
                // println!("PIO-A write data {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_A, val);
            },
            // PIO-A, control
            0x01 => {
                // println!("PIO-A write control {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_A, val);
            },
            // PIO-B, data
            0x02 => {
                // println!("PIO-B write data {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_B, val);
            },
            // PIO-B, data
            0x03 => {
                // println!("PIO-B write control {:x}", val);
                self.pio.borrow_mut().write_data(self, PIO_B, val);
            },
            // keyboard column
            0x08 => {
                // println!("keyboard column {:x}", val);
                let mut z1013 = self.z1013.borrow_mut();
                if val == 0 {
                    z1013.kbd_column_bits = z1013.next_kbd_column_bits;
                }
                z1013.kbd_column_nr_requested = val as usize;
            },
            _ => {
                println!("CPU OUT: {:x}", val);
            }
        }
    }

    fn cpu_inp(&self, port: RegT) -> RegT {
        match port & 0xFF {
            // PIO-A data
            0x00 => {
                // println!("PIO-A read data");
                self.pio.borrow_mut().read_data(self, PIO_A)
            },
            // PIO-A control
            0x01 => {
                // println!("PIO-A read control");
                self.pio.borrow_mut().read_control()
            },
            // PIO-B read data
            0x02 => {
                // println!("PIO-B read data");
                self.pio.borrow_mut().read_data(self, PIO_B)
            },
            // PIO-B read control
            0x03 => {
                // println!("PIO-B read control");
                self.pio.borrow_mut().read_control()
            },
            _ => {
                println!("CPU IN: {:x}", port);
                0xFF
            }
        }
    }

    fn pio_outp(&self, pio: usize, chn: usize, data: RegT) {
        if chn == PIO_B {
            // println!("PIO-B out {:x}", data);
            let mut z1013 = self.z1013.borrow_mut();
            z1013.kbd_8x8_requested = 0 != (data & (1<<4));
        }
        else {
            println!("PIO-A output (unused)");
        }
    }

    fn pio_inp(&self, pio: usize, chn: usize) -> RegT {
        if chn == PIO_B {
            // println!("PIO-B in");
            let z1013 = self.z1013.borrow();
            let col = z1013.kbd_column_nr_requested & 7;
            let mut val = z1013.kbd_column_bits >> (col*8);
            if z1013.kbd_8x8_requested {
                val >>= 4;
            }
            val = 0xF & !(val & 0xF);
            val as RegT
        }
        else {
            println!("PIO-A input (unused)");
            0xFF
        }
    }

    fn irq(&self, ctrl_id: usize, vec: u8) {
        println!("IRQ");
    }
    fn irq_cpu(&self) {
        println!("IRQ CPU");
    }

    fn irq_ack(&self) -> RegT {
        println!("IRQ ACK");
        0
    }
    fn irq_reti(&self) {
        println!("IRQ RETI");
    }

}

impl System {
    pub fn new() -> System {
        System {
            cpu: RefCell::new(CPU::new()),
            pio: RefCell::new(PIO::new(DEV_PIO)),
            daisy: RefCell::new(Daisychain::new(NUM_DEVS)),
            z1013: RefCell::new(Z1013::new()),
        }
    }

    pub fn poweron(&self) {
        let mut z1013 = self.z1013.borrow_mut();
        let mut cpu = self.cpu.borrow_mut();
        z1013.poweron(&mut cpu);
    }

    pub fn reset(&self) {
        let mut cpu = self.cpu.borrow_mut();
        let mut pio = self.pio.borrow_mut();
        let mut daisy = self.daisy.borrow_mut();
        let mut z1013 = self.z1013.borrow_mut();
        cpu.reset();
        pio.reset();
        daisy.reset();
        z1013.reset(&mut cpu);
    }

    pub fn step(&self, micro_seconds: i64) {
        let num_cycles = (Z1013_FREQ_KHZ * micro_seconds) / 1000;
        let mut cur_cycles = 0;
        let mut cpu = self.cpu.borrow_mut();
        while cur_cycles < num_cycles {
            cur_cycles += cpu.step(self);
        }
    }

    pub fn decode_video(&self, fb: &mut [u32]) {
        let mut i: usize = 0;
        let cpu = self.cpu.borrow();
        let vid_mem = &cpu.mem.heap[0xEC00..0xF000];
        for y in 0..32 {
            for py in 0..8 {
                for x in 0..32 {
                    let chr = vid_mem[(y<<5)+x] as usize;
                    let bits = Z1013_FONT[(chr<<3)|py];
                    for px in 0..8 {
                        fb[i] = if (bits & (1<<(7-px))) != 0 {0xFFFFFFFF} else {0xFF000000};
                        i += 1;
                    }
                }
            }
        }
    }

    pub fn put_key(&mut self, ascii: u8) {
        let mut z1013 = self.z1013.borrow_mut();
        z1013.put_key(ascii);
    }
}

fn create_window() -> Window {
    match Window::new("rz80 Z1013 Example",
               FB_WIDTH, FB_HEIGHT,
               WindowOptions {
                   resize: false,
                   scale: Scale::X2,
                   ..WindowOptions::default()
               }) {
        Ok(win) => win,
        Err(err) => panic!("Unable to create minifb window: {}", err)
    }
}

fn main() {
    let mut system = System::new();
    let mut window = create_window();
    let mut frame_buffer = [0u32; FB_WIDTH*FB_HEIGHT];
    let micro_seconds_per_frame: i64 = 1000000 / 60;
    system.poweron();
    while window.is_open() && !window.is_key_down(Key::Escape) {
        if window.is_key_down(Key::A) {
            println!("KEY!");
            system.put_key(b'A');
        }
        else {
            system.put_key(0);
        }
        system.step(micro_seconds_per_frame);
        system.decode_video(&mut frame_buffer);
        window.update_with_buffer(&frame_buffer);
    }
}

<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;

use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };

struct App {
    gl: GlGraphics,
    triangles: Vec<[[f64; 2]; 4]>
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

        let triangles = &self.triangles;

        self.gl.draw(args.viewport(), |c, gl| {
            clear(WHITE, gl);

            let transform = c.transform.trans(0.0, 0.0);

            for t in triangles {
              polygon(BLACK, t, transform, gl);
            }
        });
    }
}

fn sub_triangles(v: [[f64; 2]; 4]) -> Vec<[[f64; 2]; 4]> {
    let (a, b, c, d) = (v[0], v[1], v[2], v[3]); // Vector destructuring is not yet stable.

    vec![
        [[a[0] + ((b[0] - a[0]) / 2.0), a[1]],
         [b[0] - ((b[0] - c[0]) / 2.0), b[1] - ((b[1] - c[1]) / 2.0)],
         [a[0] + ((c[0] - a[0]) / 2.0), a[1] - ((a[1] - c[1]) / 2.0)],
         [a[0] + ((b[0] - a[0]) / 2.0), a[1]]],
        [[100.0, 200.0], [200.0, 200.0], [150.0, 100.0], [100.0, 200.0]],
        [[100.0, 200.0], [200.0, 200.0], [150.0, 100.0], [100.0, 200.0]],
        [[100.0, 200.0], [200.0, 200.0], [150.0, 100.0], [100.0, 200.0]]]
}

fn sierpinski(depth: i32, vertices: [[f64; 2]; 4]) -> Vec<[[f64; 2]; 4]> {
    let mut triangles = vec![];

    match depth {
        0 => triangles,
        d @ _ => {
            let sub_tris = sub_triangles(vertices);

            triangles.push(sub_tris[0]);

            for sub_tri in &sub_tris[1..] {
                for t in sierpinski(d - 1, *sub_tri) {
                    triangles.push(t);
                }
            }

            triangles
        },
    }
}

fn main() {
    let opengl = OpenGL::V3_2;

    let window: Window = WindowSettings::new(
        "Sierpinski-Triangle",
        [1000, 800])
        .opengl(opengl)
        .exit_on_esc(true)
        .build()
        .unwrap();

    let triangles = sierpinski(4, [[50.0, 750.0], [950.0, 750.0],
                                   [500.0, 50.0], [50.0, 750.0]]);

    let mut app = App{gl: GlGraphics::new(opengl), triangles: triangles};

    for e in window.events().max_fps(1) {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
    }
}
<commit_msg>Drawing triangle correctly<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;

use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };

struct App {
    gl: GlGraphics,
    triangles: Vec<[[f64; 2]; 4]>
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

        let triangles = &self.triangles;

        self.gl.draw(args.viewport(), |c, gl| {
            clear(WHITE, gl);

            let transform = c.transform.trans(0.0, 0.0);

            for t in triangles {
              polygon(BLACK, t, transform, gl);
            }
        });
    }
}

fn sub_triangles(v: [[f64; 2]; 4]) -> Vec<[[f64; 2]; 4]> {
    let (a, b, c, d) = (v[0], v[1], v[2], v[3]); // Vector destructuring is not yet stable.

    vec![
        [[a[0] + ((b[0] - a[0]) / 2.0), a[1]],
         [b[0] - ((b[0] - c[0]) / 2.0), b[1] - ((b[1] - c[1]) / 2.0)],
         [a[0] + ((c[0] - a[0]) / 2.0), a[1] - ((a[1] - c[1]) / 2.0)],
         [a[0] + ((b[0] - a[0]) / 2.0), a[1]]],
        [[a[0], a[1]],
         [a[0] + ((b[0] - a[0]) / 2.0), a[1]],
         [a[0] + ((c[0] - a[0]) / 2.0), a[1] - ((a[1] - c[1]) / 2.0)],
         [a[0], a[1]]],
        [[a[0] + ((b[0] - a[0]) / 2.0), a[1]],
         [b[0], b[1]],
         [b[0] - ((b[0] - c[0]) / 2.0), b[1] - ((b[1] - c[1]) / 2.0)],
         [a[0] + ((b[0] - a[0]) / 2.0), a[1]]],
        [
         [a[0] + ((c[0] - a[0]) / 2.0), a[1] - ((a[1] - c[1]) / 2.0)],
         [b[0] - ((b[0] - c[0]) / 2.0), b[1] - ((b[1] - c[1]) / 2.0)],
         [c[0], c[1]],
         [a[0] + ((c[0] - a[0]) / 2.0), a[1] - ((a[1] - c[1]) / 2.0)]]]
}

fn sierpinski(depth: i32, vertices: [[f64; 2]; 4]) -> Vec<[[f64; 2]; 4]> {
    let mut triangles = vec![];

    match depth {
        0 => triangles,
        d @ _ => {
            let sub_tris = sub_triangles(vertices);

            triangles.push(sub_tris[0]);

            for sub_tri in &sub_tris[1..] {
                for t in sierpinski(d - 1, *sub_tri) {
                    triangles.push(t);
                }
            }

            triangles
        },
    }
}

fn main() {
    let opengl = OpenGL::V3_2;

    let window: Window = WindowSettings::new(
        "Sierpinski-Triangle",
        [1000, 800])
        .opengl(opengl)
        .exit_on_esc(true)
        .build()
        .unwrap();

    let triangles = sierpinski(8, [[50.0, 750.0], [950.0, 750.0],
                                   [500.0, 50.0], [50.0, 750.0]]);

    let mut app = App{gl: GlGraphics::new(opengl), triangles: triangles};

    for e in window.events().max_fps(1) {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
    }
}
<|endoftext|>


<commit_before>use core::ops::{Add, Mul};
use core::num::Wrapping;

/// Defines an additive identity element for `Self`.
pub trait Zero: Sized + Add<Self, Output = Self> {
    /// Returns the additive identity element of `Self`, `0`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a + 0 = a       ∀ a ∈ Self
    /// 0 + a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn zero() -> Self;

    /// Returns `true` if `self` is equal to the additive identity.
    #[inline]
    fn is_zero(&self) -> bool;
}

macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            #[inline]
            fn zero() -> $t { $v }
            #[inline]
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}

zero_impl!(usize, 0usize);
zero_impl!(u8,    0u8);
zero_impl!(u16,   0u16);
zero_impl!(u32,   0u32);
zero_impl!(u64,   0u64);

zero_impl!(isize, 0isize);
zero_impl!(i8,    0i8);
zero_impl!(i16,   0i16);
zero_impl!(i32,   0i32);
zero_impl!(i64,   0i64);

zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

impl<T: Zero> Zero for Wrapping<T> where Wrapping<T>: Add<Output=Wrapping<T>> {
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }
    fn zero() -> Self {
        Wrapping(T::zero())
    }
}

/// Defines a multiplicative identity element for `Self`.
pub trait One: Sized + Mul<Self, Output = Self> {
    /// Returns the multiplicative identity element of `Self`, `1`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a * 1 = a       ∀ a ∈ Self
    /// 1 * a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn one() -> Self;

    /// Returns `true` if `self` is equal to the multiplicative identity.
    ///
    /// For performance reasons, it's best to implement this manually.
    /// After a semver bump, this method will be required, and the
    /// `where Self: PartialEq` bound will be removed.
    fn is_one(&self) -> bool where Self: PartialEq {
        *self == Self::one()
    }
}

macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            #[inline]
            fn one() -> $t { $v }
        }
    }
}

one_impl!(usize, 1usize);
one_impl!(u8,    1u8);
one_impl!(u16,   1u16);
one_impl!(u32,   1u32);
one_impl!(u64,   1u64);

one_impl!(isize, 1isize);
one_impl!(i8,    1i8);
one_impl!(i16,   1i16);
one_impl!(i32,   1i32);
one_impl!(i64,   1i64);

one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);

impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
    fn one() -> Self {
        Wrapping(T::one())
    }
}

// Some helper functions provided for backwards compatibility.

/// Returns the additive identity, `0`.
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }

/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }

#[test]
fn wrapping_identities() {
    macro_rules! test_wrapping_identities {
        ($($t:ty)+) => {
            $(
                assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
                assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
                assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
                assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
            )+
        };
    }

    test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
}

#[test]
fn wrapping_is_zero() {
    fn require_zero<T: Zero>(_: &T) {}
    require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
    fn require_one<T: One>(_: &T) {}
    require_one(&Wrapping(42));
}
<commit_msg>Add #[inline] to is_one.<commit_after>use core::ops::{Add, Mul};
use core::num::Wrapping;

/// Defines an additive identity element for `Self`.
pub trait Zero: Sized + Add<Self, Output = Self> {
    /// Returns the additive identity element of `Self`, `0`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a + 0 = a       ∀ a ∈ Self
    /// 0 + a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn zero() -> Self;

    /// Returns `true` if `self` is equal to the additive identity.
    #[inline]
    fn is_zero(&self) -> bool;
}

macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            #[inline]
            fn zero() -> $t { $v }
            #[inline]
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}

zero_impl!(usize, 0usize);
zero_impl!(u8,    0u8);
zero_impl!(u16,   0u16);
zero_impl!(u32,   0u32);
zero_impl!(u64,   0u64);

zero_impl!(isize, 0isize);
zero_impl!(i8,    0i8);
zero_impl!(i16,   0i16);
zero_impl!(i32,   0i32);
zero_impl!(i64,   0i64);

zero_impl!(f32, 0.0f32);
zero_impl!(f64, 0.0f64);

impl<T: Zero> Zero for Wrapping<T> where Wrapping<T>: Add<Output=Wrapping<T>> {
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }
    fn zero() -> Self {
        Wrapping(T::zero())
    }
}

/// Defines a multiplicative identity element for `Self`.
pub trait One: Sized + Mul<Self, Output = Self> {
    /// Returns the multiplicative identity element of `Self`, `1`.
    ///
    /// # Laws
    ///
    /// ```{.text}
    /// a * 1 = a       ∀ a ∈ Self
    /// 1 * a = a       ∀ a ∈ Self
    /// ```
    ///
    /// # Purity
    ///
    /// This function should return the same result at all times regardless of
    /// external mutable state, for example values stored in TLS or in
    /// `static mut`s.
    // FIXME (#5527): This should be an associated constant
    fn one() -> Self;

    /// Returns `true` if `self` is equal to the multiplicative identity.
    ///
    /// For performance reasons, it's best to implement this manually.
    /// After a semver bump, this method will be required, and the
    /// `where Self: PartialEq` bound will be removed.
    #[inline]
    fn is_one(&self) -> bool where Self: PartialEq {
        *self == Self::one()
    }
}

macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            #[inline]
            fn one() -> $t { $v }
        }
    }
}

one_impl!(usize, 1usize);
one_impl!(u8,    1u8);
one_impl!(u16,   1u16);
one_impl!(u32,   1u32);
one_impl!(u64,   1u64);

one_impl!(isize, 1isize);
one_impl!(i8,    1i8);
one_impl!(i16,   1i16);
one_impl!(i32,   1i32);
one_impl!(i64,   1i64);

one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);

impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
    fn one() -> Self {
        Wrapping(T::one())
    }
}

// Some helper functions provided for backwards compatibility.

/// Returns the additive identity, `0`.
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }

/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }

#[test]
fn wrapping_identities() {
    macro_rules! test_wrapping_identities {
        ($($t:ty)+) => {
            $(
                assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
                assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
                assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
                assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
            )+
        };
    }

    test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
}

#[test]
fn wrapping_is_zero() {
    fn require_zero<T: Zero>(_: &T) {}
    require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
    fn require_one<T: One>(_: &T) {}
    require_one(&Wrapping(42));
}
<|endoftext|>


<commit_before>//! Local server that accepts SOCKS 5 protocol

use std::{io, net::SocketAddr, sync::Arc};

use futures::future::{self, Either};
use log::{debug, error, info, trace, warn};
use tokio::{
    self,
    net::{
        tcp::{ReadHalf, WriteHalf},
        TcpListener, TcpStream,
    },
    prelude::*,
};

use crate::{
    config::ServerConfig,
    context::{Context, SharedContext},
};

use crate::relay::{
    loadbalancing::server::{LoadBalancer, PingBalancer},
    socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
};

use super::ignore_until_end;

#[derive(Debug, Clone)]
struct UdpConfig {
    enable_udp: bool,
    client_addr: SocketAddr,
}

async fn handle_socks5_connect<'a>(
    context: &Context,
    (mut r, mut w): (ReadHalf<'a>, WriteHalf<'a>),
    client_addr: SocketAddr,
    local_addr: SocketAddr,
    addr: &Address,
    svr_cfg: Arc<ServerConfig>,
) -> io::Result<()> {
    let svr_s = match super::connect_proxy_server(context, &*svr_cfg).await {
        Ok(svr_s) => {
            trace!("Proxy server connected, {:?}", svr_cfg);

            // Tell the client that we are ready
            let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(local_addr));
            header.write_to(&mut w).await?;
            w.flush().await?;

            trace!("Sent header: {:?}", header);

            svr_s
        }
        Err(err) => {
            use crate::relay::socks5::Reply;
            use std::io::ErrorKind;

            error!("Failed to connect remote server, err: {}", err);

            let reply = match err.kind() {
                ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
                ErrorKind::ConnectionAborted => Reply::HostUnreachable,
                _ => Reply::NetworkUnreachable,
            };

            let header = TcpResponseHeader::new(reply, Address::SocketAddress(local_addr));
            header.write_to(&mut w).await?;
            w.flush().await?;

            return Err(err);
        }
    };

    let mut svr_s = super::proxy_server_handshake(svr_s, svr_cfg.clone(), addr).await?;
    let (mut svr_r, mut svr_w) = svr_s.split();

    use tokio::io::copy;

    let rhalf = copy(&mut r, &mut svr_w);
    let whalf = copy(&mut svr_r, &mut w);

    debug!(
        "CONNECT relay established {} <-> {} ({})",
        client_addr,
        svr_cfg.addr(),
        addr
    );

    match future::select(rhalf, whalf).await {
        Either::Left((Ok(..), _)) => trace!("CONNECT relay {} -> {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Left((Err(err), _)) => trace!(
            "CONNECT relay {} -> {} ({}) closed with error {:?}",
            client_addr,
            svr_cfg.addr(),
            err,
            addr,
        ),
        Either::Right((Ok(..), _)) => trace!("CONNECT relay {} <- {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Right((Err(err), _)) => trace!(
            "CONNECT relay {} <- {} ({}) closed with error {:?}",
            client_addr,
            svr_cfg.addr(),
            err,
            addr,
        ),
    }

    debug!(
        "CONNECT relay {} <-> {} ({}) closing",
        client_addr,
        svr_cfg.addr(),
        addr
    );

    Ok(())
}

#[allow(clippy::cognitive_complexity)]
async fn handle_socks5_client(
    context: &Context,
    mut s: TcpStream,
    conf: Arc<ServerConfig>,
    udp_conf: UdpConfig,
) -> io::Result<()> {
    if let Err(err) = s.set_keepalive(conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if context.config().no_delay {
        if let Err(err) = s.set_nodelay(true) {
            error!("Failed to set no delay: {:?}", err);
        }
    }

    let client_addr = s.peer_addr()?;
    let local_addr = s.local_addr()?;

    let (mut r, mut w) = s.split();

    let handshake_req = HandshakeRequest::read_from(&mut r).await?;

    // Socks5 handshakes
    trace!("Socks5 {:?}", handshake_req);

    let (handshake_resp, res) = if !handshake_req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
        let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
        warn!("Currently shadowsocks-rust does not support authentication");
        (
            resp,
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Currently shadowsocks-rust does not support authentication",
            )),
        )
    } else {
        // Reply to client
        let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
        trace!("Reply handshake {:?}", resp);
        (resp, Ok(()))
    };

    handshake_resp.write_to(&mut w).await?;
    w.flush().await?;

    res?;

    // Fetch headers
    let header = match TcpRequestHeader::read_from(&mut r).await {
        Ok(h) => h,
        Err(err) => {
            error!("Failed to get TcpRequestHeader: {}", err);
            let rh = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr));
            rh.write_to(&mut w).await?;
            return Err(From::from(err));
        }
    };

    trace!("Socks5 {:?}", header);

    let addr = header.address;
    match header.command {
        socks5::Command::TcpConnect => {
            let enable_tcp = context.config().mode.enable_tcp();
            if enable_tcp {
                debug!("CONNECT {}", addr);

                match handle_socks5_connect(context, (r, w), client_addr, local_addr, &addr, conf).await {
                    Ok(..) => Ok(()),
                    Err(err) => Err(io::Error::new(
                        err.kind(),
                        format!("CONNECT {} failed with error \"{}\"", addr, err),
                    )),
                }
            } else {
                warn!("CONNECT is not enabled");
                let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
                rh.write_to(&mut w).await?;

                Ok(())
            }
        }
        socks5::Command::TcpBind => {
            warn!("BIND is not supported");
            let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
            rh.write_to(&mut w).await?;

            Ok(())
        }
        socks5::Command::UdpAssociate => {
            if udp_conf.enable_udp {
                debug!("UDP ASSOCIATE {}", addr);
                let rh = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr));
                rh.write_to(&mut w).await?;
                w.flush().await?;

                // Hold the connection until it ends by its own
                ignore_until_end(&mut r).await?;

                Ok(())
            } else {
                warn!("UDP ASSOCIATE is not enabled");
                let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
                rh.write_to(&mut w).await?;

                Ok(())
            }
        }
    }
}

/// Starts a TCP local server with Socks5 proxy protocol
pub async fn run(context: SharedContext) -> io::Result<()> {
    let local_addr = *context.config().local.as_ref().expect("Missing local config");

    let mut listener = TcpListener::bind(&local_addr)
        .await
        .unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));

    let actual_local_addr = listener.local_addr().expect("Could not determine port bound to");

    info!("ShadowSocks TCP Listening on {}", actual_local_addr);

    let udp_conf = UdpConfig {
        enable_udp: context.config().mode.enable_udp(),
        client_addr: actual_local_addr,
    };

    let mut servers = PingBalancer::new(context.clone());

    loop {
        let (socket, peer_addr) = listener.accept().await?;
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", peer_addr);
        trace!("Picked proxy server: {:?}", server_cfg);

        let context = context.clone();
        let udp_conf = udp_conf.clone();
        tokio::spawn(async move {
            if let Err(err) = handle_socks5_client(&*context, socket, server_cfg, udp_conf).await {
                error!("Socks5 client {}", err);
            }
        });
    }
}
<commit_msg>[#173] Socks5 local should return server connect port<commit_after>//! Local server that accepts SOCKS 5 protocol

use std::{io, net::SocketAddr, sync::Arc};

use futures::future::{self, Either};
use log::{debug, error, info, trace, warn};
use tokio::{
    self,
    net::{
        tcp::{ReadHalf, WriteHalf},
        TcpListener, TcpStream,
    },
    prelude::*,
};

use crate::{
    config::ServerConfig,
    context::{Context, SharedContext},
};

use crate::relay::{
    loadbalancing::server::{LoadBalancer, PingBalancer},
    socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
};

use super::ignore_until_end;

#[derive(Debug, Clone)]
struct UdpConfig {
    enable_udp: bool,
    client_addr: SocketAddr,
}

async fn handle_socks5_connect<'a>(
    context: &Context,
    (mut r, mut w): (ReadHalf<'a>, WriteHalf<'a>),
    client_addr: SocketAddr,
    addr: &Address,
    svr_cfg: Arc<ServerConfig>,
) -> io::Result<()> {
    let svr_s = match super::connect_proxy_server(context, &*svr_cfg).await {
        Ok(svr_s) => {
            trace!("Proxy server connected, {:?}", svr_cfg);

            // Tell the client that we are ready
            let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(svr_s.local_addr()?));
            header.write_to(&mut w).await?;
            w.flush().await?;

            trace!("Sent header: {:?}", header);

            svr_s
        }
        Err(err) => {
            use crate::relay::socks5::Reply;
            use std::io::ErrorKind;

            error!("Failed to connect remote server, err: {}", err);

            let reply = match err.kind() {
                ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
                ErrorKind::ConnectionAborted => Reply::HostUnreachable,
                _ => Reply::NetworkUnreachable,
            };

            let header = TcpResponseHeader::new(
                reply,
                Address::SocketAddress("0.0.0.0:0".parse::<SocketAddr>().unwrap()),
            );
            header.write_to(&mut w).await?;
            w.flush().await?;

            return Err(err);
        }
    };

    let mut svr_s = super::proxy_server_handshake(svr_s, svr_cfg.clone(), addr).await?;
    let (mut svr_r, mut svr_w) = svr_s.split();

    use tokio::io::copy;

    let rhalf = copy(&mut r, &mut svr_w);
    let whalf = copy(&mut svr_r, &mut w);

    debug!(
        "CONNECT relay established {} <-> {} ({})",
        client_addr,
        svr_cfg.addr(),
        addr
    );

    match future::select(rhalf, whalf).await {
        Either::Left((Ok(..), _)) => trace!("CONNECT relay {} -> {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Left((Err(err), _)) => trace!(
            "CONNECT relay {} -> {} ({}) closed with error {:?}",
            client_addr,
            svr_cfg.addr(),
            err,
            addr,
        ),
        Either::Right((Ok(..), _)) => trace!("CONNECT relay {} <- {} ({}) closed", client_addr, svr_cfg.addr(), addr),
        Either::Right((Err(err), _)) => trace!(
            "CONNECT relay {} <- {} ({}) closed with error {:?}",
            client_addr,
            svr_cfg.addr(),
            err,
            addr,
        ),
    }

    debug!(
        "CONNECT relay {} <-> {} ({}) closing",
        client_addr,
        svr_cfg.addr(),
        addr
    );

    Ok(())
}

#[allow(clippy::cognitive_complexity)]
async fn handle_socks5_client(
    context: &Context,
    mut s: TcpStream,
    conf: Arc<ServerConfig>,
    udp_conf: UdpConfig,
) -> io::Result<()> {
    if let Err(err) = s.set_keepalive(conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if context.config().no_delay {
        if let Err(err) = s.set_nodelay(true) {
            error!("Failed to set no delay: {:?}", err);
        }
    }

    let client_addr = s.peer_addr()?;

    let (mut r, mut w) = s.split();

    let handshake_req = HandshakeRequest::read_from(&mut r).await?;

    // Socks5 handshakes
    trace!("Socks5 {:?}", handshake_req);

    let (handshake_resp, res) = if !handshake_req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
        let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
        warn!("Currently shadowsocks-rust does not support authentication");
        (
            resp,
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Currently shadowsocks-rust does not support authentication",
            )),
        )
    } else {
        // Reply to client
        let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
        trace!("Reply handshake {:?}", resp);
        (resp, Ok(()))
    };

    handshake_resp.write_to(&mut w).await?;
    w.flush().await?;

    res?;

    // Fetch headers
    let header = match TcpRequestHeader::read_from(&mut r).await {
        Ok(h) => h,
        Err(err) => {
            error!("Failed to get TcpRequestHeader: {}", err);
            let rh = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr));
            rh.write_to(&mut w).await?;
            return Err(From::from(err));
        }
    };

    trace!("Socks5 {:?}", header);

    let addr = header.address;
    match header.command {
        socks5::Command::TcpConnect => {
            let enable_tcp = context.config().mode.enable_tcp();
            if enable_tcp {
                debug!("CONNECT {}", addr);

                match handle_socks5_connect(context, (r, w), client_addr, &addr, conf).await {
                    Ok(..) => Ok(()),
                    Err(err) => Err(io::Error::new(
                        err.kind(),
                        format!("CONNECT {} failed with error \"{}\"", addr, err),
                    )),
                }
            } else {
                warn!("CONNECT is not enabled");
                let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
                rh.write_to(&mut w).await?;

                Ok(())
            }
        }
        socks5::Command::TcpBind => {
            warn!("BIND is not supported");
            let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
            rh.write_to(&mut w).await?;

            Ok(())
        }
        socks5::Command::UdpAssociate => {
            if udp_conf.enable_udp {
                debug!("UDP ASSOCIATE {}", addr);
                let rh = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr));
                rh.write_to(&mut w).await?;
                w.flush().await?;

                // Hold the connection until it ends by its own
                ignore_until_end(&mut r).await?;

                Ok(())
            } else {
                warn!("UDP ASSOCIATE is not enabled");
                let rh = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr);
                rh.write_to(&mut w).await?;

                Ok(())
            }
        }
    }
}

/// Starts a TCP local server with Socks5 proxy protocol
pub async fn run(context: SharedContext) -> io::Result<()> {
    let local_addr = *context.config().local.as_ref().expect("Missing local config");

    let mut listener = TcpListener::bind(&local_addr)
        .await
        .unwrap_or_else(|err| panic!("Failed to listen on {}, {}", local_addr, err));

    let actual_local_addr = listener.local_addr().expect("Could not determine port bound to");

    info!("ShadowSocks TCP Listening on {}", actual_local_addr);

    let udp_conf = UdpConfig {
        enable_udp: context.config().mode.enable_udp(),
        client_addr: actual_local_addr,
    };

    let mut servers = PingBalancer::new(context.clone());

    loop {
        let (socket, peer_addr) = listener.accept().await?;
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", peer_addr);
        trace!("Picked proxy server: {:?}", server_cfg);

        let context = context.clone();
        let udp_conf = udp_conf.clone();
        tokio::spawn(async move {
            if let Err(err) = handle_socks5_client(&*context, socket, server_cfg, udp_conf).await {
                error!("Socks5 client {}", err);
            }
        });
    }
}
<|endoftext|>


<commit_before>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::{CHashMap, WriteGuard};
use std::collections::{BTreeMap, BTreeSet};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use super::*;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
}

struct DataObject {
    server: u64,
    cell: Option<Cell>
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError>;

    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn get_data_site(&self, server_id: u64) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok((self.data_sites .get(&server_id).unwrap().clone(), server_id))
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => self.get_data_site(id),
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock)
    }
    fn get_transaction(&self, tid: &TransactionId) -> Result<WriteGuard<TransactionId, Transaction>, TMError> {
        match self.transactions.get_mut(tid) {
            Some(tnx) => Ok(tnx),
            _ => {Err(TMError::TransactionNotFound)}
        }
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.tnx_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut tnx = self.get_transaction(tid)?;
        if let Some(dataObj) = tnx.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server, server_id)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone())
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None
                                });
                            }
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut tnx = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(id) {
            Some(server_id) => {
                tnx.data.insert(*id, DataObject {
                    server: server_id,
                    cell: Some(cell.clone())
                });
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<commit_msg>update and fix write when removed<commit_after>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::{CHashMap, WriteGuard};
use std::collections::{BTreeMap, BTreeSet};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use super::*;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
}

struct DataObject {
    server: u64,
    cell: Option<Cell>,
    new: bool
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError>;

    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn get_data_site(&self, server_id: u64) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok((self.data_sites .get(&server_id).unwrap().clone(), server_id))
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => self.get_data_site(id),
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock)
    }
    fn get_transaction(&self, tid: &TransactionId) -> Result<WriteGuard<TransactionId, Transaction>, TMError> {
        match self.transactions.get_mut(tid) {
            Some(tnx) => Ok(tnx),
            _ => {Err(TMError::TransactionNotFound)}
        }
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.tnx_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut tnx = self.get_transaction(tid)?;
        if let Some(dataObj) = tnx.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server, server_id)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone()),
                                    new: false
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None,
                                    new: false
                                });
                            }
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut tnx = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(id) {
            Some(server_id) => {
                let have_cached_cell = tnx.data.contains_key(id);
                if !have_cached_cell {
                    tnx.data.insert(*id, DataObject {
                        server: server_id,
                        cell: Some(cell.clone()),
                        new: true
                    });
                    Ok(TransactionExecResult::Accepted(()))
                } else {
                    let mut data_obj = tnx.data.get_mut(id).unwrap();
                    if !data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellAlreadyExisted))
                    }
                    data_obj.cell = Some(cell.clone());
                    Ok(TransactionExecResult::Accepted(()))
                }
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut tnx = self.get_transaction(tid)?;
        let id = cell.id();
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                let cell = cell.clone();
                if tnx.data.contains_key(&id) {
                    tnx.data.get_mut(&id).unwrap().cell = Some(cell)
                } else {
                    tnx.data.insert(id, DataObject {
                        server: server_id,
                        cell: Some(cell),
                        new: false
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<|endoftext|>


<commit_before>//! A "compatibility layer" for supporting older versions of Windows
//!
//! The standard library uses some Windows API functions that are not present
//! on older versions of Windows.  (Note that the oldest version of Windows
//! that Rust supports is Windows 7 (client) and Windows Server 2008 (server).)
//! This module implements a form of delayed DLL import binding, using
//! `GetModuleHandle` and `GetProcAddress` to look up DLL entry points at
//! runtime.
//!
//! This implementation uses a static initializer to look up the DLL entry
//! points. The CRT (C runtime) executes static initializers before `main`
//! is called (for binaries) and before `DllMain` is called (for DLLs).
//! This is the ideal time to look up DLL imports, because we are guaranteed
//! that no other threads will attempt to call these entry points. Thus,
//! we can look up the imports and store them in `static mut` fields
//! without any synchronization.
//!
//! This has an additional advantage: Because the DLL import lookup happens
//! at module initialization, the cost of these lookups is deterministic,
//! and is removed from the code paths that actually call the DLL imports.
//! That is, there is no unpredictable "cache miss" that occurs when calling
//! a DLL import. For applications that benefit from predictable delays,
//! this is a benefit. This also eliminates the comparison-and-branch
//! from the hot path.
//!
//! Currently, the standard library uses only a small number of dynamic
//! DLL imports. If this number grows substantially, then the cost of
//! performing all of the lookups at initialization time might become
//! substantial.
//!
//! The mechanism of registering a static initializer with the CRT is
//! documented in
//! [CRT Initialization](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160).
//! It works by contributing a global symbol to the `.CRT$XCU` section.
//! The linker builds a table of all static initializer functions.
//! The CRT startup code then iterates that table, calling each
//! initializer function.
//!
//! # **WARNING!!*
//! The environment that a static initializer function runs in is highly
//! constrained. There are **many** restrictions on what static initializers
//! can safely do. Static initializer functions **MUST NOT** do any of the
//! following (this list is not comprehensive):
//! * touch any other static field that is used by a different static
//!   initializer, because the order that static initializers run in
//!   is not defined.
//! * call `LoadLibrary` or any other function that acquires the DLL
//!   loader lock.
//! * call any Rust function or CRT function that touches any static
//!   (global) state.

macro_rules! compat_fn {
    ($module:literal: $(
        $(#[$meta:meta])*
        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
    )*) => ($(
        $(#[$meta])*
        pub mod $symbol {
            #[allow(unused_imports)]
            use super::*;
            use crate::mem;

            type F = unsafe extern "system" fn($($argtype),*) -> $rettype;

            /// Points to the DLL import, or the fallback function.
            ///
            /// This static can be an ordinary, unsynchronized, mutable static because
            /// we guarantee that all of the writes finish during CRT initialization,
            /// and all of the reads occur after CRT initialization.
            static mut PTR: Option<F> = None;

            /// This symbol is what allows the CRT to find the `init` function and call it.
            /// It is marked `#[used]` because otherwise Rust would assume that it was not
            /// used, and would remove it.
            #[used]
            #[link_section = ".CRT$XCU"]
            static INIT_TABLE_ENTRY: fn() = init;

            fn init() {
                // There is no locking here. This code is executed before main() is entered, and
                // is guaranteed to be single-threaded.
                //
                // DO NOT do anything interesting or complicated in this function! DO NOT call
                // any Rust functions or CRT functions, if those functions touch any global state,
                // because this function runs during global initialization. For example, DO NOT
                // do any dynamic allocation, don't call LoadLibrary, etc.
                unsafe {
                    let module_name: *const u8 = concat!($module, "\0").as_ptr();
                    let symbol_name: *const u8 = concat!(stringify!($symbol), "\0").as_ptr();
                    let module_handle = $crate::sys::c::GetModuleHandleA(module_name as *const i8);
                    if !module_handle.is_null() {
                        match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8) as usize {
                            0 => {}
                            n => {
                                PTR = Some(mem::transmute::<usize, F>(n));
                            }
                        }
                    }
                }
            }

            #[allow(dead_code)]
            pub fn option() -> Option<F> {
                unsafe { PTR }
            }

            #[allow(dead_code)]
            pub unsafe fn call($($argname: $argtype),*) -> $rettype {
                if let Some(ptr) = PTR {
                    ptr($($argname),*)
                } else {
                    $fallback_body
                }
            }
        }

        $(#[$meta])*
        pub use $symbol::call as $symbol;
    )*)
}
<commit_msg>Rollup merge of #81598 - sivadeilra:windows_dll_imports_fix_x86, r=m-ou-se<commit_after>//! A "compatibility layer" for supporting older versions of Windows
//!
//! The standard library uses some Windows API functions that are not present
//! on older versions of Windows.  (Note that the oldest version of Windows
//! that Rust supports is Windows 7 (client) and Windows Server 2008 (server).)
//! This module implements a form of delayed DLL import binding, using
//! `GetModuleHandle` and `GetProcAddress` to look up DLL entry points at
//! runtime.
//!
//! This implementation uses a static initializer to look up the DLL entry
//! points. The CRT (C runtime) executes static initializers before `main`
//! is called (for binaries) and before `DllMain` is called (for DLLs).
//! This is the ideal time to look up DLL imports, because we are guaranteed
//! that no other threads will attempt to call these entry points. Thus,
//! we can look up the imports and store them in `static mut` fields
//! without any synchronization.
//!
//! This has an additional advantage: Because the DLL import lookup happens
//! at module initialization, the cost of these lookups is deterministic,
//! and is removed from the code paths that actually call the DLL imports.
//! That is, there is no unpredictable "cache miss" that occurs when calling
//! a DLL import. For applications that benefit from predictable delays,
//! this is a benefit. This also eliminates the comparison-and-branch
//! from the hot path.
//!
//! Currently, the standard library uses only a small number of dynamic
//! DLL imports. If this number grows substantially, then the cost of
//! performing all of the lookups at initialization time might become
//! substantial.
//!
//! The mechanism of registering a static initializer with the CRT is
//! documented in
//! [CRT Initialization](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160).
//! It works by contributing a global symbol to the `.CRT$XCU` section.
//! The linker builds a table of all static initializer functions.
//! The CRT startup code then iterates that table, calling each
//! initializer function.
//!
//! # **WARNING!!*
//! The environment that a static initializer function runs in is highly
//! constrained. There are **many** restrictions on what static initializers
//! can safely do. Static initializer functions **MUST NOT** do any of the
//! following (this list is not comprehensive):
//! * touch any other static field that is used by a different static
//!   initializer, because the order that static initializers run in
//!   is not defined.
//! * call `LoadLibrary` or any other function that acquires the DLL
//!   loader lock.
//! * call any Rust function or CRT function that touches any static
//!   (global) state.

macro_rules! compat_fn {
    ($module:literal: $(
        $(#[$meta:meta])*
        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
    )*) => ($(
        $(#[$meta])*
        pub mod $symbol {
            #[allow(unused_imports)]
            use super::*;
            use crate::mem;

            type F = unsafe extern "system" fn($($argtype),*) -> $rettype;

            /// Points to the DLL import, or the fallback function.
            ///
            /// This static can be an ordinary, unsynchronized, mutable static because
            /// we guarantee that all of the writes finish during CRT initialization,
            /// and all of the reads occur after CRT initialization.
            static mut PTR: Option<F> = None;

            /// This symbol is what allows the CRT to find the `init` function and call it.
            /// It is marked `#[used]` because otherwise Rust would assume that it was not
            /// used, and would remove it.
            #[used]
            #[link_section = ".CRT$XCU"]
            static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;

            unsafe extern "C" fn init() {
                // There is no locking here. This code is executed before main() is entered, and
                // is guaranteed to be single-threaded.
                //
                // DO NOT do anything interesting or complicated in this function! DO NOT call
                // any Rust functions or CRT functions, if those functions touch any global state,
                // because this function runs during global initialization. For example, DO NOT
                // do any dynamic allocation, don't call LoadLibrary, etc.
                let module_name: *const u8 = concat!($module, "\0").as_ptr();
                let symbol_name: *const u8 = concat!(stringify!($symbol), "\0").as_ptr();
                let module_handle = $crate::sys::c::GetModuleHandleA(module_name as *const i8);
                if !module_handle.is_null() {
                    match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8) as usize {
                        0 => {}
                        n => {
                            PTR = Some(mem::transmute::<usize, F>(n));
                        }
                    }
                }
            }

            #[allow(dead_code)]
            pub fn option() -> Option<F> {
                unsafe { PTR }
            }

            #[allow(dead_code)]
            pub unsafe fn call($($argname: $argtype),*) -> $rettype {
                if let Some(ptr) = PTR {
                    ptr($($argname),*)
                } else {
                    $fallback_body
                }
            }
        }

        $(#[$meta])*
        pub use $symbol::call as $symbol;
    )*)
}
<|endoftext|>