<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::io;

use byteorder::{BigEndian, WriteBytesExt};

use mio;

use EventLoop;
use Message;
use protocol::Protocol as Protocol;
use transport::Connection as Connection;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum State {
	Handshake,
	Connected
}

// A pipe is responsible for handshaking with its peer and transfering messages over a connection.
// That means send/receive size prefix and then message payload
// according to the connection readiness and the operation progress
pub struct Pipe {
	addr: String,
	state: State,
	handshake_state: HandshakePipeState,
	connected_state: ConnectedPipeState
}

pub enum SendStatus {
	Postponed(Rc<Message>), // Message can't be sent at the moment : Handshake in progress or would block
    Completed,              // Message has been successfully sent
    InProgress              // Message has been partially sent, will finish later
}

impl Pipe {

	pub fn new(id: usize, addr: String, protocol: &Protocol, connection: Box<Connection>) -> Pipe {
		let conn_ref = Rc::new(RefCell::new(connection));

		// TODO : maybe the connection could be stored inside the Pipe
		// and then passed as &mut to the state methods ?

		Pipe {
			addr: addr,
			state: State::Handshake,
			handshake_state: HandshakePipeState::new(id, protocol, conn_ref.clone()),
			connected_state: ConnectedPipeState::new(id, conn_ref.clone())
		}
	}

	pub fn send(&mut self, event_loop: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus> {
		self.get_state().send(event_loop, msg)
	}

	pub fn addr(self) -> String {
		self.addr
	}

	fn get_state<'a>(&'a mut self) -> &'a mut PipeState {
		match self.state {
			State::Handshake => &mut self.handshake_state,
			State::Connected => &mut self.connected_state
		}
	}

	fn set_state(&mut self, state: State, event_loop: &mut EventLoop) -> io::Result<()> {
		self.state = state;
		self.get_state().enter(event_loop)
	}

	pub fn init(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		self.set_state(State::Handshake, event_loop)
	}

	pub fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<()> {
		if events.is_hup() {
			return Err(io::Error::new(io::ErrorKind::ConnectionReset, "event: hup"));
		}

		if events.is_error() {
			return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "event: error"));
		}

		if let Some(new_state) = try!(self.get_state().ready(event_loop, events)) {
			return self.set_state(new_state, event_loop);
		}

		Ok(())
	}

}

trait PipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()>;
	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>>;

	fn send(&mut self, event_loop: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus>;
}

struct HandshakePipeState {
	id: usize,
	protocol_id: u16,
	protocol_peer_id: u16,
	connection: Rc<RefCell<Box<Connection>>>,
	sent: bool,
	received: bool
}

impl HandshakePipeState {

	fn new(id: usize, protocol: &Protocol, connection: Rc<RefCell<Box<Connection>>>) -> HandshakePipeState {
		HandshakePipeState {
			id: id,
			protocol_id: protocol.id(),
			protocol_peer_id: protocol.peer_id(),
			connection: connection,
			sent: false,
			received: false }
	}

	fn check_received_handshake(&self, handshake: &[u8; 8]) -> io::Result<()> {
		let mut expected_handshake = vec!(0, 83, 80, 0);
		try!(expected_handshake.write_u16::<BigEndian>(self.protocol_peer_id));
		try!(expected_handshake.write_u16::<BigEndian>(0));
		let mut both = handshake.iter().zip(expected_handshake.iter());

		if both.all(|(l,r)| l == r) {
			Ok(())
		} else {
			Err(io::Error::new(io::ErrorKind::InvalidData, "received bad handshake"))
		}
	}

	fn check_sent_handshake(&self, written: Option<usize>) -> io::Result<()> {
		match written {
			Some(8) => Ok(()),
			Some(_) => Err(io::Error::new(io::ErrorKind::WouldBlock, "failed to send full handshake")),
			_       => Err(io::Error::new(io::ErrorKind::WouldBlock, "failed to send handshake"))
		}
	}

	fn read_handshake(&mut self) -> io::Result<()> {
		let mut handshake = [0u8; 8];
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_read(&mut handshake).
			and_then(|_| self.check_received_handshake(&handshake)));
		debug!("[{}] handshake received.", self.id);
		self.received = true;
		Ok(())
	}

	fn write_handshake(&mut self) -> io::Result<()> {
		// handshake is Zero, 'S', 'P', Version, Proto, Rsvd
		let mut handshake = vec!(0, 83, 80, 0);
		try!(handshake.write_u16::<BigEndian>(self.protocol_id));
		try!(handshake.write_u16::<BigEndian>(0));
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_write(&handshake).
			and_then(|w| self.check_sent_handshake(w)));
		debug!("[{}] handshake sent.", self.id);
		self.sent = true;
		Ok(())
	}

	fn register(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.register_opt(fd, token, interest, poll_opt)
	}

	fn reregister(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.reregister(fd, token, interest, poll_opt)
	}

}

impl PipeState for HandshakePipeState {

	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter handshake state", self.id);
		self.sent = false;
		self.received = false;

		let interest = mio::EventSet::readable() | mio::EventSet::writable() | mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		try!(self.register(event_loop, interest, poll_opt));

		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		if !self.received && events.is_readable() {
			try!(self.read_handshake());
		}

		if !self.sent && events.is_writable() {
			try!(self.write_handshake());
		}

		if self.received && self.sent {
			return Ok(Some(State::Connected));
		}

		let mut interest = mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		if !self.received {
			interest = interest | mio::EventSet::readable();
		}
		if !self.sent {
			interest = interest | mio::EventSet::writable();
		}

		try!(self.reregister(event_loop, interest, poll_opt));

		Ok(None)
	}

	fn send(&mut self, _: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus> {
		Ok(SendStatus::Postponed(msg))
	}
}

struct ConnectedPipeState {
	id: usize,
	connection: Rc<RefCell<Box<Connection>>>,
	pending_send: Option<Rc<Message>>,
	pending_step: u8, // 1=prefix, 2=header, 3=body
	pending_progress: usize  // bytes written
	// TODO move these fields inside a SendOperation struct
	// and change pending_send: Option<SendOperation>
}

impl ConnectedPipeState {

	fn new(id: usize, connection: Rc<RefCell<Box<Connection>>>) -> ConnectedPipeState {
		ConnectedPipeState {
			id: id,
			connection: connection,
			pending_send: None,
			pending_step: 0,
			pending_progress: 0
		}
	}

}

impl PipeState for ConnectedPipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter connected state", self.id);
		let token = mio::Token(self.id);
		let connection = self.connection.borrow_mut();
		let fd = connection.as_evented();
		let interest = mio::EventSet::all();
		let poll_opt = mio::PollOpt::edge();
		try!(event_loop.reregister(fd, token, interest, poll_opt));
		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		// TODO : check if there is message pending to be sent
		Ok(None)
	}

	fn send(&mut self, event_loop: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus> {
		let mut connection = self.connection.borrow_mut();
		let mut prefix = Vec::with_capacity(8);
		try!(prefix.write_u64::<BigEndian>(msg.len() as u64));

		// try send prefix
		match try!(connection.try_write(&prefix)) {
			Some(8) => {
			}, //all good
			Some(x) => {
				self.pending_send = Some(msg);
				self.pending_step = 1;
				self.pending_progress = x;
				return Ok(SendStatus::InProgress);
			},
			None => {
				return Ok(SendStatus::Postponed(msg));
			}
		}

		// try send msg header
		match try!(connection.try_write(msg.get_header())) {
			Some(x) => {
				if x < msg.get_header().len() {
					self.pending_send = Some(msg);
					self.pending_step = 2;
					self.pending_progress = x;
					return Ok(SendStatus::InProgress);
				}
			},
			None => {
				self.pending_send = Some(msg);
				self.pending_step = 2;
				self.pending_progress = 0;
				return Ok(SendStatus::InProgress);
			}
		}

		// try send msg body
		match try!(connection.try_write(msg.get_body())) {
			Some(x) => {
				if x == msg.get_body().len() {
					return Ok(SendStatus::Completed);
				} else {
					self.pending_send = Some(msg);
					self.pending_step = 3;
					self.pending_progress = x;
					return Ok(SendStatus::InProgress);
				}
			},
			None => {
				self.pending_send = Some(msg);
				self.pending_step = 3;
				self.pending_progress = 0;
				return Ok(SendStatus::InProgress);
			}
		}

		// TODO : when something is pending, should reregister to writable ...
	}
}
<commit_msg>Adds a few TODO comments ...<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::io;

use byteorder::{BigEndian, WriteBytesExt};

use mio;

use EventLoop;
use Message;
use protocol::Protocol as Protocol;
use transport::Connection as Connection;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum State {
	Handshake,
	Connected
}

// A pipe is responsible for handshaking with its peer and transfering messages over a connection.
// That means send/receive size prefix and then message payload
// according to the connection readiness and the operation progress
pub struct Pipe {
	addr: String,
	state: State,
	handshake_state: HandshakePipeState,
	connected_state: ConnectedPipeState
}

pub enum SendStatus {
	Postponed(Rc<Message>), // Message can't be sent at the moment : Handshake in progress or would block
    Completed,              // Message has been successfully sent
    InProgress              // Message has been partially sent, will finish later
}

impl Pipe {

