<commit_before>use std::collections::{hash_map, HashSet, HashMap};
use grit;
use asm;

pub fn asm_from_grit(prog: &grit::ProgDef) -> asm::ProgDef {
  let mut prog_st = ProgSt {
      used_labels: HashSet::new(),
    };

  asm::ProgDef {
    fun_defs: prog.fun_defs.iter()
      .map(|fun_def| translate_fun_def(&mut prog_st, fun_def))
      .collect(),
    main_fun: translate_fun_name(&prog.main_fun),
  }
}

struct ProgSt {
  used_labels: HashSet<asm::Label>,
}

impl ProgSt {
  fn gen_label(&mut self, name: &grit::Label) -> asm::Label {
    for i in 1.. {
      let label = asm::Label(format!("{}${}", name.0, i));
      if self.used_labels.insert(label.clone()) {
        return label
      }
    }
    unreachable!()
  }
}

struct FunSt<'d> {
  prog_st: &'d mut ProgSt,
  fun_def: &'d grit::FunDef,
  emitted_labels: HashSet<grit::Label>,
  block_map: HashMap<grit::Label, &'d grit::Block>,
  label_map: HashMap<grit::Label, asm::Label>,
  blocks: Vec<asm::Block>,
}

impl<'d> FunSt<'d> {
  fn stack_mem(index: i32) -> asm::Mem {
    asm::Mem {
      displac: Some(asm::Imm::Int(index * 4)),
      offset: Some(asm::Reg::ESP),
      index: None,
      scale: None,
    }
  }

  fn slot_mem(&self, slot: &grit::Slot) -> asm::Mem {
    FunSt::stack_mem((self.fun_def.slot_count - slot.0) as i32)
  }

  fn call_arg_mem(&self, arg: i32) -> asm::Mem {
    FunSt::stack_mem(-2 - arg)
  }

  fn frame_info_mem(&self) -> asm::Mem {
    FunSt::stack_mem(self.fun_def.slot_count as i32)
  }

  fn extern_call_arg_mem(&self, argc: i32, arg: i32) -> asm::Mem {
    FunSt::stack_mem(-argc + arg)
  }

  fn extern_call_stack_shift(&self, argc: i32) -> i32 {
    -(argc * 4)
  }

  fn stack_frame_size(&self) -> i32 {
    ((2 + self.fun_def.slot_count) * 4) as i32
  }

  fn translate_label(&mut self, label: &grit::Label) -> asm::Label {
    match self.label_map.entry(label.clone()) {
      hash_map::Entry::Occupied(entry) =>
        entry.get().clone(),
      hash_map::Entry::Vacant(entry) =>
        entry.insert(self.prog_st.gen_label(label)).clone(),
    }
  }
}

fn translate_fun_def(prog_st: &mut ProgSt, fun_def: &grit::FunDef) -> asm::FunDef {
  let mut st = FunSt {
      prog_st: prog_st,
      fun_def: fun_def,
      emitted_labels: HashSet::new(),
      block_map: fun_def.blocks.iter()
        .map(|block| (block.label.clone(), block))
        .collect(),
      label_map: HashMap::new(),
      blocks: Vec::new(),
    };

  let frame_size = st.stack_frame_size();
  let frame_info_mem = st.frame_info_mem();
  st.blocks.push(asm::Block {
      label: None,
      instrs: vec![
          asm::Instr::AddRegImm(asm::Reg::ESP, asm::Imm::Int(-frame_size)),
          asm::Instr::MoveMemImm(frame_info_mem, asm::Imm::Int(123456)),
        ],
    });
  emit_block(&mut st, &fun_def.start_label);

  asm::FunDef {
    name: translate_fun_name(&fun_def.name),
    blocks: st.blocks,
  }
}

fn emit_block(st: &mut FunSt, label: &grit::Label) {
  if !st.emitted_labels.insert(label.clone()) {
    return
  }
  let block = *st.block_map.get(label).unwrap();

  let mut instrs = Vec::new();
  for op in block.ops.iter() {
    match *op {
      grit::Op::Call(ref dst_slot, ref fun_name, ref args) => {
        for (arg_idx, arg) in args.iter().enumerate() {
          let arg_mem = st.call_arg_mem(arg_idx as i32);
          move_mem_val(st, &mut instrs, arg_mem, arg);
        }
        let addr_imm = asm::Imm::FunAddr(translate_fun_name(fun_name));
        instrs.push(asm::Instr::CallImm(addr_imm));
        instrs.push(asm::Instr::MoveMemReg(st.slot_mem(dst_slot), asm::Reg::EAX));
      },
      grit::Op::ExternCall(ref dst_slot, ref extern_name, ref args) => {
        let argc = args.len();
        for (arg_idx, arg) in args.iter().enumerate() {
          let arg_mem = st.extern_call_arg_mem(argc as i32, arg_idx as i32);
          move_mem_val(st, &mut instrs, arg_mem, arg);
        }
        let addr_imm = asm::Imm::ExternAddr(translate_extern_name(extern_name));
        instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP,
          asm::Imm::Int(st.extern_call_stack_shift(argc as i32))));
        instrs.push(asm::Instr::CallImm(addr_imm));
        instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP,
          asm::Imm::Int(-st.extern_call_stack_shift(argc as i32))));
        instrs.push(asm::Instr::MoveMemReg(st.slot_mem(dst_slot), asm::Reg::EAX));
      },
      grit::Op::Assign(ref slots_vals) =>
        mass_move(st, &mut instrs,
            &slots_vals.iter().map(|&(ref slot, _)| slot.clone()).collect::<Vec<_>>()[..],
            &slots_vals.iter().map(|&(_, ref val)| val.clone()).collect::<Vec<_>>()[..]),
    }
  }

  match block.jump {
    grit::Jump::Goto(ref label) => {
      instrs.push(asm::Instr::Jump(
        asm::Imm::Label(st.translate_label(label))));
    },
    grit::Jump::Return(ref val) => {
      let frame_size = st.stack_frame_size();
      move_reg_val(st, &mut instrs, asm::Reg::EAX, val);
      instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP, asm::Imm::Int(frame_size)));
      instrs.push(asm::Instr::Return);
    },
    grit::Jump::TailCall(ref fun_name, ref args) => {
      let frame_size = st.stack_frame_size();
      mass_move(st, &mut instrs,
          &range(0, args.len()).map(grit::Slot).collect::<Vec<_>>()[..], &args[..]);
      instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP, asm::Imm::Int(frame_size)));
      instrs.push(asm::Instr::Jump(
        asm::Imm::FunAddr(translate_fun_name(fun_name))));
    },
    grit::Jump::Branch(ref boolval, ref then_label, ref else_label) =>
      match *boolval {
        grit::Boolval::IsTrue(ref val) => {
          cmp_val_imm(st, &mut instrs, val, asm::Imm::Float(0.0));
          instrs.push(asm::Instr::JumpIf(asm::Test::Equal,
            asm::Imm::Label(st.translate_label(else_label))));
          instrs.push(asm::Instr::Jump(
            asm::Imm::Label(st.translate_label(then_label))));
        },
        grit::Boolval::IsFalse(ref val) => {
          cmp_val_imm(st, &mut instrs, val, asm::Imm::Float(0.0));
          instrs.push(asm::Instr::JumpIf(asm::Test::NotEqual,
            asm::Imm::Label(st.translate_label(else_label))));
          instrs.push(asm::Instr::Jump(
            asm::Imm::Label(st.translate_label(then_label))));
        },
      },
  }

  let block_label = st.translate_label(label);
  st.blocks.push(asm::Block {
    label: Some(block_label),
    instrs: instrs,
  });

  match block.jump {
    grit::Jump::Goto(ref label) =>
      emit_block(st, label),
    grit::Jump::Branch(_, ref then_label, ref else_label) => {
      emit_block(st, then_label);
      emit_block(st, else_label);
    },
    grit::Jump::Return(_) | grit::Jump::TailCall(_, _) => (),
  }
}