	pub fn new(id: usize, addr: String, protocol: &Protocol, connection: Box<Connection>) -> Pipe {
		let conn_ref = Rc::new(RefCell::new(connection));

		// TODO : maybe the connection could be stored inside the Pipe
		// and then passed as &mut to the state methods ?

		Pipe {
			addr: addr,
			state: State::Handshake,
			handshake_state: HandshakePipeState::new(id, protocol, conn_ref.clone()),
			connected_state: ConnectedPipeState::new(id, conn_ref.clone())
		}
	}

	pub fn send(&mut self, event_loop: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus> {
		self.get_state().send(event_loop, msg)
	}

	pub fn addr(self) -> String {
		self.addr
	}

	fn get_state<'a>(&'a mut self) -> &'a mut PipeState {
		match self.state {
			State::Handshake => &mut self.handshake_state,
			State::Connected => &mut self.connected_state
		}
	}

	fn set_state(&mut self, state: State, event_loop: &mut EventLoop) -> io::Result<()> {
		self.state = state;
		self.get_state().enter(event_loop)
	}

	pub fn init(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		self.set_state(State::Handshake, event_loop)
	}

	pub fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<()> {
		if events.is_hup() {
			return Err(io::Error::new(io::ErrorKind::ConnectionReset, "event: hup"));
		}

		if events.is_error() {
			return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "event: error"));
		}

		if let Some(new_state) = try!(self.get_state().ready(event_loop, events)) {
			return self.set_state(new_state, event_loop);
		}

		Ok(())
	}

}

trait PipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()>;
	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>>;

	fn send(&mut self, event_loop: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus>;
}

struct HandshakePipeState {
	id: usize,
	protocol_id: u16,
	protocol_peer_id: u16,
	connection: Rc<RefCell<Box<Connection>>>,
	sent: bool,
	received: bool
}

impl HandshakePipeState {

	fn new(id: usize, protocol: &Protocol, connection: Rc<RefCell<Box<Connection>>>) -> HandshakePipeState {
		HandshakePipeState {
			id: id,
			protocol_id: protocol.id(),
			protocol_peer_id: protocol.peer_id(),
			connection: connection,
			sent: false,
			received: false }
	}

	fn check_received_handshake(&self, handshake: &[u8; 8]) -> io::Result<()> {
		let mut expected_handshake = vec!(0, 83, 80, 0);
		try!(expected_handshake.write_u16::<BigEndian>(self.protocol_peer_id));
		try!(expected_handshake.write_u16::<BigEndian>(0));
		let mut both = handshake.iter().zip(expected_handshake.iter());

		if both.all(|(l,r)| l == r) {
			Ok(())
		} else {
			Err(io::Error::new(io::ErrorKind::InvalidData, "received bad handshake"))
		}
	}

	fn check_sent_handshake(&self, written: Option<usize>) -> io::Result<()> {
		match written {
			Some(8) => Ok(()),
			Some(_) => Err(io::Error::new(io::ErrorKind::WouldBlock, "failed to send full handshake")),
			_       => Err(io::Error::new(io::ErrorKind::WouldBlock, "failed to send handshake"))
		}
	}

	fn read_handshake(&mut self) -> io::Result<()> {
		let mut handshake = [0u8; 8];
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_read(&mut handshake).
			and_then(|_| self.check_received_handshake(&handshake)));
		debug!("[{}] handshake received.", self.id);
		self.received = true;
		Ok(())
	}

	fn write_handshake(&mut self) -> io::Result<()> {
		// handshake is Zero, 'S', 'P', Version, Proto, Rsvd
		let mut handshake = vec!(0, 83, 80, 0);
		try!(handshake.write_u16::<BigEndian>(self.protocol_id));
		try!(handshake.write_u16::<BigEndian>(0));
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_write(&handshake).
			and_then(|w| self.check_sent_handshake(w)));
		debug!("[{}] handshake sent.", self.id);
		self.sent = true;
		Ok(())
	}

	fn register(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.register_opt(fd, token, interest, poll_opt)
	}

	fn reregister(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.reregister(fd, token, interest, poll_opt)
	}

}

impl PipeState for HandshakePipeState {

	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter handshake state", self.id);
		self.sent = false;
		self.received = false;

		let interest = mio::EventSet::readable() | mio::EventSet::writable() | mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		try!(self.register(event_loop, interest, poll_opt));

		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		if !self.received && events.is_readable() {
			try!(self.read_handshake());
		}

		if !self.sent && events.is_writable() {
			try!(self.write_handshake());
		}

		if self.received && self.sent {
			return Ok(Some(State::Connected));
		}

		let mut interest = mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		if !self.received {
			interest = interest | mio::EventSet::readable();
		}
		if !self.sent {
			interest = interest | mio::EventSet::writable();
		}

		try!(self.reregister(event_loop, interest, poll_opt));

		Ok(None)
	}

	fn send(&mut self, _: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus> {
		Ok(SendStatus::Postponed(msg))
	}
}

struct ConnectedPipeState {
	id: usize,
	connection: Rc<RefCell<Box<Connection>>>,
	pending_send: Option<Rc<Message>>,
	pending_step: u8,        // 1=prefix, 2=header, 3=body
	pending_progress: usize  // bytes written
	// TODO move these fields inside a SendOperation struct
	// and change pending_send: Option<SendOperation>
}

impl ConnectedPipeState {

	fn new(id: usize, connection: Rc<RefCell<Box<Connection>>>) -> ConnectedPipeState {
		ConnectedPipeState {
			id: id,
			connection: connection,
			pending_send: None,
			pending_step: 0,
			pending_progress: 0
		}
	}

}

impl PipeState for ConnectedPipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter connected state", self.id);
		let token = mio::Token(self.id);
		let connection = self.connection.borrow_mut();
		let fd = connection.as_evented();
		let interest = mio::EventSet::all();
		let poll_opt = mio::PollOpt::edge();
		try!(event_loop.reregister(fd, token, interest, poll_opt));
		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		// TODO : check if there is a message pending to be sent
		Ok(None)
	}

	fn send(&mut self, event_loop: &mut EventLoop, msg: Rc<Message>) -> io::Result<SendStatus> {
		// TODO just create a SendOperation and let it work from the begining ?
		let mut connection = self.connection.borrow_mut();
		let mut prefix = Vec::with_capacity(8);
		try!(prefix.write_u64::<BigEndian>(msg.len() as u64));

		// try send prefix
		match try!(connection.try_write(&prefix)) {
			Some(x) => if x < 8 {
				self.pending_send = Some(msg);
				self.pending_step = 1;
				self.pending_progress = x;
				return Ok(SendStatus::InProgress);
			},
			None => {
				return Ok(SendStatus::Postponed(msg));
			}
		}

		// try send msg header
		match try!(connection.try_write(msg.get_header())) {
			Some(x) => if x < msg.get_header().len() {
				self.pending_send = Some(msg);
				self.pending_step = 2;
				self.pending_progress = x;
				return Ok(SendStatus::InProgress);
			},
			None => {
				self.pending_send = Some(msg);
				self.pending_step = 2;
				self.pending_progress = 0;
				return Ok(SendStatus::InProgress);
			}
		}

		// try send msg body
		match try!(connection.try_write(msg.get_body())) {
			Some(x) => if x < msg.get_body().len() {
				self.pending_send = Some(msg);
				self.pending_step = 3;
				self.pending_progress = x;
				return Ok(SendStatus::InProgress);
			},
			None => {
				self.pending_send = Some(msg);
				self.pending_step = 3;
				self.pending_progress = 0;
				return Ok(SendStatus::InProgress);
			}
		}

		// TODO : when something is pending, should reregister, to writable at least ...
		Ok(SendStatus::Completed)
	}
}
<|endoftext|>


<commit_before>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::collections::RingBuf;