fn move_mem_val(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  mem: asm::Mem, val: &grit::Val)
{
  match *val {
    grit::Val::Literal(num) => {
      instrs.push(asm::Instr::MoveMemImm(mem, asm::Imm::Float(num)));
    },
    grit::Val::Slot(ref slot) => {
      instrs.push(asm::Instr::MoveRegMem(asm::Reg::EDX, st.slot_mem(slot)));
      instrs.push(asm::Instr::MoveMemReg(mem, asm::Reg::EDX));
    },
  }
}

fn move_reg_val(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  reg: asm::Reg, val: &grit::Val)
{
  match *val {
    grit::Val::Literal(num) =>
      instrs.push(asm::Instr::MoveRegImm(reg, asm::Imm::Float(num))),
    grit::Val::Slot(ref slot) =>
      instrs.push(asm::Instr::MoveRegMem(reg, st.slot_mem(slot))),
  }
}

fn mass_move(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  slots: &[grit::Slot], vals: &[grit::Val])
{
  let mut remaining: HashSet<usize> = range(0, slots.len()).collect();
  let mut saved_in_reg = None;

  while !remaining.is_empty() {
    let required: HashSet<grit::Slot> = remaining.iter().cloned()
      .filter_map(|i| match vals[i] {
        grit::Val::Slot(ref src_slot) =>
          if saved_in_reg != Some(src_slot.clone()) {
            Some(src_slot.clone())
          } else {
            None
          },
        grit::Val::Literal(_) => None,
      }).collect();
    let mut satisfied = Vec::new();

    for &i in remaining.iter() {
      if !required.contains(&slots[i]) {
        match (&saved_in_reg, &vals[i]) {
          (&Some(ref saved_slot), &grit::Val::Slot(ref read_slot)) => {
            assert_eq!(saved_slot, read_slot);
            instrs.push(asm::Instr::MoveMemReg(st.slot_mem(&slots[i]), asm::Reg::EDX));
          },
          (_, &grit::Val::Slot(ref read_slot)) => {
            instrs.push(asm::Instr::MoveRegMem(asm::Reg::EDX, st.slot_mem(read_slot)));
            instrs.push(asm::Instr::MoveMemReg(st.slot_mem(&slots[i]), asm::Reg::EDX));
          },
          (_, &grit::Val::Literal(num)) => {
            instrs.push(asm::Instr::MoveMemImm(st.slot_mem(&slots[i]),
              asm::Imm::Float(num)));
          },
        }
        satisfied.push(i);
      }
    }

    if satisfied.is_empty() {
      let breaker = required.iter().next().unwrap();
      instrs.push(asm::Instr::MoveRegMem(asm::Reg::EDX, st.slot_mem(breaker)));
      saved_in_reg = Some(breaker.clone());
    }

    for i in satisfied.into_iter() {
      remaining.remove(&i);
    }
  }
}

fn cmp_val_imm(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  val: &grit::Val, imm: asm::Imm)
{
  match *val {
    grit::Val::Literal(num) => {
      instrs.push(asm::Instr::MoveRegImm(asm::Reg::EDX, asm::Imm::Float(num)));
      instrs.push(asm::Instr::CmpRegImm(asm::Reg::EDX, imm));
    },
    grit::Val::Slot(ref slot) => {
      instrs.push(asm::Instr::CmpMemImm(st.slot_mem(slot), imm));
    },
  }
}

fn translate_fun_name(name: &grit::FunName) -> asm::FunName {
  asm::FunName(name.0.clone())
}

fn translate_extern_name(name: &grit::ExternName) -> asm::ExternName {
  asm::ExternName(name.0.clone())
}
<commit_msg>Fix mass assignment (one register was not enough)<commit_after>use std::collections::{hash_map, HashSet, HashMap};
use grit;
use asm;

pub fn asm_from_grit(prog: &grit::ProgDef) -> asm::ProgDef {
  let mut prog_st = ProgSt {
      used_labels: HashSet::new(),
    };

  asm::ProgDef {
    fun_defs: prog.fun_defs.iter()
      .map(|fun_def| translate_fun_def(&mut prog_st, fun_def))
      .collect(),
    main_fun: translate_fun_name(&prog.main_fun),
  }
}

struct ProgSt {
  used_labels: HashSet<asm::Label>,
}

impl ProgSt {
  fn gen_label(&mut self, name: &grit::Label) -> asm::Label {
    for i in 1.. {
      let label = asm::Label(format!("{}${}", name.0, i));
      if self.used_labels.insert(label.clone()) {
        return label
      }
    }
    unreachable!()
  }
}

struct FunSt<'d> {
  prog_st: &'d mut ProgSt,
  fun_def: &'d grit::FunDef,
  emitted_labels: HashSet<grit::Label>,
  block_map: HashMap<grit::Label, &'d grit::Block>,
  label_map: HashMap<grit::Label, asm::Label>,
  blocks: Vec<asm::Block>,
}

impl<'d> FunSt<'d> {
  fn stack_mem(index: i32) -> asm::Mem {
    asm::Mem {
      displac: Some(asm::Imm::Int(index * 4)),
      offset: Some(asm::Reg::ESP),
      index: None,
      scale: None,
    }
  }

  fn slot_mem(&self, slot: &grit::Slot) -> asm::Mem {
    FunSt::stack_mem((self.fun_def.slot_count - slot.0) as i32)
  }

  fn call_arg_mem(&self, arg: i32) -> asm::Mem {
    FunSt::stack_mem(-2 - arg)
  }

  fn frame_info_mem(&self) -> asm::Mem {
    FunSt::stack_mem(self.fun_def.slot_count as i32)
  }

  fn extern_call_arg_mem(&self, argc: i32, arg: i32) -> asm::Mem {
    FunSt::stack_mem(-argc + arg)
  }

  fn extern_call_stack_shift(&self, argc: i32) -> i32 {
    -(argc * 4)
  }

  fn stack_frame_size(&self) -> i32 {
    ((2 + self.fun_def.slot_count) * 4) as i32
  }

  fn translate_label(&mut self, label: &grit::Label) -> asm::Label {
    match self.label_map.entry(label.clone()) {
      hash_map::Entry::Occupied(entry) =>
        entry.get().clone(),
      hash_map::Entry::Vacant(entry) =>
        entry.insert(self.prog_st.gen_label(label)).clone(),
    }
  }
}

fn translate_fun_def(prog_st: &mut ProgSt, fun_def: &grit::FunDef) -> asm::FunDef {
  let mut st = FunSt {
      prog_st: prog_st,
      fun_def: fun_def,
      emitted_labels: HashSet::new(),
      block_map: fun_def.blocks.iter()
        .map(|block| (block.label.clone(), block))
        .collect(),
      label_map: HashMap::new(),
      blocks: Vec::new(),
    };

  let frame_size = st.stack_frame_size();
  let frame_info_mem = st.frame_info_mem();
  st.blocks.push(asm::Block {
      label: None,
      instrs: vec![
          asm::Instr::AddRegImm(asm::Reg::ESP, asm::Imm::Int(-frame_size)),
          asm::Instr::MoveMemImm(frame_info_mem, asm::Imm::Int(123456)),
        ],
    });
  emit_block(&mut st, &fun_def.start_label);

  asm::FunDef {
    name: translate_fun_name(&fun_def.name),
    blocks: st.blocks,
  }
}