/// A polygon with 4 points. Maps to `GL_QUADS`
#[derive(Clone, Show, PartialEq, Eq, Copy)]
pub struct Quad<T> {
    /// the first point of a quad
    pub x: T,
    /// the second point of a quad
    pub y: T,
    /// the third point of a quad
    pub z: T,
    /// the fourth point of a quad
    pub w: T,
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[derive(Clone, Show, PartialEq, Eq, Copy)]
pub struct Triangle<T> {
    /// the first point of a triangle
    pub x: T,
    /// the second point of a triangle
    pub y: T,
    /// the third point of a triangle
    pub z: T,
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[derive(Show, Clone, PartialEq, Copy)]
pub enum Polygon<T> {
    /// A wraped triangle
    PolyTri(Triangle<T>),
    /// A wraped quad
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T);
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Triangle{x, y, z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Quad{x, y, z, w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices<F>(self, emit: F) where F: FnMut(T) {
        use self::Polygon::{ PolyQuad, PolyTri };

        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<Item=P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: RingBuf::new()
        }
    }
}

/// an iterator that breaks a polygon down into its individual
/// verticies.
pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: RingBuf<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<Item=U>> Iterator for VerticesIterator<SRC, V> {
    type Item = V;

    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}

/// equivalent of `map` but per-vertex
pub trait MapVertex<T, U, P> {
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex<F>(self, mut map: F) -> P where F: FnMut(T) -> U;
}

impl<T: Clone, U> MapVertex<T, U, Triangle<U>> for Triangle<T> {
    fn map_vertex<F>(self, mut map: F) -> Triangle<U> where F: FnMut(T) -> U {
        let Triangle{x, y, z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U, Quad<U>> for Quad<T> {
    fn map_vertex<F>(self, mut map: F) -> Quad<U> where F: FnMut(T) -> U {
        let Quad{x, y, z, w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U, Polygon<U>> for Polygon<T> {
    fn map_vertex<F>(self, map: F) -> Polygon<U> where F: FnMut(T) -> U {
        use self::Polygon::{ PolyTri, PolyQuad };

        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U> {
    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<F>(self, map: F) -> MapToVerticesIter<Self, T, U, F>
        where F: FnMut(T) -> U;
}

impl<VIn, VOut,
    P, POut: MapVertex<VIn, VOut, P>,
    T: Iterator<Item=POut>>
    MapToVertices<VIn, VOut> for T {
    fn vertex<F>(self, map: F) -> MapToVerticesIter<T, VIn, VOut, F>
            where F: FnMut(VIn) -> VOut {

        MapToVerticesIter {
            src: self,
            f: map
        }
    }
}

struct MapToVerticesIter<SRC, T, U, F: FnMut(T) -> U> {
    src: SRC,
    f: F
}

impl<'a, POut: MapVertex<T, U, P>,
         SRC: Iterator<Item=POut>,
         T, U, P, F: FnMut(T) -> U> Iterator for MapToVerticesIter<SRC, T, U, F> {
    type Item = P;

    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}
<commit_msg>Move to associated types<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::collections::RingBuf;

/// A polygon with 4 points. Maps to `GL_QUADS`
#[derive(Clone, Show, PartialEq, Eq, Copy)]
pub struct Quad<T> {
    /// the first point of a quad
    pub x: T,
    /// the second point of a quad
    pub y: T,
    /// the third point of a quad
    pub z: T,
    /// the fourth point of a quad
    pub w: T,
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[derive(Clone, Show, PartialEq, Eq, Copy)]
pub struct Triangle<T> {
    /// the first point of a triangle
    pub x: T,
    /// the second point of a triangle
    pub y: T,
    /// the third point of a triangle
    pub z: T,
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[derive(Show, Clone, PartialEq, Copy)]
pub enum Polygon<T> {
    /// A wraped triangle
    PolyTri(Triangle<T>),
    /// A wraped quad
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T);
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Triangle{x, y, z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices<F>(self, mut emit: F) where F: FnMut(T) {
        let Quad{x, y, z, w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices<F>(self, emit: F) where F: FnMut(T) {
        use self::Polygon::{ PolyQuad, PolyTri };

        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<Item=P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: RingBuf::new()
        }
    }
}

/// an iterator that breaks a polygon down into its individual
/// verticies.
pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: RingBuf<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<Item=U>> Iterator for VerticesIterator<SRC, V> {
    type Item = V;

    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push_back(v)),
                None => return None
            }
        }
    }
}

/// equivalent of `map` but per-vertex
pub trait MapVertex<T, U> {
    type Output;
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex<F>(self, mut map: F) -> Self::Output where F: FnMut(T) -> U;
}

impl<T: Clone, U> MapVertex<T, U> for Triangle<T> {
    type Output = Triangle<U>;

    fn map_vertex<F>(self, mut map: F) -> Triangle<U> where F: FnMut(T) -> U {
        let Triangle{x, y, z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Quad<T> {
    type Output = Quad<U>;

    fn map_vertex<F>(self, mut map: F) -> Quad<U> where F: FnMut(T) -> U {
        let Quad{x, y, z, w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U> for Polygon<T> {
    type Output = Polygon<U>;

    fn map_vertex<F>(self, map: F) -> Polygon<U> where F: FnMut(T) -> U {
        use self::Polygon::{ PolyTri, PolyQuad };

        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U> {
    type Output;

    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<F>(self, map: F) -> MapToVerticesIter<Self, T, U, F>
        where F: FnMut(T) -> U;
}

impl<VIn, VOut,
    P, POut: MapVertex<VIn, VOut, Output=P>,
    T: Iterator<Item=POut>>
    MapToVertices<VIn, VOut> for T {
    type Output = P;

    fn vertex<F>(self, map: F) -> MapToVerticesIter<T, VIn, VOut, F>
            where F: FnMut(VIn) -> VOut {

        MapToVerticesIter {
            src: self,
            f: map
        }
    }
}

struct MapToVerticesIter<SRC, T, U, F: FnMut(T) -> U> {
    src: SRC,
    f: F
}

impl<'a, P,
         POut: MapVertex<T, U, Output=P>,
         SRC: Iterator<Item=POut>,
         T, U, F: FnMut(T) -> U> Iterator for MapToVerticesIter<SRC, T, U, F> {
    type Item = P;

    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}
<|endoftext|>


<commit_before>#![ allow (unused_parens) ]

use std::collections::HashSet;
use std::fs;
use std::fs::DirEntry;
use std::io;
use std::os::unix::fs::MetadataExt;
use std::rc::Rc;

use output::Output;

use arguments::*;
use misc::*;
use storage::*;
use types::*;

pub fn scan_directories (
	arguments: & Arguments,
	output: & mut Output,
	previous_database: FileDatabase,
) -> Result <FileDatabase, String> {

	let root_paths: HashSet <PathRef> =
		arguments.root_paths.iter ().map (
			|root_path|

			root_path.clone ()

		).collect ();

	let previous_database_iterator =
		previous_database.into_iter ();

	let previous_database_iterator =
		previous_database_iterator.peekable ();

	let new_database: FileDatabase =
		FileDatabase::new ();

	let directory_scanner =
		DirectoryScanner {

		arguments: arguments,
		output: output,

		in_iterator: previous_database_iterator,
		out_database: new_database,

		root_paths_unordered: root_paths,
		root_paths_scanned: HashSet::new (),

		progress: 0,

	};

	directory_scanner.scan_directories ()

}

struct DirectoryScanner <'a> {

	arguments: & 'a Arguments,
	output: & 'a mut Output,

	in_iterator: FileDatabaseIntoIterator,
	out_database: FileDatabase,

	root_paths_unordered: HashSet <PathRef>,
	root_paths_scanned: HashSet <PathRef>,

	progress: u64,

}

impl <'a> DirectoryScanner <'a> {

	pub fn scan_directories (
		mut self,
	) -> Result <FileDatabase, String> {

		for root_path in & self.arguments.root_paths {

			if self.root_paths_scanned.contains (root_path) {
				continue;
			}

			self.output.message (
				& format! (
					"Scanning {}",
					root_path.to_string_lossy ()));

			let root_path =
				self.out_database.get_path (
					root_path.clone ());

			let metadata =
				try! (

				fs::symlink_metadata (
					root_path.as_ref (),
				).map_err (
					|error|

					format! (
						"Error reading metadata for: {}: {}",
						root_path.to_string_lossy (),
						error)

				)

			);

			loop {

				{

					let existing_file_data_option =
						self.in_iterator.peek ();

					if existing_file_data_option.is_none () {
						break;
					}

					let existing_file_data =
						existing_file_data_option.unwrap ();

					let existing_file_path =
						& existing_file_data.path;

					if * existing_file_path >= root_path {
						break;
					}

				}

				self.out_database.insert_direct (
					self.in_iterator.next ().unwrap ());

			}

			try! (
				self.scan_directory_internal (
					root_path.clone (),
					root_path.clone (),
					metadata.dev ()));

		}

		for existing_file_data_ref
		in self.in_iterator {

			self.out_database.insert_direct (
				existing_file_data_ref.clone ());

		}

		self.output.clear_status ();

		self.output.message (
			& format! (
				"Scanned {} files",
				self.progress));

		self.output.message (
			& format! (
				"Total {} files in database",
				self.out_database.len ()));

		Ok (self.out_database)

	}

	fn scan_directory_internal (
		& mut self,
		directory: PathRef,
		root_path: PathRef,
		device_id: u64,
	) -> Result <(), String> {

		if (
			self.root_paths_unordered.contains (
				& directory)
		) {
			self.root_paths_scanned.insert (
				directory.clone ());
		}

		let directory =
			directory.as_ref ();

		let entry_results: Vec <io::Result <DirEntry>> =
			try! (

			io_result (
				fs::read_dir (
					directory),
			).map_err (
				|error|

				format! (
					"Error reading directory: {}: {}",
					directory.to_string_lossy (),
					error)

			)

		).collect ();

		let mut entries: Vec <DirEntry> =
			Vec::new ();

		for entry_result in entry_results.into_iter () {

			entries.push (
				try! (

				io_result (
					entry_result,
				).map_err (
					|error|

					format! (
						"Error reading entry: {}",
						error)

				)

			));

		}

		entries.sort_by_key (
			|entry|

			entry.file_name ()

		);

		let mut entry_iterator =
			entries.into_iter ().peekable ();

		loop {

			{

				let entry_next =
					entry_iterator.peek ();

				if entry_next.is_none () {
					break;
				}

			}

			let entry =
				entry_iterator.next ().unwrap ();

			let entry_path =
				Rc::new (
					entry.path ());

			loop {

				let exists = {

					let in_next_option =
						self.in_iterator.peek ();

					if in_next_option.is_none () {
						break;
					}

					let in_next =
						in_next_option.unwrap ();

					let in_next_path =
						in_next.path.clone ();

					if in_next_path >= entry_path {
						break;
					}

					in_next_path.exists ()

				};

				if exists {

					self.out_database.insert_direct (
						self.in_iterator.next ().unwrap ());

				} else {

					self.in_iterator.next ();

				}

			}

			let metadata =
				try! (

				fs::symlink_metadata (
					entry.path (),
				).map_err (
					|error|

					format! (
						"Error reading metadata for: {}: {}",
						entry.path ().to_string_lossy (),
						error)

				)

			);

			let file_type =
				metadata.file_type ();

			if (

				file_type.is_symlink ()

				|| metadata.dev () != device_id

			) {

				// ignore

			} else if file_type.is_dir () {

				try! (
					self.scan_directory_internal (
						entry_path,
						root_path.clone (),
						device_id));

			} else if file_type.is_file () {

				let exists = {

					let in_next_option =
						self.in_iterator.peek ();

					if in_next_option.is_some () {

						let in_next =
							in_next_option.unwrap ();

						let in_next_path =
							in_next.path.clone ();

						in_next_path == entry_path

					} else {

						false

					}

				};

				if exists {

					let existing_file_data =
						self.in_iterator.next ().unwrap ();

					let changed = (

						metadata.len () !=
							existing_file_data.size

					||

						metadata.mtime () !=
							existing_file_data.mtime

					);

					if changed {

						self.out_database.insert_update_metadata (
							& existing_file_data,
							root_path.clone (),
							& metadata,
						);

					} else {

						self.out_database.insert_direct (
							existing_file_data)

					}

				} else {

					self.out_database.insert_new (
						Rc::new (
							entry.path ()),
						root_path.clone (),
						& metadata,
					);

				}

			};

			if self.progress % 0x1000 == 0 {

				self.output.status (
					& format! (
						"Scanning filesystem: {}",
						entry.path ().to_string_lossy ()));

			}

			self.progress += 1;

		}

		Ok (())

	}

}

// ex: noet ts=4 filetype=rust
<commit_msg>more fixes for directory scanning, related to devices and roots, more work to do<commit_after>#![ allow (unused_parens) ]

use std::collections::HashSet;
use std::fs;
use std::fs::DirEntry;
use std::io;
use std::os::unix::fs::MetadataExt;
use std::rc::Rc;

use output::Output;

use arguments::*;
use misc::*;
use storage::*;
use types::*;

pub fn scan_directories (
	arguments: & Arguments,
	output: & mut Output,
	previous_database: FileDatabase,
) -> Result <FileDatabase, String> {

	let root_paths: HashSet <PathRef> =
		arguments.root_paths.iter ().map (
			|root_path|

			root_path.clone ()

		).collect ();

	let previous_database_iterator =
		previous_database.into_iter ();

	let previous_database_iterator =
		previous_database_iterator.peekable ();

	let new_database: FileDatabase =
		FileDatabase::new ();

	let directory_scanner =
		DirectoryScanner {

		arguments: arguments,
		output: output,

		in_iterator: previous_database_iterator,
		out_database: new_database,

		root_paths_unordered: root_paths,
		root_paths_scanned: HashSet::new (),

		progress: 0,

	};

	directory_scanner.scan_directories ()

}

struct DirectoryScanner <'a> {

	arguments: & 'a Arguments,
	output: & 'a mut Output,

	in_iterator: FileDatabaseIntoIterator,
	out_database: FileDatabase,

	root_paths_unordered: HashSet <PathRef>,
	root_paths_scanned: HashSet <PathRef>,

	progress: u64,

}

impl <'a> DirectoryScanner <'a> {

	pub fn scan_directories (
		mut self,
	) -> Result <FileDatabase, String> {

		for root_path in & self.arguments.root_paths {

			if self.root_paths_scanned.contains (root_path) {
				continue;
			}

			self.output.message (
				& format! (
					"Scanning {}",
					root_path.to_string_lossy ()));

			let root_path =
				self.out_database.get_path (
					root_path.clone ());

			let metadata =
				try! (

				fs::symlink_metadata (
					root_path.as_ref (),
				).map_err (
					|error|

					format! (
						"Error reading metadata for: {}: {}",
						root_path.to_string_lossy (),
						error)

				)

			);

			loop {

				{

					let existing_file_data_option =
						self.in_iterator.peek ();

					if existing_file_data_option.is_none () {
						break;
					}

					let existing_file_data =
						existing_file_data_option.unwrap ();

					let existing_file_path =
						& existing_file_data.path;

					if * existing_file_path >= root_path {
						break;
					}

				}

				self.out_database.insert_direct (
					self.in_iterator.next ().unwrap ());

			}

			try! (
				self.scan_directory_internal (
					root_path.clone (),
					root_path.clone (),
					metadata.dev ()));

		}

		for existing_file_data_ref
		in self.in_iterator {

			self.out_database.insert_direct (
				existing_file_data_ref.clone ());

		}

		self.output.clear_status ();

		self.output.message (
			& format! (
				"Scanned {} files",
				self.progress));

		self.output.message (
			& format! (
				"Total {} files in database",
				self.out_database.len ()));

		Ok (self.out_database)

	}

	fn scan_directory_internal (
		& mut self,
		directory: PathRef,
		root_path: PathRef,
		device_id: u64,
	) -> Result <(), String> {

		if (
			self.root_paths_unordered.contains (
				& directory)
		) {
			self.root_paths_scanned.insert (
				directory.clone ());
		}

		let directory =
			directory.as_ref ();

		let entry_results: Vec <io::Result <DirEntry>> =
			try! (

			io_result (
				fs::read_dir (
					directory),
			).map_err (
				|error|

				format! (
					"Error reading directory: {}: {}",
					directory.to_string_lossy (),
					error)

			)

		).collect ();

		let mut entries: Vec <DirEntry> =
			Vec::new ();

		for entry_result in entry_results.into_iter () {

			entries.push (
				try! (

				io_result (
					entry_result,
				).map_err (
					|error|

					format! (
						"Error reading entry: {}",
						error)

				)

			));

		}

		entries.sort_by_key (
			|entry|

			entry.file_name ()

		);

		let mut entry_iterator =
			entries.into_iter ().peekable ();

		loop {

			{

				let entry_next =
					entry_iterator.peek ();

				if entry_next.is_none () {
					break;
				}

			}

			let entry =
				entry_iterator.next ().unwrap ();

			let entry_path =
				Rc::new (
					entry.path ());

			loop {

				let exists = {

					let in_next_option =
						self.in_iterator.peek ();

					if in_next_option.is_none () {
						break;
					}

					let in_next =
						in_next_option.unwrap ();

					let in_next_path =
						in_next.path.clone ();

					if in_next_path >= entry_path {
						break;
					}

					in_next_path.exists ()

				};

				if exists {

					self.out_database.insert_direct (
						self.in_iterator.next ().unwrap ());

				} else {

					self.in_iterator.next ();

				}

			}

			let entry_metadata =
				try! (

				fs::symlink_metadata (
					entry_path.as_ref (),
				).map_err (
					|error|

					format! (
						"Error reading metadata for: {}: {}",
						entry_path.to_string_lossy (),
						error)

				)

			);

			let entry_file_type =
				entry_metadata.file_type ();

			let (temp_root_path, temp_device_id) =
				if self.root_paths_unordered.contains (
					& entry_path) {

				(
					entry_path.clone (),
					entry_metadata.dev (),
				)

			} else {

				(
					root_path.clone (),
					device_id,
				)

			};

			if (
				entry_file_type.is_symlink ()
				|| entry_metadata.dev () != temp_device_id
			) {

				// ignore

			} else if entry_file_type.is_dir () {

				try! (
					self.scan_directory_internal (
						entry_path.clone (),
						temp_root_path,
						temp_device_id));

			} else if entry_file_type.is_file () {

				let exists = {

					let in_next_option =
						self.in_iterator.peek ();

					if in_next_option.is_some () {

						let in_next =
							in_next_option.unwrap ();

						let in_next_path =
							in_next.path.clone ();

						in_next_path == entry_path

					} else {

						false

					}

				};

				if exists {

					let existing_file_data =
						self.in_iterator.next ().unwrap ();

					let changed = (

						entry_metadata.len () !=
							existing_file_data.size

					||

						entry_metadata.mtime () !=
							existing_file_data.mtime

					);

					if changed {

						self.out_database.insert_update_metadata (
							& existing_file_data,
							temp_root_path.clone (),
							& entry_metadata,
						);

					} else {

						self.out_database.insert_direct (
							existing_file_data)

					}

				} else {

					self.out_database.insert_new (
						entry_path.clone (),
						temp_root_path.clone (),
						& entry_metadata,
					);

				}

			};

			if self.progress % 0x1000 == 0 {

				self.output.status (
					& format! (
						"Scanning filesystem: {}",
						entry_path.to_string_lossy ()));

			}

			self.progress += 1;

		}

		Ok (())

	}

}

// ex: noet ts=4 filetype=rust
<|endoftext|>


<commit_before>fn hex_string_to_bytes(hex_str: &str) -> Option<Vec<u8>> {
    let mut bytes: Vec<u8> = Vec::new();
    let mut byte = 0u8;

    for (i, b) in hex_str.chars().enumerate() {
        match b.to_digit(16) {
            Some(n) => byte += (n << (4 * (1 - (i % 2)))) as u8,
            None => return None,
        }

        if i % 2 == 0 || i == hex_str.len() - 1 {
            bytes.push(byte);
            byte = 0;
        }
    }

    Some(bytes)
}

// fn hex_to_base64(hex_str: &str) -> String {
//     let hex =
// }

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

    #[test]
    fn test_hex_string_to_bytes() {
        assert_eq!(vec![1u8], hex_string_to_bytes("01").unwrap());
    }
}
<commit_msg>Write some hex_string_to_bytes tests<commit_after>fn hex_string_to_bytes(hex_str: &str) -> Option<Vec<u8>> {
    let mut bytes: Vec<u8> = Vec::new();
    let mut byte = 0u8;

    for (i, b) in hex_str.chars().enumerate() {
        match b.to_digit(16) {
            Some(n) => byte += (n << (4 * (1 - (i % 2)))) as u8,
            None => return None,
        }

        if i % 2 == 1 || i == hex_str.len() - 1 {
            bytes.push(byte);
            byte = 0;
        }
    }

    Some(bytes)
}

fn hex_to_base64(hex_str: &str) -> String {
    let bytes = hex_string_to_bytes(hex_str).unwrap();

}

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

    #[test]
    fn test_hex_string_to_bytes() {
        assert_eq!(vec![1u8], hex_string_to_bytes("01").unwrap());
        assert_eq!(None, hex_string_to_bytes("x"));
        assert_eq!(vec![255u8, 220u8, 15u8], hex_string_to_bytes("ffdc0f").unwrap());
    }

}
<|endoftext|>


<commit_before>use std::fmt;

use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};

struct Printer<'a, 'b> {
    output: &'a mut fmt::Formatter<'b>,
    stack: Vec<&'a str>,
}

impl fmt::Show for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            String(ref s) => {
                try!(write!(f, "\""));
                for ch in s.as_slice().chars() {
                    match ch {
                        '\u0008' => try!(write!(f, "\\b")),
                        '\u0009' => try!(write!(f, "\\t")),
                        '\u000a' => try!(write!(f, "\\n")),
                        '\u000c' => try!(write!(f, "\\f")),
                        '\u000d' => try!(write!(f, "\\r")),
                        '\u0022' => try!(write!(f, "\\\"")),
                        '\u002f' => try!(write!(f, "\\/")),
                        '\u005c' => try!(write!(f, "\\\\")),
                        ch => try!(write!(f, "{}", ch)),
                    }
                }
                write!(f, "\"")
            }
            Integer(i) => write!(f, "{}", i),
            Float(fp) => {
                try!(write!(f, "{}", fp));
                if fp % 1.0 == 0.0 { try!(write!(f, ".0")) }
                Ok(())
            }
            Boolean(b) => write!(f, "{}", b),
            Datetime(ref s) => write!(f, "{}", s),
            Array(ref a) => {
                match a.as_slice().head() {
                    Some(&Table(..)) => fail!("invalid toml array of tables"),
                    _ => {}
                }
                write!(f, "{}", a)
            }
            Table(ref t) => {
                let mut p = Printer { output: f, stack: Vec::new() };
                p.print(t)
            }
        }
    }
}

impl<'a, 'b> Printer<'a, 'b> {
    fn print(&mut self, table: &'a Table) -> fmt::Result {
        for (k, v) in table.iter() {
            match *v {
                Table(..) => continue,
                Array(ref a) => {
                    match a.as_slice().head() {
                        Some(&Table(..)) => continue,
                        _ => {}
                    }
                }
                _ => {}
            }
            try!(writeln!(self.output, "{} = {}", k, v));
        }
        for (k, v) in table.iter() {
            match *v {
                Table(ref inner) => {
                    self.stack.push(k.as_slice());
                    try!(writeln!(self.output, "\n[{}]",
                                  self.stack.connect(".")));
                    try!(self.print(inner));
                    self.stack.pop();
                }
                Array(ref inner) => {
                    match inner.as_slice().head() {
                        Some(&Table(..)) => {}
                        _ => continue
                    }
                    self.stack.push(k.as_slice());
                    for inner in inner.iter() {
                        try!(writeln!(self.output, "\n[[{}]]",
                                      self.stack.connect(".")));
                        match *inner {
                            Table(ref inner) => try!(self.print(inner)),
                            _ => fail!("non-heterogeneous toml array"),
                        }
                    }
                    self.stack.pop();
                }
                _ => {},
            }
        }
        Ok(())
    }
}

#[cfg(test)]
#[allow(warnings)]
mod tests {
    use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};
    use std::collections::TreeMap;

    macro_rules! map( ($($k:expr: $v:expr),*) => ({
        let mut _m = TreeMap::new();
        $(_m.insert($k.to_string(), $v);)*
        _m
    }) )

    #[test]
    fn simple_show() {
        assert_eq!(String("foo".to_string()).to_string().as_slice(),
                   "\"foo\"")
        assert_eq!(Integer(10).to_string().as_slice(),
                   "10")
        assert_eq!(Float(10.0).to_string().as_slice(),
                   "10.0")
        assert_eq!(Float(2.4).to_string().as_slice(),
                   "2.4")
        assert_eq!(Boolean(true).to_string().as_slice(),
                   "true")
        assert_eq!(Datetime("test".to_string()).to_string().as_slice(),
                   "test")
        assert_eq!(Array(vec![]).to_string().as_slice(),
                   "[]")
        assert_eq!(Array(vec![Integer(1), Integer(2)]).to_string().as_slice(),
                   "[1, 2]")
    }

    #[test]
    fn table() {
        assert_eq!(Table(map! { }).to_string().as_slice(),
                   "")
        assert_eq!(Table(map! { "test": Integer(2) }).to_string().as_slice(),
                   "test = 2\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Array(vec![Table(map! {
                            "test": String("wut".to_string())
                        })])
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [[test2]]\n\
                    test = \"wut\"\n")
    }
}

<commit_msg>Don't escape `/` when printing.<commit_after>use std::fmt;

use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};

struct Printer<'a, 'b> {
    output: &'a mut fmt::Formatter<'b>,
    stack: Vec<&'a str>,
}

impl fmt::Show for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            String(ref s) => {
                try!(write!(f, "\""));
                for ch in s.as_slice().chars() {
                    match ch {
                        '\u0008' => try!(write!(f, "\\b")),
                        '\u0009' => try!(write!(f, "\\t")),
                        '\u000a' => try!(write!(f, "\\n")),
                        '\u000c' => try!(write!(f, "\\f")),
                        '\u000d' => try!(write!(f, "\\r")),
                        '\u0022' => try!(write!(f, "\\\"")),
                        '\u005c' => try!(write!(f, "\\\\")),
                        ch => try!(write!(f, "{}", ch)),
                    }
                }
                write!(f, "\"")
            }
            Integer(i) => write!(f, "{}", i),
            Float(fp) => {
                try!(write!(f, "{}", fp));
                if fp % 1.0 == 0.0 { try!(write!(f, ".0")) }
                Ok(())
            }
            Boolean(b) => write!(f, "{}", b),
            Datetime(ref s) => write!(f, "{}", s),
            Array(ref a) => {
                match a.as_slice().head() {
                    Some(&Table(..)) => fail!("invalid toml array of tables"),
                    _ => {}
                }
                write!(f, "{}", a)
            }
            Table(ref t) => {
                let mut p = Printer { output: f, stack: Vec::new() };
                p.print(t)
            }
        }
    }
}

impl<'a, 'b> Printer<'a, 'b> {
    fn print(&mut self, table: &'a Table) -> fmt::Result {
        for (k, v) in table.iter() {
            match *v {
                Table(..) => continue,
                Array(ref a) => {
                    match a.as_slice().head() {
                        Some(&Table(..)) => continue,
                        _ => {}
                    }
                }
                _ => {}
            }
            try!(writeln!(self.output, "{} = {}", k, v));
        }
        for (k, v) in table.iter() {
            match *v {
                Table(ref inner) => {
                    self.stack.push(k.as_slice());
                    try!(writeln!(self.output, "\n[{}]",
                                  self.stack.connect(".")));
                    try!(self.print(inner));
                    self.stack.pop();
                }
                Array(ref inner) => {
                    match inner.as_slice().head() {
                        Some(&Table(..)) => {}
                        _ => continue
                    }
                    self.stack.push(k.as_slice());
                    for inner in inner.iter() {
                        try!(writeln!(self.output, "\n[[{}]]",
                                      self.stack.connect(".")));
                        match *inner {
                            Table(ref inner) => try!(self.print(inner)),
                            _ => fail!("non-heterogeneous toml array"),
                        }
                    }
                    self.stack.pop();
                }
                _ => {},
            }
        }
        Ok(())
    }
}