fn emit_block(st: &mut FunSt, label: &grit::Label) {
  if !st.emitted_labels.insert(label.clone()) {
    return
  }
  let block = *st.block_map.get(label).unwrap();

  let mut instrs = Vec::new();
  for op in block.ops.iter() {
    match *op {
      grit::Op::Call(ref dst_slot, ref fun_name, ref args) => {
        for (arg_idx, arg) in args.iter().enumerate() {
          let arg_mem = st.call_arg_mem(arg_idx as i32);
          move_mem_val(st, &mut instrs, arg_mem, arg);
        }
        let addr_imm = asm::Imm::FunAddr(translate_fun_name(fun_name));
        instrs.push(asm::Instr::CallImm(addr_imm));
        instrs.push(asm::Instr::MoveMemReg(st.slot_mem(dst_slot), asm::Reg::EAX));
      },
      grit::Op::ExternCall(ref dst_slot, ref extern_name, ref args) => {
        let argc = args.len();
        for (arg_idx, arg) in args.iter().enumerate() {
          let arg_mem = st.extern_call_arg_mem(argc as i32, arg_idx as i32);
          move_mem_val(st, &mut instrs, arg_mem, arg);
        }
        let addr_imm = asm::Imm::ExternAddr(translate_extern_name(extern_name));
        instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP,
          asm::Imm::Int(st.extern_call_stack_shift(argc as i32))));
        instrs.push(asm::Instr::CallImm(addr_imm));
        instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP,
          asm::Imm::Int(-st.extern_call_stack_shift(argc as i32))));
        instrs.push(asm::Instr::MoveMemReg(st.slot_mem(dst_slot), asm::Reg::EAX));
      },
      grit::Op::Assign(ref slots_vals) =>
        mass_move(st, &mut instrs,
            &slots_vals.iter().map(|&(ref slot, _)| slot.clone()).collect::<Vec<_>>()[..],
            &slots_vals.iter().map(|&(_, ref val)| val.clone()).collect::<Vec<_>>()[..]),
    }
  }

  match block.jump {
    grit::Jump::Goto(ref label) => {
      instrs.push(asm::Instr::Jump(
        asm::Imm::Label(st.translate_label(label))));
    },
    grit::Jump::Return(ref val) => {
      let frame_size = st.stack_frame_size();
      move_reg_val(st, &mut instrs, asm::Reg::EAX, val);
      instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP, asm::Imm::Int(frame_size)));
      instrs.push(asm::Instr::Return);
    },
    grit::Jump::TailCall(ref fun_name, ref args) => {
      let frame_size = st.stack_frame_size();
      mass_move(st, &mut instrs,
          &range(0, args.len()).map(grit::Slot).collect::<Vec<_>>()[..], &args[..]);
      instrs.push(asm::Instr::AddRegImm(asm::Reg::ESP, asm::Imm::Int(frame_size)));
      instrs.push(asm::Instr::Jump(
        asm::Imm::FunAddr(translate_fun_name(fun_name))));
    },
    grit::Jump::Branch(ref boolval, ref then_label, ref else_label) =>
      match *boolval {
        grit::Boolval::IsTrue(ref val) => {
          cmp_val_imm(st, &mut instrs, val, asm::Imm::Float(0.0));
          instrs.push(asm::Instr::JumpIf(asm::Test::Equal,
            asm::Imm::Label(st.translate_label(else_label))));
          instrs.push(asm::Instr::Jump(
            asm::Imm::Label(st.translate_label(then_label))));
        },
        grit::Boolval::IsFalse(ref val) => {
          cmp_val_imm(st, &mut instrs, val, asm::Imm::Float(0.0));
          instrs.push(asm::Instr::JumpIf(asm::Test::NotEqual,
            asm::Imm::Label(st.translate_label(else_label))));
          instrs.push(asm::Instr::Jump(
            asm::Imm::Label(st.translate_label(then_label))));
        },
      },
  }

  let block_label = st.translate_label(label);
  st.blocks.push(asm::Block {
    label: Some(block_label),
    instrs: instrs,
  });

  match block.jump {
    grit::Jump::Goto(ref label) =>
      emit_block(st, label),
    grit::Jump::Branch(_, ref then_label, ref else_label) => {
      emit_block(st, then_label);
      emit_block(st, else_label);
    },
    grit::Jump::Return(_) | grit::Jump::TailCall(_, _) => (),
  }
}

fn move_mem_val(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  mem: asm::Mem, val: &grit::Val)
{
  match *val {
    grit::Val::Literal(num) => {
      instrs.push(asm::Instr::MoveMemImm(mem, asm::Imm::Float(num)));
    },
    grit::Val::Slot(ref slot) => {
      instrs.push(asm::Instr::MoveRegMem(asm::Reg::EAX, st.slot_mem(slot)));
      instrs.push(asm::Instr::MoveMemReg(mem, asm::Reg::EAX));
    },
  }
}

fn move_reg_val(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  reg: asm::Reg, val: &grit::Val)
{
  match *val {
    grit::Val::Literal(num) =>
      instrs.push(asm::Instr::MoveRegImm(reg, asm::Imm::Float(num))),
    grit::Val::Slot(ref slot) =>
      instrs.push(asm::Instr::MoveRegMem(reg, st.slot_mem(slot))),
  }
}

fn mass_move(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  slots: &[grit::Slot], vals: &[grit::Val])
{
  let mut assigns: HashSet<usize> = range(0, slots.len())
    .filter(|&i| vals[i] != grit::Val::Slot(slots[i].clone()))
    .collect();
  let mut saved_in_reg: Option<grit::Slot> = None;

  while !assigns.is_empty() {
    let required_slots: HashSet<grit::Slot> = assigns.iter().cloned()
      .filter_map(|i| match vals[i] {
        grit::Val::Slot(ref slot) =>
          if Some(slot) != saved_in_reg.as_ref() {
            Some(slot.clone())
          } else {
            None
          },
        grit::Val::Literal(_) => None,
      }).collect();

    let mut satisfied = Vec::new();
    for i in assigns.iter().cloned() {
      let lslot = &slots[i];
      if !required_slots.contains(lslot) {
        match vals[i] {
          grit::Val::Literal(num) => {
            instrs.push(asm::Instr::MoveMemImm(st.slot_mem(lslot), asm::Imm::Float(num)));
          },
          grit::Val::Slot(ref rslot) => {
            if Some(rslot) == saved_in_reg.as_ref() {
              instrs.push(asm::Instr::MoveMemReg(st.slot_mem(lslot), asm::Reg::EDX));
            } else {
              instrs.push(asm::Instr::MoveRegMem(asm::Reg::EAX, st.slot_mem(rslot)));
              instrs.push(asm::Instr::MoveMemReg(st.slot_mem(lslot), asm::Reg::EAX));
            }
          }
        }
        satisfied.push(i);
      }
    }

    if satisfied.is_empty() {
      assert!(!required_slots.is_empty());
      let save_slot = required_slots.iter().next().unwrap();
      instrs.push(asm::Instr::MoveRegMem(asm::Reg::EDX, st.slot_mem(save_slot)));
      saved_in_reg = Some(save_slot.clone());
    } else {
      for i in satisfied.iter() {
        assigns.remove(i);
      }
    }
  }
}

fn cmp_val_imm(st: &mut FunSt, instrs: &mut Vec<asm::Instr>,
  val: &grit::Val, imm: asm::Imm)
{
  match *val {
    grit::Val::Literal(num) => {
      instrs.push(asm::Instr::MoveRegImm(asm::Reg::EDX, asm::Imm::Float(num)));
      instrs.push(asm::Instr::CmpRegImm(asm::Reg::EDX, imm));
    },
    grit::Val::Slot(ref slot) => {
      instrs.push(asm::Instr::CmpMemImm(st.slot_mem(slot), imm));
    },
  }
}

fn translate_fun_name(name: &grit::FunName) -> asm::FunName {
  asm::FunName(name.0.clone())
}

fn translate_extern_name(name: &grit::ExternName) -> asm::ExternName {
  asm::ExternName(name.0.clone())
}
<|endoftext|>


<commit_before>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkey::PKey;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl, SSL_OP_NO_SSLV2,
                         SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION, MidHandshakeSslStream};
use self::openssl::x509::X509;
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Certificate(X509);

pub struct Identity {
    cert: X509,
    pkey: PKey,
}