#[cfg(test)]
#[allow(warnings)]
mod tests {
    use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};
    use std::collections::TreeMap;

    macro_rules! map( ($($k:expr: $v:expr),*) => ({
        let mut _m = TreeMap::new();
        $(_m.insert($k.to_string(), $v);)*
        _m
    }) )

    #[test]
    fn simple_show() {
        assert_eq!(String("foo".to_string()).to_string().as_slice(),
                   "\"foo\"")
        assert_eq!(Integer(10).to_string().as_slice(),
                   "10")
        assert_eq!(Float(10.0).to_string().as_slice(),
                   "10.0")
        assert_eq!(Float(2.4).to_string().as_slice(),
                   "2.4")
        assert_eq!(Boolean(true).to_string().as_slice(),
                   "true")
        assert_eq!(Datetime("test".to_string()).to_string().as_slice(),
                   "test")
        assert_eq!(Array(vec![]).to_string().as_slice(),
                   "[]")
        assert_eq!(Array(vec![Integer(1), Integer(2)]).to_string().as_slice(),
                   "[1, 2]")
    }

    #[test]
    fn table() {
        assert_eq!(Table(map! { }).to_string().as_slice(),
                   "")
        assert_eq!(Table(map! { "test": Integer(2) }).to_string().as_slice(),
                   "test = 2\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Array(vec![Table(map! {
                            "test": String("wut".to_string())
                        })])
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [[test2]]\n\
                    test = \"wut\"\n")
    }
}