pub struct Pkcs12 {
    pub identity: Identity,
    pub chain: Vec<Certificate>,
}

impl Pkcs12 {
    pub fn parse(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));

        Ok(Pkcs12 {
            identity: Identity {
                cert: parsed.cert,
                pkey: parsed.pkey,
            },
            chain: parsed.chain.into_iter().map(Certificate).collect(),
        })
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    ctx.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
    try!(ctx.set_default_verify_paths());
    try!(ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH"));
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn handshake<S>(&mut self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new<I>(identity: Identity, certs: I) -> Result<ServerBuilder, Error>
        where I: IntoIterator<Item = Certificate>
    {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&identity.cert));
        try!(ctx.set_private_key(&identity.pkey));
        for cert in certs {
            try!(ctx.add_extra_chain_cert(&cert.0));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&mut self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<commit_msg>Check cert/private key match<commit_after>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkey::PKey;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl, SSL_OP_NO_SSLV2,
                         SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION, MidHandshakeSslStream};
use self::openssl::x509::X509;
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Certificate(X509);

pub struct Identity {
    cert: X509,
    pkey: PKey,
}

pub struct Pkcs12 {
    pub identity: Identity,
    pub chain: Vec<Certificate>,
}

impl Pkcs12 {
    pub fn parse(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));

        Ok(Pkcs12 {
            identity: Identity {
                cert: parsed.cert,
                pkey: parsed.pkey,
            },
            chain: parsed.chain.into_iter().map(Certificate).collect(),
        })
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    ctx.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION);
    try!(ctx.set_default_verify_paths());
    try!(ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH"));
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn handshake<S>(&mut self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new<I>(identity: Identity, certs: I) -> Result<ServerBuilder, Error>
        where I: IntoIterator<Item = Certificate>
    {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&identity.cert));
        try!(ctx.set_private_key(&identity.pkey));
        try!(ctx.check_private_key());
        for cert in certs {
            try!(ctx.add_extra_chain_cert(&cert.0));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&mut self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<|endoftext|>


<commit_before>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkey::PKey;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl,
                         MidHandshakeSslStream};
use self::openssl::x509::X509;
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12(pkcs12::ParsedPkcs12);

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));
        Ok(Pkcs12(parsed))
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ctx.set_default_verify_paths());
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        // FIXME clear chain certs to clean up if called multiple times
        try!(self.0.set_certificate(&pkcs12.0.cert));
        try!(self.0.set_private_key(&pkcs12.0.pkey));
        try!(self.0.check_private_key());
        for cert in &pkcs12.0.chain {
            try!(self.0.add_extra_chain_cert(&cert));
        }
        Ok(())
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ClientBuilder`.
pub trait ClientBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ClientBuilderExt for ::ClientBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&pkcs12.0.cert));
        try!(ctx.set_private_key(&pkcs12.0.pkey));
        try!(ctx.check_private_key());
        for cert in &pkcs12.0.chain {
            try!(ctx.add_extra_chain_cert(&cert));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ServerBuilder`.
pub trait ServerBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ServerBuilderExt for ::ServerBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<commit_msg>Remove unused imports<commit_after>extern crate openssl;
extern crate openssl_verify;

use std::io;
use std::fmt;
use std::error;
use self::openssl::crypto::pkcs12;
use self::openssl::error::ErrorStack;
use self::openssl::ssl::{self, SslContext, SslMethod, SSL_VERIFY_PEER, IntoSsl,
                         MidHandshakeSslStream};
use self::openssl_verify::verify_callback;

pub struct Error(ssl::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<ssl::Error> for Error {
    fn from(err: ssl::Error) -> Error {
        Error(err)
    }
}

impl From<ErrorStack> for Error {
    fn from(err: ErrorStack) -> Error {
        ssl::Error::Ssl(err).into()
    }
}

pub struct Pkcs12(pkcs12::ParsedPkcs12);

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let pkcs12 = try!(pkcs12::Pkcs12::from_der(buf));
        let parsed = try!(pkcs12.parse(pass));
        Ok(Pkcs12(parsed))
    }
}

pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            ssl::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
            ssl::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<ErrorStack> for HandshakeError<S> {
    fn from(e: ErrorStack) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

fn ctx() -> Result<SslContext, Error> {
    let mut ctx = try!(SslContext::new(SslMethod::Sslv23));
    try!(ctx.set_default_verify_paths());
    Ok(ctx)
}

pub struct ClientBuilder(SslContext);

impl ClientBuilder {
    pub fn new() -> Result<ClientBuilder, Error> {
        ctx().map(ClientBuilder)
    }

    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        // FIXME clear chain certs to clean up if called multiple times
        try!(self.0.set_certificate(&pkcs12.0.cert));
        try!(self.0.set_private_key(&pkcs12.0.pkey));
        try!(self.0.check_private_key());
        for cert in &pkcs12.0.chain {
            try!(self.0.add_extra_chain_cert(&cert));
        }
        Ok(())
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut ssl = try!(self.0.into_ssl());
        try!(ssl.set_hostname(domain));
        let domain = domain.to_owned();
        ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify_callback(&domain, p, x));

        let s = try!(ssl::SslStream::connect(ssl, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ClientBuilder`.
pub trait ClientBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ClientBuilderExt for ::ClientBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct ServerBuilder(SslContext);

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        let mut ctx = try!(ctx());
        try!(ctx.set_certificate(&pkcs12.0.cert));
        try!(ctx.set_private_key(&pkcs12.0.pkey));
        try!(ctx.check_private_key());
        for cert in &pkcs12.0.chain {
            try!(ctx.add_extra_chain_cert(&cert));
        }
        Ok(ServerBuilder(ctx))
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let s = try!(ssl::SslStream::accept(&self.0, stream));
        Ok(TlsStream(s))
    }
}

/// OpenSSL-specific extensions to `ServerBuilder`.
pub trait ServerBuilderExt {
    /// Returns a shared reference to the inner `SslContext`.
    fn context(&self) -> &SslContext;

    /// Returns a mutable reference to the inner `SslContext`.
    fn context_mut(&mut self) -> &mut SslContext;
}

impl ServerBuilderExt for ::ServerBuilder {
    fn context(&self) -> &SslContext {
        &(self.0).0
    }

    fn context_mut(&mut self) -> &mut SslContext {
        &mut (self.0).0
    }
}

pub struct TlsStream<S>(ssl::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.ssl().pending())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// OpenSSL-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the OpenSSL `SslStream`.
    fn raw_stream(&self) -> &ssl::SslStream<S>;

    /// Returns a mutable reference to the OpenSSL `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &ssl::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut ssl::SslStream<S> {
        &mut (self.0).0
    }
}
<|endoftext|>


<commit_before>/* kernel::sgash.rs */

use core::*;
use core::str::*;
use core::option::{Some, Option, None}; // Match statement
use core::iter::Iterator;
use core::vec::Vec;
use core::mem::Allocator;
use kernel::*;
use super::super::platform::*;

pub static mut buffer: cstr = cstr {
				p: 0 as *mut u8,
				p_cstr_i: 0,
				max: 0
			      };
pub fn putchar(key: char) {
    unsafe {
	/*
	 * We need to include a blank asm call to prevent rustc
	 * from optimizing this part out
	 */
	asm!("");
	io::write_char(key, io::UART0);
    }
}

#[lang = "exchange_free"]
fn putstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
	putchar(*c as char);
    }
}

/*
pub unsafe fn output(&cstr)
{
    p_cstr.map(|p| {
	let mut x = 0;
	while *(((p as uint)+x) as *char) != '\0'
	{
	    putchar(*(((p as uint)+x) as *char));
	    x += 1;
	}
    });
}
*/

pub unsafe fn parsekey(x: char) {
    let x = x as u8;
    // Set this to false to learn the keycodes of various keys!
    // Key codes are printed backwards because life is hard
    if (true) {
	match x {
	    13		=>	{ prompt(); }
	    127		=>	{
		if (buffer.delete_char()) { putchar(''); }
	    }
	    _		=>	{
		if (buffer.add_char(x)) { putchar(x as char); }
	    }
	}
    }
    else {
	keycode(x);
    }
}

fn keycode(x: u8) {
    let mut x = x;
    while ( x != 0 ) {
	putchar((x%10+ ('0' as u8) ) as char);
	x = x/10;
    }
    putchar(' ');
}

pub unsafe fn init() {
    prompt();
    buffer = cstr::new(256);
}

unsafe fn prompt() {
    putstr(&"\nsgash > ");
    buffer.reset();
}

/* BUFFER MODIFICATION FUNCTIONS */

struct cstr {
    p: *mut u8,
    p_cstr_i: uint,
    max: uint
}

impl cstr {
    pub unsafe fn new(size: uint) -> cstr {
	let (x, y) = memory::allocator.alloc(size);
	let this = cstr {
	    p: x,
	    p_cstr_i: 0,
	    max: y
	};
	this
    }

    unsafe fn add_char(&mut self, x: u8) -> bool{
	if (self.p_cstr_i == self.max) { return false; }
	*(((self.p as uint)+self.p_cstr_i) as *mut u8) = x;
	self.p_cstr_i += 1;
	*(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
	true
    }

    unsafe fn delete_char(&mut self) -> bool {
	if (self.p_cstr_i == 0) { return false; }
	self.p_cstr_i -= 1;
	*(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
	true
    }

    unsafe fn reset(&mut self) {
	self.p_cstr_i = 0;
	*(self.p as *mut char) = '\0';
    }
}

/* Utility functions! */
/*
fn eq(a: *mut u8, b: *mut u8) {
    ind = 0;
    while (a[i] !=
}
*/
<commit_msg>Fixed dumb bugs with strings<commit_after>/* kernel::sgash.rs */

use core::*;
use core::str::*;
use core::option::{Some, Option, None}; // Match statement
use core::iter::Iterator;
use core::vec::Vec;
use core::mem::Allocator;
use kernel::*;
use super::super::platform::*;

pub static mut buffer: cstr = cstr {
				p: 0 as *mut u8,
				p_cstr_i: 0,
				max: 0
			      };
pub fn putchar(key: char) {
    unsafe {
	/*
	 * We need to include a blank asm call to prevent rustc
	 * from optimizing this part out
	 */
	asm!("");
	io::write_char(key, io::UART0);
    }
}

#[lang = "exchange_free"]
fn putstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
	putchar(*c as char);
    }
}

pub unsafe fn output(s: cstr)
{
    let mut x = 0;
    while *(((s.p as uint)+x) as *char) != '\0'
    {
	putchar(*(((s.p as uint)+x) as *char));
	x += 1;
    }
}

pub unsafe fn parsekey(x: char) {
    let x = x as u8;
    // Set this to false to learn the keycodes of various keys!
    // Key codes are printed backwards because life is hard
    if (true) {
	match x {
	    13		=>	{ prompt(); }
	    127		=>	{
		if (buffer.delete_char()) {
		    putchar('');
		    putchar(' ');
		    putchar('');
		}
	    }
	    _		=>	{
		if (buffer.add_char(x)) { putchar(x as char); }
	    }
	}
    }
    else {
	keycode(x);
    }
}

fn keycode(x: u8) {
    let mut x = x;
    while ( x != 0 ) {
	putchar((x%10+ ('0' as u8) ) as char);
	x = x/10;
    }
    putchar(' ');
}

pub unsafe fn init() {
    buffer = cstr::new(256);
    prompt();
}

unsafe fn prompt() {
    putstr(&"\nsgash > ");
    output(buffer);
}

/* BUFFER MODIFICATION FUNCTIONS */

struct cstr {
    p: *mut u8,
    p_cstr_i: uint,
    max: uint
}

impl cstr {
    pub unsafe fn new(size: uint) -> cstr {
	let (x, y) = memory::allocator.alloc(size);
	let this = cstr {
	    p: x,
	    p_cstr_i: 0,
	    max: y
	};
	this
    }

    unsafe fn add_char(&mut self, x: u8) -> bool{
	if (self.p_cstr_i == self.max) { return false; }
	*(((self.p as uint)+self.p_cstr_i) as *mut u8) = x;
	self.p_cstr_i += 1;
	*(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
	true
    }

    unsafe fn delete_char(&mut self) -> bool {
	if (self.p_cstr_i == 0) { return false; }
	self.p_cstr_i -= 1;
	*(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
	true
    }

    unsafe fn reset(&mut self) {
	self.p_cstr_i = 0;
	*(self.p as *mut char) = '\0';
    }
}

/* Utility functions! */
/*
fn eq(a: *mut u8, b: *mut u8) {
    ind = 0;
    while (a[i] !=
}
*/
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::str;

use position;

/// A span over a `&str`. It is created from either [two `Position`s] or from a [`Pair`].
///
/// [two `Position`s]: struct.Position.html#method.span
/// [`Pair`]: ../iterators/struct.Pair.html#method.span
#[derive(Clone)]
pub struct Span<'i> {
    input: &'i str,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    start: usize,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    end: usize
}

impl<'i> Span<'i> {
    /// Create a new `Span` without checking invariants. (Checked with `debug_assertions`.)
    ///
    /// # Safety
    ///
    /// `input[start..end]` must be a valid subslice; that is, said indexing should not panic.
    pub(crate) unsafe fn new_unchecked(input: &str, start: usize, end: usize) -> Span {
        debug_assert!(input.get(start..end).is_some());
        Span { input, start, end }
    }

    /// Attempts to create a new span. Will return None if `input[start..end]` is an invalid index
    /// into `input`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Span;
    /// let input = "Hello!";
    /// assert_eq!(None, Span::new(input, 100, 0));
    /// assert!(Span::new(input, 0, input.len()).is_some());
    /// ```
    pub fn new(input: &str, start: usize, end: usize) -> Option<Span> {
        if input.get(start..end).is_some() {
            Some(Span { input, start, end })
        } else {
            None
        }
    }

    /// Returns the `Span`'s start byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.start(), 0);
    /// ```
    #[inline]
    pub fn start(&self) -> usize {
        self.start
    }

    /// Returns the `Span`'s end byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end(), 0);
    /// ```
    #[inline]
    pub fn end(&self) -> usize {
        self.end
    }

    /// Returns the `Span`'s start `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.start_pos(), start);
    /// ```
    #[inline]
    pub fn start_pos(&self) -> position::Position<'i> {
        // Span's start position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.start) }
    }

    /// Returns the `Span`'s end `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end_pos(), end);
    /// ```
    #[inline]
    pub fn end_pos(&self) -> position::Position<'i> {
        // Span's end position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.end) }
    }

    /// Splits the `Span` into a pair of `Position`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.split(), (start, end));
    /// ```
    #[inline]
    pub fn split(self) -> (position::Position<'i>, position::Position<'i>) {
        // Span's start and end positions are always a UTF-8 borders.
        let pos1 = unsafe { position::Position::new_unchecked(self.input, self.start) };
        let pos2 = unsafe { position::Position::new_unchecked(self.input, self.end) };

        (pos1, pos2)
    }

    /// Captures a slice from the `&str` defined by the `Span`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "abc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(1).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.as_str(), "b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        // Span's start and end positions are always a UTF-8 borders.
        &self.input[self.start..self.end]
    }
}

impl<'i> fmt::Debug for Span<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Span")
            .field("str", &self.as_str())
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

impl<'i> PartialEq for Span<'i> {
    fn eq(&self, other: &Span<'i>) -> bool {
        ptr::eq(self.input, other.input) && self.start == other.start && self.end == other.end
    }
}

impl<'i> Eq for Span<'i> {}