<|endoftext|>


<commit_before>use rustyline;
use std::iter;
use std::collections::btree_set::BTreeSet;
use ::interpreter;
use ::grammar::{self, error_printing};

pub struct Repl {}

impl Repl {
    pub fn start() {
        let quit = "(quit)";
        let break_chars: BTreeSet<char> = vec![' ', '('].into_iter().collect();
        let mut rl = rustyline::Editor::<IdentCompleter>::new();
        rl.add_history_entry(quit);

        let mut interpreter = interpreter::Interpreter::new();

        loop {
            let idents: Vec<String> = interpreter.current_scope.symbol_ids()
            .into_iter()
            .filter_map(|id| interpreter.interner.lookup(id).map(Into::into))
            .collect();

            let completer = IdentCompleter {
                break_chars: &break_chars,
                ident_list: idents
            };

            rl.set_completer(Some(completer));

            let line = rl.readline(">> ");
            let line = if line.is_err() { return } else { line.unwrap() };
            if line == quit { return }
            rl.add_history_entry(&line);

            // strip \n at the end
            let parsed = grammar::parse(&line, &mut interpreter);
            match parsed {
                Ok(value) => println!("=> {}", interpreter.evaluate(&value).to_string(&interpreter.interner)),
                Err(ref err)  => println!("{}", error_printing::create_error_message(&line, err)),
            }
        }
    }
}

struct IdentCompleter<'a> {
    break_chars: &'a BTreeSet<char>,
    ident_list: Vec<String>,
}

impl<'a> rustyline::completion::Completer for IdentCompleter<'a> {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let (start, word) = rustyline::completion::extract_word(line, pos, &self.break_chars);
        let matches: Vec<String> = self.ident_list.iter()
        .filter(|&ident| ident.starts_with(word))
        .cloned()
        //.chain(iter::once(close_params(line))) TODO
        .collect();
        Ok((start, matches))
    }
}

fn close_params(line: &str) -> String {
    let unclosed_parens = line.chars()
    .fold(0, |n, c| if c == '(' { n + 1 } else if c == ')' { n - 1 } else { n });
    let missing_parens: String = iter::repeat(')').take(unclosed_parens).collect();
    missing_parens
}
<commit_msg>improve autocomplete: handle quote, give closing parens as suggestions<commit_after>use rustyline;
use std::iter;
use std::collections::btree_set::BTreeSet;
use ::interpreter;
use ::grammar::{self, error_printing};

pub struct Repl {}

impl Repl {
    pub fn start() {
        let quit = "(quit)";
        let break_chars: BTreeSet<char> = vec![' ', '(', '\''].into_iter().collect();
        let mut rl = rustyline::Editor::<IdentCompleter>::new();
        rl.add_history_entry(quit);

        let mut interpreter = interpreter::Interpreter::new();

        loop {
            let idents: Vec<String> = interpreter.current_scope.symbol_ids()
            .into_iter()
            .filter_map(|id| interpreter.interner.lookup(id).map(Into::into))
            .collect();

            let completer = IdentCompleter {
                break_chars: &break_chars,
                ident_list: idents
            };

            rl.set_completer(Some(completer));

            let line = rl.readline(">> ");
            let line = if line.is_err() { return } else { line.unwrap() };
            if line == quit { return }
            rl.add_history_entry(&line);

            // strip \n at the end
            let parsed = grammar::parse(&line, &mut interpreter);
            match parsed {
                Ok(value) => println!("=> {}", interpreter.evaluate(&value).to_string(&interpreter.interner)),
                Err(ref err)  => println!("{}", error_printing::create_error_message(&line, err)),
            }
        }
    }
}

struct IdentCompleter<'a> {
    break_chars: &'a BTreeSet<char>,
    ident_list: Vec<String>,
}

impl<'a> rustyline::completion::Completer for IdentCompleter<'a> {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let (start, word) = rustyline::completion::extract_word(line, pos, &self.break_chars);

        let symbol_matches =
        self.ident_list.iter()
        .filter(|&ident| ident.starts_with(word))
        .cloned();

        // if word is just whitespaces return closing parens as first result
        let matches: Vec<String> = if word.chars().all(|c| c == ' ') {
            iter::once(close_params(line))
            .chain(symbol_matches)
            .collect()
        // else return closing parens as last result
        } else {
            symbol_matches
            .chain(iter::once(close_params(line)))
            .collect()
        };

        Ok((start, matches))
    }
}

fn close_params(line: &str) -> String {
    let unclosed_parens = line.chars()
    .fold(0, |n, c| if c == '(' { n + 1 } else if c == ')' { n - 1 } else { n });
    let missing_parens: String = iter::repeat(')').take(unclosed_parens).collect();
    missing_parens
}
<|endoftext|>


<commit_before>//! Query result rows.

use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::collections::VecDeque;
use std::fmt;
use std::ops::Deref;
use std::slice;

use {Result, Transaction, read_rows, DbErrorNew, SessionInfoNew, RowsNew, LazyRowsNew,
     StatementInternals};
use types::{FromSql, SessionInfo};
use stmt::{Statement, Column};
use error::Error;
use message::FrontendMessage::*;

enum StatementContainer<'a> {
    Borrowed(&'a Statement<'a>),
    Owned(Statement<'a>),
}

impl<'a> Deref for StatementContainer<'a> {
    type Target = Statement<'a>;

    fn deref(&self) -> &Statement<'a> {
        match *self {
            StatementContainer::Borrowed(s) => s,
            StatementContainer::Owned(ref s) => s,
        }
    }
}

/// The resulting rows of a query.
pub struct Rows<'stmt> {
    stmt: StatementContainer<'stmt>,
    data: Vec<Vec<Option<Vec<u8>>>>,
}

impl<'a> RowsNew<'a> for Rows<'a> {
    fn new(stmt: &'a Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a> {
        Rows {
            stmt: StatementContainer::Borrowed(stmt),
            data: data,
        }
    }

    fn new_owned(stmt: Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a> {
        Rows {
            stmt: StatementContainer::Owned(stmt),
            data: data,
        }
    }
}

impl<'a> fmt::Debug for Rows<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Rows")
           .field("columns", &self.columns())
           .field("rows", &self.data.len())
           .finish()
    }
}

impl<'stmt> Rows<'stmt> {
    /// Returns a slice describing the columns of the `Rows`.
    pub fn columns(&self) -> &[Column] {
        self.stmt.columns()
    }

    /// Returns the number of rows present.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Returns a specific `Row`.
    ///
    /// # Panics
    ///
    /// Panics if `idx` is out of bounds.
    pub fn get<'a>(&'a self, idx: usize) -> Row<'a> {
        Row {
            stmt: &*self.stmt,
            data: Cow::Borrowed(&self.data[idx]),
        }
    }

    /// Returns an iterator over the `Row`s.
    pub fn iter<'a>(&'a self) -> Iter<'a> {
        Iter {
            stmt: &*self.stmt,
            iter: self.data.iter(),
        }
    }
}

impl<'a> IntoIterator for &'a Rows<'a> {
    type Item = Row<'a>;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// An iterator over `Row`s.
pub struct Iter<'a> {
    stmt: &'a Statement<'a>,
    iter: slice::Iter<'a, Vec<Option<Vec<u8>>>>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Row<'a>;

    fn next(&mut self) -> Option<Row<'a>> {
        self.iter.next().map(|row| {
            Row {
                stmt: &*self.stmt,
                data: Cow::Borrowed(row),
            }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Row<'a>> {
        self.iter.next_back().map(|row| {
            Row {
                stmt: &*self.stmt,
                data: Cow::Borrowed(row),
            }
        })
    }
}

impl<'a> ExactSizeIterator for Iter<'a> {}

/// A single result row of a query.
pub struct Row<'a> {
    stmt: &'a Statement<'a>,
    data: Cow<'a, [Option<Vec<u8>>]>,
}

impl<'a> fmt::Debug for Row<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Row")
           .field("statement", self.stmt)
           .finish()
    }
}

impl<'a> Row<'a> {
    /// Returns the number of values in the row.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Returns a slice describing the columns of the `Row`.
    pub fn columns(&self) -> &'a [Column] {
        self.stmt.columns()
    }

    /// Retrieves the contents of a field of the row.
    ///
    /// A field can be accessed by the name or index of its column, though
    /// access by index is more efficient. Rows are 0-indexed.
    ///
    /// # Panics
    ///
    /// Panics if the index does not reference a column or the return type is
    /// not compatible with the Postgres type.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// # use postgres::{Connection, SslMode};
    /// # let conn = Connection::connect("", SslMode::None).unwrap();
    /// let stmt = conn.prepare("SELECT foo, bar from BAZ").unwrap();
    /// for row in &stmt.query(&[]).unwrap() {
    ///     let foo: i32 = row.get(0);
    ///     let bar: String = row.get("bar");
    ///     println!("{}: {}", foo, bar);
    /// }
    /// ```
    pub fn get<I, T>(&self, idx: I) -> T
        where I: RowIndex + fmt::Debug,
              T: FromSql
    {
        match self.get_inner(&idx) {
            Ok(ok) => ok,
            Err(err) => panic!("error retrieving column {:?}: {:?}", idx, err),
        }
    }

    /// Retrieves the contents of a field of the row.
    ///
    /// A field can be accessed by the name or index of its column, though
    /// access by index is more efficient. Rows are 0-indexed.
    ///
    /// Returns an `Error` value if the index does not reference a column or
    /// the return type is not compatible with the Postgres type.
    pub fn get_opt<I, T>(&self, idx: I) -> Result<T>
        where I: RowIndex,
              T: FromSql
    {
        self.get_inner(&idx)
    }

    fn get_inner<I, T>(&self, idx: &I) -> Result<T>
        where I: RowIndex,
              T: FromSql
    {
        let idx = try!(idx.idx(self.stmt).ok_or(Error::InvalidColumn));
        let ty = self.stmt.columns()[idx].type_();
        if !<T as FromSql>::accepts(ty) {
            return Err(Error::WrongType(ty.clone()));
        }
        let conn = self.stmt.conn().conn.borrow();
        match self.data[idx] {
            Some(ref data) => FromSql::from_sql(ty, &mut &**data, &SessionInfo::new(&*conn)),
            None => FromSql::from_sql_null(ty, &SessionInfo::new(&*conn)),
        }
    }

    /// Retrieves the specified field as a raw buffer of Postgres data.
    ///
    /// # Panics
    ///
    /// Panics if the index does not reference a column.
    pub fn get_bytes<I>(&self, idx: I) -> Option<&[u8]>
        where I: RowIndex + fmt::Debug
    {
        match idx.idx(self.stmt) {
            Some(idx) => self.data[idx].as_ref().map(|e| &**e),
            None => panic!("invalid index {:?}", idx),
        }
    }
}