impl<'i> Hash for Span<'i> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (self.input.as_bytes() as *const [u8]).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

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

    #[test]
    fn split() {
        let input = "a";
        let start = position::Position::from_start(input);
        let mut end = start.clone();

        assert!(end.skip(1));

        let span = start.clone().span(&end.clone());

        assert_eq!(span.split(), (start, end));
    }
}
<commit_msg>Update pest/src/span.rs<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
use std::str;

use position;

/// A span over a `&str`. It is created from either [two `Position`s] or from a [`Pair`].
///
/// [two `Position`s]: struct.Position.html#method.span
/// [`Pair`]: ../iterators/struct.Pair.html#method.span
#[derive(Clone)]
pub struct Span<'i> {
    input: &'i str,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    start: usize,
    /// # Safety
    ///
    /// Must be a valid character boundary index into `input`.
    end: usize
}

impl<'i> Span<'i> {
    /// Create a new `Span` without checking invariants. (Checked with `debug_assertions`.)
    ///
    /// # Safety
    ///
    /// `input[start..end]` must be a valid subslice; that is, said indexing should not panic.
    pub(crate) unsafe fn new_unchecked(input: &str, start: usize, end: usize) -> Span {
        debug_assert!(input.get(start..end).is_some());
        Span { input, start, end }
    }

    /// Attempts to create a new span. Will return None if `input[start..end]` is an invalid index
    /// into `input`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Span;
    /// let input = "Hello!";
    /// assert_eq!(None, Span::new(input, 100, 0));
    /// assert!(Span::new(input, 0, input.len()).is_some());
    /// ```
    pub fn new(input: &str, start: usize, end: usize) -> Option<Span> {
        if input.get(start..end).is_some() {
            Some(Span { input, start, end })
        } else {
            None
        }
    }

    /// Returns the `Span`'s start byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.start(), 0);
    /// ```
    #[inline]
    pub fn start(&self) -> usize {
        self.start
    }

    /// Returns the `Span`'s end byte position as a `usize`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end(), 0);
    /// ```
    #[inline]
    pub fn end(&self) -> usize {
        self.end
    }

    /// Returns the `Span`'s start `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.start_pos(), start);
    /// ```
    #[inline]
    pub fn start_pos(&self) -> position::Position<'i> {
        // Span's start position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.start) }
    }

    /// Returns the `Span`'s end `Position`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.span(&end);
    ///
    /// assert_eq!(span.end_pos(), end);
    /// ```
    #[inline]
    pub fn end_pos(&self) -> position::Position<'i> {
        // Span's end position is always a UTF-8 border.
        unsafe { position::Position::new_unchecked(self.input, self.end) }
    }

    /// Splits the `Span` into a pair of `Position`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::Position;
    /// let input = "ab";
    /// let start = Position::from_start(input);
    /// let end = start.clone();
    /// let span = start.clone().span(&end);
    ///
    /// assert_eq!(span.split(), (start, end));
    /// ```
    #[inline]
    pub fn split(self) -> (position::Position<'i>, position::Position<'i>) {
        // Span's start and end positions are always a UTF-8 borders.
        let pos1 = unsafe { position::Position::new_unchecked(self.input, self.start) };
        let pos2 = unsafe { position::Position::new_unchecked(self.input, self.end) };

        (pos1, pos2)
    }

    /// Captures a slice from the `&str` defined by the `Span`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest;
    /// # #[allow(non_camel_case_types)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// enum Rule {}
    ///
    /// let input = "abc";
    /// let mut state: Box<pest::ParserState<Rule>> = pest::ParserState::new(input).skip(1).unwrap();
    /// let start_pos = state.position().clone();
    /// state = state.match_string("b").unwrap();
    /// let span = start_pos.span(&state.position().clone());
    /// assert_eq!(span.as_str(), "b");
    /// ```
    #[inline]
    pub fn as_str(&self) -> &'i str {
        // Span's start and end positions are always a UTF-8 borders.
        &self.input[self.start..self.end]
    }
}

impl<'i> fmt::Debug for Span<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Span")
            .field("str", &self.as_str())
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

impl<'i> PartialEq for Span<'i> {
    fn eq(&self, other: &Span<'i>) -> bool {
        ptr::eq(self.input, other.input) && self.start == other.start && self.end == other.end
    }
}

impl<'i> Eq for Span<'i> {}

impl<'i> Hash for Span<'i> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (self.input as *const str).hash(state);
        self.start.hash(state);
        self.end.hash(state);
    }
}

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

    #[test]
    fn split() {
        let input = "a";
        let start = position::Position::from_start(input);
        let mut end = start.clone();

        assert!(end.skip(1));

        let span = start.clone().span(&end.clone());

        assert_eq!(span.split(), (start, end));
    }
}
<|endoftext|>


<commit_before>#[macro_use]
pub mod marks;

use std::{
    fs,
    path::{Path, PathBuf}
};

use text_unit::{TextRange, TextUnit};
use serde_json::Value;

pub use difference::Changeset as __Changeset;

pub const CURSOR_MARKER: &str = "<|>";

#[macro_export]
macro_rules! assert_eq_text {
    ($left:expr, $right:expr) => {
        assert_eq_text!($left, $right,)
    };
    ($left:expr, $right:expr, $($tt:tt)*) => {{
        let left = $left;
        let right = $right;
        if left != right {
            if left.trim() == right.trim() {
                eprintln!("Left:\n{:?}\n\nRight:\n{:?}\n\nWhitespace difference\n", left, right);
            } else {
                let changeset = $crate::__Changeset::new(right, left, "\n");
                eprintln!("Left:\n{}\n\nRight:\n{}\n\nDiff:\n{}\n", left, right, changeset);
            }
            eprintln!($($tt)*);
            panic!("text differs");
        }
    }};
}

pub fn extract_offset(text: &str) -> (TextUnit, String) {
    match try_extract_offset(text) {
        None => panic!("text should contain cursor marker"),
        Some(result) => result,
    }
}

pub fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> {
    let cursor_pos = text.find(CURSOR_MARKER)?;
    let mut new_text = String::with_capacity(text.len() - CURSOR_MARKER.len());
    new_text.push_str(&text[..cursor_pos]);
    new_text.push_str(&text[cursor_pos + CURSOR_MARKER.len()..]);
    let cursor_pos = TextUnit::from(cursor_pos as u32);
    Some((cursor_pos, new_text))
}

pub fn extract_range(text: &str) -> (TextRange, String) {
    match try_extract_range(text) {
        None => panic!("text should contain cursor marker"),
        Some(result) => result,
    }
}

pub fn try_extract_range(text: &str) -> Option<(TextRange, String)> {
    let (start, text) = try_extract_offset(text)?;
    let (end, text) = try_extract_offset(&text)?;
    Some((TextRange::from_to(start, end), text))
}

/// Extracts ranges, marked with `<tag> </tag>` paris from the `text`
pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
    let open = format!("<{}>", tag);
    let close = format!("</{}>", tag);
    let mut ranges = Vec::new();
    let mut res = String::new();
    let mut stack = Vec::new();
    loop {
        match text.find('<') {
            None => {
                res.push_str(text);
                break;
            }
            Some(i) => {
                res.push_str(&text[..i]);
                text = &text[i..];
                if text.starts_with(&open) {
                    text = &text[open.len()..];
                    let from = TextUnit::of_str(&res);
                    stack.push(from);
                } else if text.starts_with(&close) {
                    text = &text[close.len()..];
                    let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
                    let to = TextUnit::of_str(&res);
                    ranges.push(TextRange::from_to(from, to));
                }
            }
        }
    }
    assert!(stack.is_empty(), "unmatched <{}>", tag);
    ranges.sort_by_key(|r| (r.start(), r.end()));
    (ranges, res)
}

pub fn add_cursor(text: &str, offset: TextUnit) -> String {
    let offset: u32 = offset.into();
    let offset: usize = offset as usize;
    let mut res = String::new();
    res.push_str(&text[..offset]);
    res.push_str("<|>");
    res.push_str(&text[offset..]);
    res
}