/// A trait implemented by types that can index into columns of a row.
pub trait RowIndex {
    /// Returns the index of the appropriate column, or `None` if no such
    /// column exists.
    fn idx(&self, stmt: &Statement) -> Option<usize>;
}

impl RowIndex for usize {
    #[inline]
    fn idx(&self, stmt: &Statement) -> Option<usize> {
        if *self >= stmt.columns().len() {
            None
        } else {
            Some(*self)
        }
    }
}

impl<'a> RowIndex for &'a str {
    #[inline]
    fn idx(&self, stmt: &Statement) -> Option<usize> {
        if let Some(idx) = stmt.columns().iter().position(|d| d.name() == *self) {
            return Some(idx);
        };

        // FIXME ASCII-only case insensitivity isn't really the right thing to
        // do. Postgres itself uses a dubious wrapper around tolower and JDBC
        // uses the US locale.
        stmt.columns().iter().position(|d| d.name().eq_ignore_ascii_case(*self))
    }
}

/// A lazily-loaded iterator over the resulting rows of a query.
pub struct LazyRows<'trans, 'stmt> {
    stmt: &'stmt Statement<'stmt>,
    data: VecDeque<Vec<Option<Vec<u8>>>>,
    name: String,
    row_limit: i32,
    more_rows: bool,
    finished: bool,
    _trans: &'trans Transaction<'trans>,
}

impl<'trans, 'stmt> LazyRowsNew<'trans, 'stmt> for LazyRows<'trans, 'stmt> {
    fn new(stmt: &'stmt Statement<'stmt>,
           data: VecDeque<Vec<Option<Vec<u8>>>>,
           name: String,
           row_limit: i32,
           more_rows: bool,
           finished: bool,
           trans: &'trans Transaction<'trans>)
           -> LazyRows<'trans, 'stmt> {
        LazyRows {
            stmt: stmt,
            data: data,
            name: name,
            row_limit: row_limit,
            more_rows: more_rows,
            finished: finished,
            _trans: trans,
        }
    }
}

impl<'a, 'b> Drop for LazyRows<'a, 'b> {
    fn drop(&mut self) {
        if !self.finished {
            let _ = self.finish_inner();
        }
    }
}

impl<'a, 'b> fmt::Debug for LazyRows<'a, 'b> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("LazyRows")
           .field("name", &self.name)
           .field("row_limit", &self.row_limit)
           .field("remaining_rows", &self.data.len())
           .field("more_rows", &self.more_rows)
           .finish()
    }
}

impl<'trans, 'stmt> LazyRows<'trans, 'stmt> {
    fn finish_inner(&mut self) -> Result<()> {
        let mut conn = self.stmt.conn().conn.borrow_mut();
        check_desync!(conn);
        conn.close_statement(&self.name, b'P')
    }

    fn execute(&mut self) -> Result<()> {
        let mut conn = self.stmt.conn().conn.borrow_mut();

        try!(conn.write_messages(&[Execute {
                                       portal: &self.name,
                                       max_rows: self.row_limit,
                                   },
                                   Sync]));
        read_rows(&mut conn, &mut self.data).map(|more_rows| self.more_rows = more_rows)
    }

    /// Returns a slice describing the columns of the `LazyRows`.
    pub fn columns(&self) -> &'stmt [Column] {
        self.stmt.columns()
    }

    /// Consumes the `LazyRows`, cleaning up associated state.
    ///
    /// Functionally identical to the `Drop` implementation on `LazyRows`
    /// except that it returns any error to the caller.
    pub fn finish(mut self) -> Result<()> {
        self.finish_inner()
    }
}

impl<'trans, 'stmt> Iterator for LazyRows<'trans, 'stmt> {
    type Item = Result<Row<'stmt>>;

    fn next(&mut self) -> Option<Result<Row<'stmt>>> {
        if self.data.is_empty() && self.more_rows {
            if let Err(err) = self.execute() {
                return Some(Err(err));
            }
        }

        self.data.pop_front().map(|r| {
            Ok(Row {
                stmt: self.stmt,
                data: Cow::Owned(r),
            })
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let lower = self.data.len();
        let upper = if self.more_rows {
            None
        } else {
            Some(lower)
        };
        (lower, upper)
    }
}
<commit_msg>Tweak lifetime<commit_after>//! Query result rows.

use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::collections::VecDeque;
use std::fmt;
use std::ops::Deref;
use std::slice;

use {Result, Transaction, read_rows, DbErrorNew, SessionInfoNew, RowsNew, LazyRowsNew,
     StatementInternals};
use types::{FromSql, SessionInfo};
use stmt::{Statement, Column};
use error::Error;
use message::FrontendMessage::*;

enum StatementContainer<'a> {
    Borrowed(&'a Statement<'a>),
    Owned(Statement<'a>),
}

impl<'a> Deref for StatementContainer<'a> {
    type Target = Statement<'a>;

    fn deref(&self) -> &Statement<'a> {
        match *self {
            StatementContainer::Borrowed(s) => s,
            StatementContainer::Owned(ref s) => s,
        }
    }
}

/// The resulting rows of a query.
pub struct Rows<'stmt> {
    stmt: StatementContainer<'stmt>,
    data: Vec<Vec<Option<Vec<u8>>>>,
}

impl<'a> RowsNew<'a> for Rows<'a> {
    fn new(stmt: &'a Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a> {
        Rows {
            stmt: StatementContainer::Borrowed(stmt),
            data: data,
        }
    }

    fn new_owned(stmt: Statement<'a>, data: Vec<Vec<Option<Vec<u8>>>>) -> Rows<'a> {
        Rows {
            stmt: StatementContainer::Owned(stmt),
            data: data,
        }
    }
}

impl<'a> fmt::Debug for Rows<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Rows")
           .field("columns", &self.columns())
           .field("rows", &self.data.len())
           .finish()
    }
}

impl<'stmt> Rows<'stmt> {
    /// Returns a slice describing the columns of the `Rows`.
    pub fn columns(&self) -> &[Column] {
        self.stmt.columns()
    }

    /// Returns the number of rows present.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Returns a specific `Row`.
    ///
    /// # Panics
    ///
    /// Panics if `idx` is out of bounds.
    pub fn get<'a>(&'a self, idx: usize) -> Row<'a> {
        Row {
            stmt: &*self.stmt,
            data: Cow::Borrowed(&self.data[idx]),
        }
    }

    /// Returns an iterator over the `Row`s.
    pub fn iter<'a>(&'a self) -> Iter<'a> {
        Iter {
            stmt: &*self.stmt,
            iter: self.data.iter(),
        }
    }
}

impl<'a> IntoIterator for &'a Rows<'a> {
    type Item = Row<'a>;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// An iterator over `Row`s.
pub struct Iter<'a> {
    stmt: &'a Statement<'a>,
    iter: slice::Iter<'a, Vec<Option<Vec<u8>>>>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Row<'a>;

    fn next(&mut self) -> Option<Row<'a>> {
        self.iter.next().map(|row| {
            Row {
                stmt: &*self.stmt,
                data: Cow::Borrowed(row),
            }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Row<'a>> {
        self.iter.next_back().map(|row| {
            Row {
                stmt: &*self.stmt,
                data: Cow::Borrowed(row),
            }
        })
    }
}

impl<'a> ExactSizeIterator for Iter<'a> {}

/// A single result row of a query.
pub struct Row<'a> {
    stmt: &'a Statement<'a>,
    data: Cow<'a, [Option<Vec<u8>>]>,
}

impl<'a> fmt::Debug for Row<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Row")
           .field("statement", self.stmt)
           .finish()
    }
}

impl<'a> Row<'a> {
    /// Returns the number of values in the row.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Returns a slice describing the columns of the `Row`.
    pub fn columns(&self) -> &[Column] {
        self.stmt.columns()
    }