#[derive(Debug)]
pub struct FixtureEntry {
    pub meta: String,
    pub text: String,
}

/// Parses text which looks like this:
///
///  ```not_rust
///  //- some meta
///  line 1
///  line 2
///  // - other meta
///  ```
pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
    let mut res = Vec::new();
    let mut buf = String::new();
    let mut meta: Option<&str> = None;

    macro_rules! flush {
        () => {
            if let Some(meta) = meta {
                res.push(FixtureEntry { meta: meta.to_string(), text: buf.clone() });
                buf.clear();
            }
        };
    };
    let margin = fixture
        .lines()
        .filter(|it| it.trim_start().starts_with("//-"))
        .map(|it| it.len() - it.trim_start().len())
        .next()
        .expect("empty fixture");
    let lines = fixture.lines().filter_map(|line| {
        if line.len() >= margin {
            assert!(line[..margin].trim().is_empty());
            Some(&line[margin..])
        } else {
            assert!(line.trim().is_empty());
            None
        }
    });

    for line in lines {
        if line.starts_with("//-") {
            flush!();
            buf.clear();
            meta = Some(line["//-".len()..].trim());
            continue;
        }
        buf.push_str(line);
        buf.push('\n');
    }
    flush!();
    res
}

// Comparison functionality borrowed from cargo:

/// Compare a line with an expected pattern.
/// - Use `[..]` as a wildcard to match 0 or more characters on the same line
///   (similar to `.*` in a regex).
pub fn lines_match(expected: &str, actual: &str) -> bool {
    // Let's not deal with / vs \ (windows...)
    // First replace backslash-escaped backslashes with forward slashes
    // which can occur in, for example, JSON output
    let expected = expected.replace("\\\\", "/").replace("\\", "/");
    let mut actual: &str = &actual.replace("\\\\", "/").replace("\\", "/");
    for (i, part) in expected.split("[..]").enumerate() {
        match actual.find(part) {
            Some(j) => {
                if i == 0 && j != 0 {
                    return false;
                }
                actual = &actual[j + part.len()..];
            }
            None => return false,
        }
    }
    actual.is_empty() || expected.ends_with("[..]")
}

#[test]
fn lines_match_works() {
    assert!(lines_match("a b", "a b"));
    assert!(lines_match("a[..]b", "a b"));
    assert!(lines_match("a[..]", "a b"));
    assert!(lines_match("[..]", "a b"));
    assert!(lines_match("[..]b", "a b"));

    assert!(!lines_match("[..]b", "c"));
    assert!(!lines_match("b", "c"));
    assert!(!lines_match("b", "cb"));
}

// Compares JSON object for approximate equality.
// You can use `[..]` wildcard in strings (useful for OS dependent things such
// as paths).  You can use a `"{...}"` string literal as a wildcard for
// arbitrary nested JSON (useful for parts of object emitted by other programs
// (e.g. rustc) rather than Cargo itself).  Arrays are sorted before comparison.
pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> {
    use serde_json::Value::*;
    match (expected, actual) {
        (&Number(ref l), &Number(ref r)) if l == r => None,
        (&Bool(l), &Bool(r)) if l == r => None,
        (&String(ref l), &String(ref r)) if lines_match(l, r) => None,
        (&Array(ref l), &Array(ref r)) => {
            if l.len() != r.len() {
                return Some((expected, actual));
            }

            let mut l = l.iter().collect::<Vec<_>>();
            let mut r = r.iter().collect::<Vec<_>>();

            l.retain(|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) {
                Some(i) => {
                    r.remove(i);
                    false
                }
                None => true,
            });

            if !l.is_empty() {
                assert!(!r.is_empty());
                Some((&l[0], &r[0]))
            } else {
                assert_eq!(r.len(), 0);
                None
            }
        }
        (&Object(ref l), &Object(ref r)) => {
            let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k));
            if !same_keys {
                return Some((expected, actual));
            }

            l.values().zip(r.values()).filter_map(|(l, r)| find_mismatch(l, r)).nth(0)
        }
        (&Null, &Null) => None,
        // magic string literal "{...}" acts as wildcard for any sub-JSON
        (&String(ref l), _) if l == "{...}" => None,
        _ => Some((expected, actual)),
    }
}

pub fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], f: F)
where
    F: Fn(&str, &Path) -> String,
{
    for (path, input_code) in collect_tests(test_data_dir, paths) {
        let parse_tree = f(&input_code, &path);
        let path = path.with_extension("txt");
        if !path.exists() {
            println!("\nfile: {}", path.display());
            println!("No .txt file with expected result, creating...\n");
            println!("{}\n{}", input_code, parse_tree);
            fs::write(&path, &parse_tree).unwrap();
            panic!("No expected result")
        }
        let expected = read_text(&path);
        let expected = expected.as_str();
        let parse_tree = parse_tree.as_str();
        assert_equal_text(expected, parse_tree, &path);
    }
}

pub fn collect_tests(test_data_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
    paths
        .iter()
        .flat_map(|path| {
            let path = test_data_dir.to_owned().join(path);
            test_from_dir(&path).into_iter()
        })
        .map(|path| {
            let text = read_text(&path);
            (path, text)
        })
        .collect()
}

fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
    let mut acc = Vec::new();
    for file in fs::read_dir(&dir).unwrap() {
        let file = file.unwrap();
        let path = file.path();
        if path.extension().unwrap_or_default() == "rs" {
            acc.push(path);
        }
    }
    acc.sort();
    acc
}

pub fn project_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
}

/// Read file and normalize newlines.
///
/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
///
/// ```
/// let s = "
/// ";
/// assert_eq!(s.as_bytes(), &[10]);
/// ```
///
/// so this should always be correct.
pub fn read_text(path: &Path) -> String {
    fs::read_to_string(path)
        .expect(&format!("File at {:?} should be valid", path))
        .replace("\r\n", "\n")
}

const REWRITE: bool = false;

fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
    if expected == actual {
        return;
    }
    let dir = project_dir();
    let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
    if expected.trim() == actual.trim() {
        println!("whitespace difference, rewriting");
        println!("file: {}\n", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    if REWRITE {
        println!("rewriting {}", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
}
<commit_msg>Fix clippy::expect_fun_call<commit_after>#[macro_use]
pub mod marks;

use std::{
    fs,
    path::{Path, PathBuf}
};

use text_unit::{TextRange, TextUnit};
use serde_json::Value;

pub use difference::Changeset as __Changeset;

pub const CURSOR_MARKER: &str = "<|>";

#[macro_export]
macro_rules! assert_eq_text {
    ($left:expr, $right:expr) => {
        assert_eq_text!($left, $right,)
    };
    ($left:expr, $right:expr, $($tt:tt)*) => {{
        let left = $left;
        let right = $right;
        if left != right {
            if left.trim() == right.trim() {
                eprintln!("Left:\n{:?}\n\nRight:\n{:?}\n\nWhitespace difference\n", left, right);
            } else {
                let changeset = $crate::__Changeset::new(right, left, "\n");
                eprintln!("Left:\n{}\n\nRight:\n{}\n\nDiff:\n{}\n", left, right, changeset);
            }
            eprintln!($($tt)*);
            panic!("text differs");
        }
    }};
}

pub fn extract_offset(text: &str) -> (TextUnit, String) {
    match try_extract_offset(text) {
        None => panic!("text should contain cursor marker"),
        Some(result) => result,
    }
}

pub fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> {
    let cursor_pos = text.find(CURSOR_MARKER)?;
    let mut new_text = String::with_capacity(text.len() - CURSOR_MARKER.len());
    new_text.push_str(&text[..cursor_pos]);
    new_text.push_str(&text[cursor_pos + CURSOR_MARKER.len()..]);
    let cursor_pos = TextUnit::from(cursor_pos as u32);
    Some((cursor_pos, new_text))
}

pub fn extract_range(text: &str) -> (TextRange, String) {
    match try_extract_range(text) {
        None => panic!("text should contain cursor marker"),
        Some(result) => result,
    }
}

pub fn try_extract_range(text: &str) -> Option<(TextRange, String)> {
    let (start, text) = try_extract_offset(text)?;
    let (end, text) = try_extract_offset(&text)?;
    Some((TextRange::from_to(start, end), text))
}

/// Extracts ranges, marked with `<tag> </tag>` paris from the `text`
pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
    let open = format!("<{}>", tag);
    let close = format!("</{}>", tag);
    let mut ranges = Vec::new();
    let mut res = String::new();
    let mut stack = Vec::new();
    loop {
        match text.find('<') {
            None => {
                res.push_str(text);
                break;
            }
            Some(i) => {
                res.push_str(&text[..i]);
                text = &text[i..];
                if text.starts_with(&open) {
                    text = &text[open.len()..];
                    let from = TextUnit::of_str(&res);
                    stack.push(from);
                } else if text.starts_with(&close) {
                    text = &text[close.len()..];
                    let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
                    let to = TextUnit::of_str(&res);
                    ranges.push(TextRange::from_to(from, to));
                }
            }
        }
    }
    assert!(stack.is_empty(), "unmatched <{}>", tag);
    ranges.sort_by_key(|r| (r.start(), r.end()));
    (ranges, res)
}

pub fn add_cursor(text: &str, offset: TextUnit) -> String {
    let offset: u32 = offset.into();
    let offset: usize = offset as usize;
    let mut res = String::new();
    res.push_str(&text[..offset]);
    res.push_str("<|>");
    res.push_str(&text[offset..]);
    res
}

#[derive(Debug)]
pub struct FixtureEntry {
    pub meta: String,
    pub text: String,
}

/// Parses text which looks like this:
///
///  ```not_rust
///  //- some meta
///  line 1
///  line 2
///  // - other meta
///  ```
pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
    let mut res = Vec::new();
    let mut buf = String::new();
    let mut meta: Option<&str> = None;

    macro_rules! flush {
        () => {
            if let Some(meta) = meta {
                res.push(FixtureEntry { meta: meta.to_string(), text: buf.clone() });
                buf.clear();
            }
        };
    };
    let margin = fixture
        .lines()
        .filter(|it| it.trim_start().starts_with("//-"))
        .map(|it| it.len() - it.trim_start().len())
        .next()
        .expect("empty fixture");
    let lines = fixture.lines().filter_map(|line| {
        if line.len() >= margin {
            assert!(line[..margin].trim().is_empty());
            Some(&line[margin..])
        } else {
            assert!(line.trim().is_empty());
            None
        }
    });

    for line in lines {
        if line.starts_with("//-") {
            flush!();
            buf.clear();
            meta = Some(line["//-".len()..].trim());
            continue;
        }
        buf.push_str(line);
        buf.push('\n');
    }
    flush!();
    res
}

// Comparison functionality borrowed from cargo:

/// Compare a line with an expected pattern.
/// - Use `[..]` as a wildcard to match 0 or more characters on the same line
///   (similar to `.*` in a regex).
pub fn lines_match(expected: &str, actual: &str) -> bool {
    // Let's not deal with / vs \ (windows...)
    // First replace backslash-escaped backslashes with forward slashes
    // which can occur in, for example, JSON output
    let expected = expected.replace("\\\\", "/").replace("\\", "/");
    let mut actual: &str = &actual.replace("\\\\", "/").replace("\\", "/");
    for (i, part) in expected.split("[..]").enumerate() {
        match actual.find(part) {
            Some(j) => {
                if i == 0 && j != 0 {
                    return false;
                }
                actual = &actual[j + part.len()..];
            }
            None => return false,
        }
    }
    actual.is_empty() || expected.ends_with("[..]")
}

#[test]
fn lines_match_works() {
    assert!(lines_match("a b", "a b"));
    assert!(lines_match("a[..]b", "a b"));
    assert!(lines_match("a[..]", "a b"));
    assert!(lines_match("[..]", "a b"));
    assert!(lines_match("[..]b", "a b"));

    assert!(!lines_match("[..]b", "c"));
    assert!(!lines_match("b", "c"));
    assert!(!lines_match("b", "cb"));
}

// Compares JSON object for approximate equality.
// You can use `[..]` wildcard in strings (useful for OS dependent things such
// as paths).  You can use a `"{...}"` string literal as a wildcard for
// arbitrary nested JSON (useful for parts of object emitted by other programs
// (e.g. rustc) rather than Cargo itself).  Arrays are sorted before comparison.
pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> {
    use serde_json::Value::*;
    match (expected, actual) {
        (&Number(ref l), &Number(ref r)) if l == r => None,
        (&Bool(l), &Bool(r)) if l == r => None,
        (&String(ref l), &String(ref r)) if lines_match(l, r) => None,
        (&Array(ref l), &Array(ref r)) => {
            if l.len() != r.len() {
                return Some((expected, actual));
            }

            let mut l = l.iter().collect::<Vec<_>>();
            let mut r = r.iter().collect::<Vec<_>>();

            l.retain(|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) {
                Some(i) => {
                    r.remove(i);
                    false
                }
                None => true,
            });

            if !l.is_empty() {
                assert!(!r.is_empty());
                Some((&l[0], &r[0]))
            } else {
                assert_eq!(r.len(), 0);
                None
            }
        }
        (&Object(ref l), &Object(ref r)) => {
            let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k));
            if !same_keys {
                return Some((expected, actual));
            }

            l.values().zip(r.values()).filter_map(|(l, r)| find_mismatch(l, r)).nth(0)
        }
        (&Null, &Null) => None,
        // magic string literal "{...}" acts as wildcard for any sub-JSON
        (&String(ref l), _) if l == "{...}" => None,
        _ => Some((expected, actual)),
    }
}

pub fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], f: F)
where
    F: Fn(&str, &Path) -> String,
{
    for (path, input_code) in collect_tests(test_data_dir, paths) {
        let parse_tree = f(&input_code, &path);
        let path = path.with_extension("txt");
        if !path.exists() {
            println!("\nfile: {}", path.display());
            println!("No .txt file with expected result, creating...\n");
            println!("{}\n{}", input_code, parse_tree);
            fs::write(&path, &parse_tree).unwrap();
            panic!("No expected result")
        }
        let expected = read_text(&path);
        let expected = expected.as_str();
        let parse_tree = parse_tree.as_str();
        assert_equal_text(expected, parse_tree, &path);
    }
}

pub fn collect_tests(test_data_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
    paths
        .iter()
        .flat_map(|path| {
            let path = test_data_dir.to_owned().join(path);
            test_from_dir(&path).into_iter()
        })
        .map(|path| {
            let text = read_text(&path);
            (path, text)
        })
        .collect()
}

fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
    let mut acc = Vec::new();
    for file in fs::read_dir(&dir).unwrap() {
        let file = file.unwrap();
        let path = file.path();
        if path.extension().unwrap_or_default() == "rs" {
            acc.push(path);
        }
    }
    acc.sort();
    acc
}

pub fn project_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
}

/// Read file and normalize newlines.
///
/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
///
/// ```
/// let s = "
/// ";
/// assert_eq!(s.as_bytes(), &[10]);
/// ```
///
/// so this should always be correct.
pub fn read_text(path: &Path) -> String {
    fs::read_to_string(path)
        .unwrap_or_else(|_| panic!("File at {:?} should be valid", path))
        .replace("\r\n", "\n")
}

const REWRITE: bool = false;

fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
    if expected == actual {
        return;
    }
    let dir = project_dir();
    let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
    if expected.trim() == actual.trim() {
        println!("whitespace difference, rewriting");
        println!("file: {}\n", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    if REWRITE {
        println!("rewriting {}", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
}
<|endoftext|>