    /// Retrieves the contents of a field of the row.
    ///
    /// A field can be accessed by the name or index of its column, though
    /// access by index is more efficient. Rows are 0-indexed.
    ///
    /// # Panics
    ///
    /// Panics if the index does not reference a column or the return type is
    /// not compatible with the Postgres type.
    ///
    /// # Example
    ///
    /// ```rust,no_run
    /// # use postgres::{Connection, SslMode};
    /// # let conn = Connection::connect("", SslMode::None).unwrap();
    /// let stmt = conn.prepare("SELECT foo, bar from BAZ").unwrap();
    /// for row in &stmt.query(&[]).unwrap() {
    ///     let foo: i32 = row.get(0);
    ///     let bar: String = row.get("bar");
    ///     println!("{}: {}", foo, bar);
    /// }
    /// ```
    pub fn get<I, T>(&self, idx: I) -> T
        where I: RowIndex + fmt::Debug,
              T: FromSql
    {
        match self.get_inner(&idx) {
            Ok(ok) => ok,
            Err(err) => panic!("error retrieving column {:?}: {:?}", idx, err),
        }
    }

    /// Retrieves the contents of a field of the row.
    ///
    /// A field can be accessed by the name or index of its column, though
    /// access by index is more efficient. Rows are 0-indexed.
    ///
    /// Returns an `Error` value if the index does not reference a column or
    /// the return type is not compatible with the Postgres type.
    pub fn get_opt<I, T>(&self, idx: I) -> Result<T>
        where I: RowIndex,
              T: FromSql
    {
        self.get_inner(&idx)
    }

    fn get_inner<I, T>(&self, idx: &I) -> Result<T>
        where I: RowIndex,
              T: FromSql
    {
        let idx = try!(idx.idx(self.stmt).ok_or(Error::InvalidColumn));
        let ty = self.stmt.columns()[idx].type_();
        if !<T as FromSql>::accepts(ty) {
            return Err(Error::WrongType(ty.clone()));
        }
        let conn = self.stmt.conn().conn.borrow();
        match self.data[idx] {
            Some(ref data) => FromSql::from_sql(ty, &mut &**data, &SessionInfo::new(&*conn)),
            None => FromSql::from_sql_null(ty, &SessionInfo::new(&*conn)),
        }
    }

    /// Retrieves the specified field as a raw buffer of Postgres data.
    ///
    /// # Panics
    ///
    /// Panics if the index does not reference a column.
    pub fn get_bytes<I>(&self, idx: I) -> Option<&[u8]>
        where I: RowIndex + fmt::Debug
    {
        match idx.idx(self.stmt) {
            Some(idx) => self.data[idx].as_ref().map(|e| &**e),
            None => panic!("invalid index {:?}", idx),
        }
    }
}

/// A trait implemented by types that can index into columns of a row.
pub trait RowIndex {
    /// Returns the index of the appropriate column, or `None` if no such
    /// column exists.
    fn idx(&self, stmt: &Statement) -> Option<usize>;
}

impl RowIndex for usize {
    #[inline]
    fn idx(&self, stmt: &Statement) -> Option<usize> {
        if *self >= stmt.columns().len() {
            None
        } else {
            Some(*self)
        }
    }
}

impl<'a> RowIndex for &'a str {
    #[inline]
    fn idx(&self, stmt: &Statement) -> Option<usize> {
        if let Some(idx) = stmt.columns().iter().position(|d| d.name() == *self) {
            return Some(idx);
        };

        // FIXME ASCII-only case insensitivity isn't really the right thing to
        // do. Postgres itself uses a dubious wrapper around tolower and JDBC
        // uses the US locale.
        stmt.columns().iter().position(|d| d.name().eq_ignore_ascii_case(*self))
    }
}

/// A lazily-loaded iterator over the resulting rows of a query.
pub struct LazyRows<'trans, 'stmt> {
    stmt: &'stmt Statement<'stmt>,
    data: VecDeque<Vec<Option<Vec<u8>>>>,
    name: String,
    row_limit: i32,
    more_rows: bool,
    finished: bool,
    _trans: &'trans Transaction<'trans>,
}

impl<'trans, 'stmt> LazyRowsNew<'trans, 'stmt> for LazyRows<'trans, 'stmt> {
    fn new(stmt: &'stmt Statement<'stmt>,
           data: VecDeque<Vec<Option<Vec<u8>>>>,
           name: String,
           row_limit: i32,
           more_rows: bool,
           finished: bool,
           trans: &'trans Transaction<'trans>)
           -> LazyRows<'trans, 'stmt> {
        LazyRows {
            stmt: stmt,
            data: data,
            name: name,
            row_limit: row_limit,
            more_rows: more_rows,
            finished: finished,
            _trans: trans,
        }
    }
}

impl<'a, 'b> Drop for LazyRows<'a, 'b> {
    fn drop(&mut self) {
        if !self.finished {
            let _ = self.finish_inner();
        }
    }
}

impl<'a, 'b> fmt::Debug for LazyRows<'a, 'b> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("LazyRows")
           .field("name", &self.name)
           .field("row_limit", &self.row_limit)
           .field("remaining_rows", &self.data.len())
           .field("more_rows", &self.more_rows)
           .finish()
    }
}

impl<'trans, 'stmt> LazyRows<'trans, 'stmt> {
    fn finish_inner(&mut self) -> Result<()> {
        let mut conn = self.stmt.conn().conn.borrow_mut();
        check_desync!(conn);
        conn.close_statement(&self.name, b'P')
    }

    fn execute(&mut self) -> Result<()> {
        let mut conn = self.stmt.conn().conn.borrow_mut();

        try!(conn.write_messages(&[Execute {
                                       portal: &self.name,
                                       max_rows: self.row_limit,
                                   },
                                   Sync]));
        read_rows(&mut conn, &mut self.data).map(|more_rows| self.more_rows = more_rows)
    }

    /// Returns a slice describing the columns of the `LazyRows`.
    pub fn columns(&self) -> &'stmt [Column] {
        self.stmt.columns()
    }

    /// Consumes the `LazyRows`, cleaning up associated state.
    ///
    /// Functionally identical to the `Drop` implementation on `LazyRows`
    /// except that it returns any error to the caller.
    pub fn finish(mut self) -> Result<()> {
        self.finish_inner()
    }
}

impl<'trans, 'stmt> Iterator for LazyRows<'trans, 'stmt> {
    type Item = Result<Row<'stmt>>;

    fn next(&mut self) -> Option<Result<Row<'stmt>>> {
        if self.data.is_empty() && self.more_rows {
            if let Err(err) = self.execute() {
                return Some(Err(err));
            }
        }

        self.data.pop_front().map(|r| {
            Ok(Row {
                stmt: self.stmt,
                data: Cow::Owned(r),
            })
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let lower = self.data.len();
        let upper = if self.more_rows {
            None
        } else {
            Some(lower)
        };
        (lower, upper)
    }
}
<|endoftext|>


<commit_before>//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7

pub use crate::segmentation;

/// Load the task state register.
pub unsafe fn load_tr(sel: segmentation::SegmentSelector) {
    asm!("ltr $0" :: "r" (sel.bits()));
}
<commit_msg>Added function to return the current value of the task register<commit_after>//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7

pub use crate::segmentation;

/// Returns the current value of the task register.
pub fn tr() -> segmentation::SegmentSelector {
    let segment: u16;
    unsafe { asm!("str $0" : "=r" (segment) ) };
    segmentation::SegmentSelector::from_raw(segment)
}

/// Loads the task register.
pub unsafe fn load_tr(sel: segmentation::SegmentSelector) {
    asm!("ltr $0" :: "r" (sel.bits()));
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::uintptr_t;
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use std::string;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;
use green::task::GreenTask;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

unsafe extern fn gc_callback(rt: *mut JSRuntime, _status: JSGCStatus) {
    use std::rt::local::Local;
    use std::rt::task::Task;
    unsafe {
        let mut task = Local::borrow(None::<Task>);
        let runtime = task.take_runtime();
        let (start, end) = runtime.stack_bounds();
        JS_SetNativeStackBounds(rt, cmp::min(start, end) as uintptr_t,
                                    cmp::max(start, end) as uintptr_t);
        task.put_runtime(runtime);
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, Some(gc_callback));
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *const c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.as_slice().utf16_units().collect();
        let filename_cstr = filename.to_c_str();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {:s} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(ptr.is_not_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if fnptr.is_not_null() {string::raw::from_buf(fnptr as *const i8 as *const u8)} else {"none".to_string()};
    let lineno = (*report).lineno;
    let msg = string::raw::from_buf(msg as *const i8 as *const u8);
    error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<commit_msg>Allow the user to set their own GC callback<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::uintptr_t;
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use std::string;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;
use green::task::GreenTask;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

/// If you set your own callback, the first step should be a call to this one.
pub unsafe extern fn gc_callback(rt: *mut JSRuntime, _status: JSGCStatus) {
    use std::rt::local::Local;
    use std::rt::task::Task;
    unsafe {
        let mut task = Local::borrow(None::<Task>);
        let runtime = task.take_runtime();
        let (start, end) = runtime.stack_bounds();
        JS_SetNativeStackBounds(rt, cmp::min(start, end) as uintptr_t,
                                    cmp::max(start, end) as uintptr_t);
        task.put_runtime(runtime);
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, Some(gc_callback));
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *const c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.as_slice().utf16_units().collect();
        let filename_cstr = filename.to_c_str();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {:s} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(ptr.is_not_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if fnptr.is_not_null() {string::raw::from_buf(fnptr as *const i8 as *const u8)} else {"none".to_string()};
    let lineno = (*report).lineno;
    let msg = string::raw::from_buf(msg as *const i8 as *const u8);
    error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<|endoftext|>