<commit_before>extern crate petgraph;

pub mod indextype;
pub mod inner;

use super::traits::{InstructionType, NavigationInternal};

use self::indextype::IndexType;
use self::inner::{InnerGraph, InnerEdgeLight, InnerEdgeTrait, AuxQuery};
use self::petgraph::{Incoming, Outgoing};
use self::petgraph::graph::{Edge, EdgeIndex, Graph, NodeIndex};

type DefaultInnerEdge<Index/*: IndexType*/> = InnerEdgeLight<Index>;

trait BlockToReprPayload { type Type; }
trait UsedInnerEdgeType { type InnerEdgeType: InnerEdgeTrait; }

pub struct PhiIndex<Index>(Index);

pub struct BasicBlock<Index: IndexType, Instruction: InstructionType> {
	num_ext: Index,
	phis: Vec<(Instruction::PhiType, <DefaultInnerEdge<Index> as self::inner::InnerEdgeTrait>::NodeAux)>,
	inner_graph: InnerGraph<Instruction, DefaultInnerEdge<Index>>
}

enum LookupResult<Index: IndexType, Instruction: InstructionType> {
	FoundInBB(Instruction),
	Phi(Index),
	External(Index),
	NotFound(Index)
}

impl<Index: IndexType, Instruction: InstructionType> BlockToReprPayload for BasicBlock<Index, Instruction> {
	type Type = <InnerEdgeLight<Index> as InnerEdgeTrait>::NodeAux;
}

impl<Index: IndexType, Instruction: InstructionType> BasicBlock<Index, Instruction> {
	pub fn new() -> Self {
		BasicBlock::<Index, Instruction> {
			num_ext: Index::zero(),
			phis: Vec::new(),
			inner_graph: InnerGraph::<Instruction, InnerEdgeLight<Index>>::new()
		}
	}

	fn lookup(&self, i: Index) -> LookupResult<Index, Instruction> {
		if i >= Index::zero() {
			let instr = self.inner_graph.lookup(i);
			if instr.is_phi() {
				// TODO
			}
			LookupResult::NotFound(i)

		} else if i + self.num_ext >= Index::zero() {
			LookupResult::External(i)

		} else {
			LookupResult::NotFound(i)
		}
	}
}

type DefaultInnerIndex = i16;
type DefaultBasicBlock<Instruction> = BasicBlock<DefaultInnerIndex, Instruction>;

enum IRNode<Instruction: InstructionType> {
	// Represents an operation of a basic block that is used by non-phi nodes outside of that basic block
	Repr,
	// Represents a basic block
	BasicBlock(DefaultBasicBlock<Instruction>)
}

enum IREdge<Instruction: InstructionType> {
	// Points from a `IRNode::Repr` to the `IR::BasicBlock` that it belongs to
	ReprToBlock(DefaultInnerIndex),
	// Points from a `IR::BasicBlock`s to `IRNode::Repr` whose target BlockToReprPayloadis used by operations in the basic block
	// Contains a id of the first user in the basic block, and the id the `IRNode::Repr` is known by in the basic block
	BlockToRepr(DefaultInnerIndex, <DefaultBasicBlock<Instruction> as BlockToReprPayload>::Type),
	// Points from one `IR::BasicBlock` to another. Represents control flow.
	// It contains a vector of 'n' references to operations in the origin basic block
	// that are used by 'n' phi operations in the target basic block.
	Flow(Vec<DefaultInnerIndex>, u64)
}

type IRGraph<Instruction> = Graph<IRNode<Instruction>, IREdge<Instruction>>;

pub struct NodeRef<I>(NodeIndex, I);
struct AuxQueryImpl<'a, Instruction: InstructionType + 'a>(&'a mut IRGraph<Instruction>, NodeIndex);

// forward that type
impl<Index: IndexType, Instruction: InstructionType> UsedInnerEdgeType for BasicBlock<Index, Instruction> {
	type InnerEdgeType = DefaultInnerEdge<Index>;
}
impl<Instruction: InstructionType> UsedInnerEdgeType for IRGraph<Instruction> {
	type InnerEdgeType = <DefaultBasicBlock<Instruction> as UsedInnerEdgeType>::InnerEdgeType;
}
impl<'a, Instruction: InstructionType> UsedInnerEdgeType for AuxQueryImpl<'a, Instruction> {
	type InnerEdgeType = <IRGraph<Instruction> as UsedInnerEdgeType>::InnerEdgeType;
}

macro_rules! find_edge {
	( $graph:expr, $node:expr, $direction:expr, $( $pat:pat => $cond:expr ),* ) => {
		{
			let mut fedge: Option<EdgeIndex> = Option::None;
			let mut temp_edgewalk = $graph.walk_edges_directed($node, $direction);
			while let Some(edge) = temp_edgewalk.next($graph) {
				if match $graph.edge_weight(edge).expect("petgraph.walk_edges_directed gave us a non-existant edge") {
					$(
						$pat => $cond
					),*
					_ => { false }
				} {
					fedge = Option::Some(edge);
					break
				}
			}
			fedge
		}
	};
}

impl<'b, Instruction: InstructionType/*, InnerEdge: InnerEdgeTrait<Index=DefaultInnerIndex>*/>
	inner::AuxQuery<<AuxQueryImpl<'b, Instruction> as UsedInnerEdgeType>::InnerEdgeType>
	for AuxQueryImpl<'b, Instruction>
{
	//use AuxQueryImpl<'b, Instruction>::InnerEdgeType as InnerEdge;

	fn access_aux<'a>(&'a mut self, i: <<Self as UsedInnerEdgeType>::InnerEdgeType as InnerEdgeTrait>::Index)
		-> &'a mut <<Self as UsedInnerEdgeType>::InnerEdgeType as InnerEdgeTrait>::NodeAux
	{
		let fedge: Option<EdgeIndex> = find_edge!(self.0, self.1, Outgoing,
			&IREdge::BlockToRepr(key, _) => { key == i }
		);
		if let Some(edge) = fedge {
			if let Some(&mut IREdge::BlockToRepr(_, ref mut aux)) = self.0.edge_weight_mut(edge){
				return aux
			}
		}
		panic!();
	}
}

fn deref<Instruction: InstructionType>(graph: &IRGraph<Instruction>, noderef: NodeRef<DefaultInnerIndex>) {

	let fedge: Option<EdgeIndex> = find_edge!(graph, noderef.0, Outgoing,
		&IREdge::BlockToRepr(key, _) => { key == noderef.1 }
	);
	if let Some(edge) = fedge {
		// TODO
	}
}

impl<Index: IndexType, Instruction: InstructionType> NavigationInternal<NodeRef<Index>> for IRGraph<Instruction> {
	fn add_uses_to(&self, noderef: NodeRef<Index>, r: &mut Vec<NodeRef<Index>>) {
		if let Option::Some(node) = self.node_weight(noderef.0) {
			// TODO
			panic!();
		} else {
			panic!();
		}
	}

	fn add_args_to(&self, noderef: NodeRef<Index>, r: &mut Vec<NodeRef<Index>>) {
		if let Option::Some(node) = self.node_weight(noderef.0) {
			let bb = match *node {
				IRNode::Repr => panic!(),
				IRNode::BasicBlock(ref bb) => {
					bb
				}
			};
			/* // TODO
			if (noderef.is_phi()) {
				let phiindex = !noderef.1;
				let mut edges = self.walk_edges_directed(noderef.0, Incoming);
				while let Some(edge) = edges.next(&self) {
					match self.edge_weight(edge) {
						None => {},
						Some(&IREdge::ReprToBlock(_)) => {},
						Some(&IREdge::BlockToRepr(_, _)) => {},
						Some(&IREdge::Flow(phisource, id)) => {
							// r.push(deref_noderef(self, noderef.0, i));
						}
					}
				}
			} else {
				let inner_r = Vec::<Index>::new();
				bb.inner_graph.add_args_to(noderef.1, &mut r);
				for i in inner_r {
					// TODO
					// r.push(deref_noderef(self, noderef.0, i));
				}
			}*/
		} else {
			panic!();
		}
	}
}

mod test {
	use super::super::traits::InstructionType;
	use super::IRGraph;

	#[derive(Debug)]
	enum TestInstr { Phi, NotPhi }

	impl InstructionType for TestInstr {
		type PhiType = ();
		fn make_phi(_: ()) -> TestInstr { TestInstr::Phi }
		fn is_phi(&self) -> bool { if let TestInstr::Phi = *self { true } else { false } }
	}

	#[test]
	fn construct() {
		let graph: IRGraph<TestInstr>;
	}

	// more tests will follow
}
<commit_msg>ir/graph: Changed parametrization from <Instr> to <Index, Instr><commit_after>extern crate petgraph;

pub mod indextype;
pub mod inner;

use super::traits::{InstructionType, Navigation, NavigationInternal};

use self::indextype::IndexType;
use self::inner::{InnerGraph, InnerEdgeLight, InnerEdgeTrait, AuxQuery};
use self::petgraph::{Incoming, Outgoing};
use self::petgraph::graph::{Edge, EdgeIndex, Graph, NodeIndex};

type DefaultInnerEdge<Index/*: IndexType*/> = InnerEdgeLight<Index>;

trait BlockToReprPayload { type Type; }
trait UsedInnerEdgeType { type InnerEdgeType: InnerEdgeTrait; }

pub struct PhiIndex<Index>(Index);

pub struct BasicBlock<Index: IndexType, Instruction: InstructionType> {
	num_ext: Index,
	phis: Vec<(Instruction::PhiType, <DefaultInnerEdge<Index> as self::inner::InnerEdgeTrait>::NodeAux)>,
	inner_graph: InnerGraph<Instruction, DefaultInnerEdge<Index>>
}

enum LookupResult<Index: IndexType, Instruction: InstructionType> {
	FoundInBB(Instruction),
	Phi(Index),
	External(Index),
	NotFound(Index)
}

impl<Index: IndexType, Instruction: InstructionType> BlockToReprPayload for BasicBlock<Index, Instruction> {
	type Type = <InnerEdgeLight<Index> as InnerEdgeTrait>::NodeAux;
}

impl<Index: IndexType, Instruction: InstructionType> BasicBlock<Index, Instruction> {
	pub fn new() -> Self {
		BasicBlock::<Index, Instruction> {
			num_ext: Index::zero(),
			phis: Vec::new(),
			inner_graph: InnerGraph::<Instruction, InnerEdgeLight<Index>>::new()
		}
	}

	fn lookup(&self, i: Index) -> LookupResult<Index, Instruction> {
		if i >= Index::zero() {
			let instr = self.inner_graph.lookup(i);
			if instr.is_phi() {
				// TODO
			}
			LookupResult::NotFound(i)

		} else if i + self.num_ext >= Index::zero() {
			LookupResult::External(i)

		} else {
			LookupResult::NotFound(i)
		}
	}
}

type DefaultInnerIndex = i16;
type DefaultBasicBlock<Instruction> = BasicBlock<DefaultInnerIndex, Instruction>;

enum IRNode<Index: IndexType, Instruction: InstructionType> {
	// Represents an operation of a basic block that is used by non-phi nodes outside of that basic block
	Repr,
	// Represents a basic block
	BasicBlock(BasicBlock<Index, Instruction>)
}

enum IREdge<Index: IndexType, Instruction: InstructionType> {
	// Points from a `IRNode::Repr` to the `IR::BasicBlock` that it belongs to
	ReprToBlock(Index),
	// Points from a `IR::BasicBlock`s to `IRNode::Repr` whose target is used by operations in the basic block
	// Contains a id of the first user in the basic block, and the id the `IRNode::Repr` is known by in the basic block
	BlockToRepr(Index, <BasicBlock<Index, Instruction> as BlockToReprPayload>::Type),
	// Points from one `IR::BasicBlock` to another. Represents control flow.
	// It contains a vector of 'n' references to operations in the origin basic block
	// that are used by 'n' phi operations in the target basic block.
	Flow(Vec<Index>, u64)
}

type IRGraph<Index, Instruction> = Graph<
	IRNode<Index, Instruction>,
	IREdge<Index, Instruction>
>;

pub struct NodeRef<I>(NodeIndex, I);
struct AuxQueryImpl<'a, Index: IndexType + 'a, Instruction: InstructionType + 'a>(
	&'a mut IRGraph<Index, Instruction>,
	NodeIndex
);

// forward that type
impl<Index: IndexType, Instruction: InstructionType> UsedInnerEdgeType for IRGraph<Index, Instruction> {
	type InnerEdgeType = DefaultInnerEdge<Index>;
}
impl<'a, Index: IndexType, Instruction: InstructionType> UsedInnerEdgeType for AuxQueryImpl<'a, Index, Instruction> {
	type InnerEdgeType = <IRGraph<Index, Instruction> as UsedInnerEdgeType>::InnerEdgeType;
}

macro_rules! find_edge {
	( $graph:expr, $node:expr, $direction:expr, $( $pat:pat => $cond:expr ),* ) => {
		{
			let mut fedge: Option<EdgeIndex> = Option::None;
			let mut temp_edgewalk = $graph.walk_edges_directed($node, $direction);
			while let Some(edge) = temp_edgewalk.next($graph) {
				if match &$graph[edge] {
					$(
						$pat => $cond
					),*
					_ => { false }
				} {
					fedge = Option::Some(edge);
					break
				}
			}
			fedge
		}
	};
}

impl<'b, Index: IndexType, Instruction: InstructionType/*, InnerEdge: InnerEdgeTrait<Index=DefaultInnerIndex>*/>
	inner::AuxQuery<<AuxQueryImpl<'b, Index, Instruction> as UsedInnerEdgeType>::InnerEdgeType>
	for AuxQueryImpl<'b, Index, Instruction>
{
	//use AuxQueryImpl<'b, Instruction>::InnerEdgeType as InnerEdge;

	fn access_aux<'a>(&'a mut self, i: <<Self as UsedInnerEdgeType>::InnerEdgeType as InnerEdgeTrait>::Index)
		-> &'a mut <<Self as UsedInnerEdgeType>::InnerEdgeType as InnerEdgeTrait>::NodeAux
	{
		let fedge: Option<EdgeIndex> = find_edge!(self.0, self.1, Outgoing,
			&IREdge::BlockToRepr(key, _) => { key == i }
		);
		if let Some(edge) = fedge {
			if let Some(&mut IREdge::BlockToRepr(_, ref mut aux)) = self.0.edge_weight_mut(edge){
				return aux
			}
		}
		panic!();
	}
}

fn deref<Index: IndexType, Instruction: InstructionType>(
	graph: &IRGraph<Index, Instruction>,
	noderef: NodeRef<Index>
) -> NodeRef<Index> {
	let fedge: Option<EdgeIndex> = find_edge!(graph, noderef.0, Outgoing,
		&IREdge::BlockToRepr(key, _) => { key == noderef.1 }
	);
	if let Some(edge) = fedge {
		// TODO
	}
	panic!();
}

impl<Index: IndexType, Instruction: InstructionType> NavigationInternal<NodeRef<Index>> for IRGraph<Index, Instruction> {
	fn add_uses_to(&self, noderef: NodeRef<Index>, r: &mut Vec<NodeRef<Index>>) {
		let node = &self[noderef.0];
		let bb = if let &IRNode::BasicBlock(ref bb) = node { bb } else { panic!() };
	}

	fn add_args_to(&self, noderef: NodeRef<Index>, r: &mut Vec<NodeRef<Index>>) {
		let node = &self[noderef.0];
		let bb = if let &IRNode::BasicBlock(ref bb) = node { bb } else { panic!() };
		let instruction = bb.inner_graph.lookup(noderef.1);

		if (instruction.is_phi()) {
			let mut edges = self.walk_edges_directed(noderef.0, Incoming);
			while let Some(edgeindex) = edges.next(&self) {
				let edge = &self.raw_edges()[edgeindex.index()];
				match &edge.weight {
					&IREdge::Flow(ref phisource, ref id) => {
						//r.push(deref(self, NodeRef::<Index>(edge.source(), phisource[])));
					}
					_ => {}
				}
			}
		} else {
			let inner_arg = bb.inner_graph.args_of(noderef.1);
			for i in inner_arg {
				r.push(deref(self, NodeRef::<Index>(noderef.0, i)));
			}
		}
	}
}

mod test {
	use super::super::traits::InstructionType;
	use super::{DefaultInnerIndex, IRGraph};

	#[derive(Debug)]
	enum TestInstr { Phi, NotPhi }

	impl InstructionType for TestInstr {
		type PhiType = ();
		fn make_phi(_: ()) -> TestInstr { TestInstr::Phi }
		fn is_phi(&self) -> bool { if let TestInstr::Phi = *self { true } else { false } }
	}

	#[test]
	fn construct() {
		let graph: IRGraph<DefaultInnerIndex, TestInstr>;
	}

	// more tests will follow
}
<|endoftext|>


<commit_before>use crate::Result;
use async_task::Task;
use crossbeam_channel::{Receiver, Sender};
use parking_lot::Mutex;
use std::{
    fmt,
    future::Future,
    ops::Deref,
    pin::Pin,
    sync::Arc,
    thread::{Builder as ThreadBuilder, JoinHandle},
};

pub trait Executor: std::fmt::Debug + Send + Sync {
    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<()>;
}

impl Executor for Arc<dyn Executor> {
    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<()> {
        self.deref().spawn(f)
    }
}

#[derive(Clone)]
pub struct DefaultExecutor {
    sender: Sender<Task<()>>,
    receiver: Receiver<Task<()>>,
    threads: Arc<Mutex<Vec<JoinHandle<()>>>>,
    max_threads: usize,
}

impl DefaultExecutor {
    pub fn new(max_threads: usize) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        let threads = Default::default();
        Self {
            sender,
            receiver,
            threads,
            max_threads,
        }
    }

    pub(crate) fn maybe_spawn_thread(&self) -> Result<()> {
        let mut threads = self.threads.lock();
        let id = threads.len() + 1;
        if id <= self.max_threads {
            let receiver = self.receiver.clone();
            threads.push(
                ThreadBuilder::new()
                    .name(format!("executor {}", id))
                    .spawn(move || {
                        for task in receiver {
                            task.run();
                        }
                    })?,
            );
        }
        Ok(())
    }
}

impl Default for DefaultExecutor {
    fn default() -> Self {
        Self::new(1)
    }
}

impl fmt::Debug for DefaultExecutor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DefaultExecutor")
            .field("max_threads", &self.max_threads)
            .finish()
    }
}

impl Executor for DefaultExecutor {
    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<()> {
        self.maybe_spawn_thread()?;
        let sender = self.sender.clone();
        let schedule = move |task| sender.send(task).expect("executor failed");
        let (task, _) = async_task::spawn(f, schedule, ());
        task.schedule();
        Ok(())
    }
}
<commit_msg>executor: wait for threads on Drop<commit_after>use crate::{thread::ThreadHandle, Result};
use async_task::Task;
use crossbeam_channel::{Receiver, Sender};
use parking_lot::Mutex;
use std::{fmt, future::Future, ops::Deref, pin::Pin, sync::Arc, thread::Builder as ThreadBuilder};

pub trait Executor: std::fmt::Debug + Send + Sync {
    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<()>;
}

impl Executor for Arc<dyn Executor> {
    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<()> {
        self.deref().spawn(f)
    }
}

#[derive(Clone)]
pub struct DefaultExecutor {
    sender: Sender<Option<Task<()>>>,
    receiver: Receiver<Option<Task<()>>>,
    threads: Arc<Mutex<Vec<ThreadHandle>>>,
    max_threads: usize,
}

impl DefaultExecutor {
    pub fn new(max_threads: usize) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        let threads = Default::default();
        Self {
            sender,
            receiver,
            threads,
            max_threads,
        }
    }

    pub(crate) fn maybe_spawn_thread(&self) -> Result<()> {
        let mut threads = self.threads.lock();
        let id = threads.len() + 1;
        if id <= self.max_threads {
            let receiver = self.receiver.clone();
            threads.push(ThreadHandle::new(
                ThreadBuilder::new()
                    .name(format!("executor {}", id))
                    .spawn(move || {
                        while let Ok(Some(task)) = receiver.recv() {
                            task.run();
                        }
                        Ok(())
                    })?,
            ));
        }
        Ok(())
    }
}

impl Default for DefaultExecutor {
    fn default() -> Self {
        Self::new(1)
    }
}

impl fmt::Debug for DefaultExecutor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DefaultExecutor")
            .field("max_threads", &self.max_threads)
            .finish()
    }
}

impl Executor for DefaultExecutor {
    fn spawn(&self, f: Pin<Box<dyn Future<Output = ()> + Send>>) -> Result<()> {
        self.maybe_spawn_thread()?;
        let sender = self.sender.clone();
        let schedule = move |task| sender.send(Some(task)).expect("executor failed");
        let (task, _) = async_task::spawn(f, schedule, ());
        task.schedule();
        Ok(())
    }
}

impl Drop for DefaultExecutor {
    fn drop(&mut self) {
        if let Some(threads) = self.threads.try_lock() {
            for _ in threads.iter() {
                let _ = self.sender.send(None);
            }
            for thread in threads.iter() {
                let _ = thread.wait("executor");
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::{mem, ptr};
use libc;

use c;
use low;

type FfiType_      = *mut low::ffi_type;
type FfiTypeArray_ = *mut FfiType_;

#[derive(Debug)]
pub struct FfiType(FfiType_);

#[derive(Debug)]
pub struct FfiTypeArray {
    ptr: FfiTypeArray_,
    len: usize,
}

/// Computes the length of a raw `FfiTypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: FfiTypeArray_) -> usize {
    let mut current = array;
    let mut count   = 0;
    while !(*current).is_null() {
        count += 1;
    }
    count
}

unsafe fn ffi_type_array_create_empty(size: usize) -> FfiTypeArray_ {
    let array = libc::malloc((size + 1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;
    *array.offset(size as isize) = ptr::null::<low::ffi_type>() as FfiType_;
    array
}

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>) -> FfiTypeArray_ {
    let size  = elements.len();
    let array = ffi_type_array_create_empty(size);
    for i in 0 .. size {
        *array.offset(i as isize) = elements[i].0;
    }

    for t in elements {
        mem::forget(t);
    }

    println!("ffi_type_array_create(...) = {:?}", array);

    array
}

unsafe fn ffi_type_struct_create_raw(elements: FfiTypeArray_) -> FfiType_ {
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as FfiType_;

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = c::ffi_type_enum::STRUCT as ::libc::c_ushort;
    (*new).elements  = elements;

    println!("ffi_type_struct_create_raw({:?}) = {:?}", elements, new);

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> FfiType_ {
    println!("ffi_type_array_create({:?})", elements);
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

unsafe fn ffi_type_array_clone(ffi_types: FfiTypeArray_) -> FfiTypeArray_ {
    let size = ffi_type_array_len(ffi_types);
    let new   = ffi_type_array_create_empty(size);

    for i in 0 .. size {
        *new.offset(i as isize) = ffi_type_clone(*ffi_types.offset(i as isize));
    }

    new
}

unsafe fn ffi_type_clone(old: FfiType_) -> FfiType_ {
    if (*old).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys an array of FfiType_ and all of its elements.
unsafe fn ffi_type_array_destroy(ffi_types: FfiTypeArray_) {
    println!("ffi_type_array_destroy({:?})", ffi_types);
    let mut current = ffi_types;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(ffi_types as *mut libc::c_void);
}

/// Destroys an FfiType_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(ffi_type: FfiType_) {
    println!("ffi_type_destroy({:?})", ffi_type);
    if (*ffi_type).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_array_destroy((*ffi_type).elements);
        libc::free(ffi_type as *mut libc::c_void);
    }
}

impl Drop for FfiType {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0) }
    }
}

impl Drop for FfiTypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.ptr) }
    }
}

impl FfiType {
    pub fn void() -> Self {
        FfiType(unsafe { &mut low::ffi_type_void })
    }

    pub fn uint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint8 })
    }

    pub fn sint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint8 })
    }

    pub fn uint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint16 })
    }

    pub fn sint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint16 })
    }

    pub fn uint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint32 })
    }

    pub fn sint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint32 })
    }

    pub fn uint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint64 })
    }

    pub fn sint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint64 })
    }

    pub fn float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_float })
    }

    pub fn double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_double })
    }

    pub fn pointer() -> Self {
        FfiType(unsafe { &mut low::ffi_type_pointer })
    }

    pub fn longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_longdouble })
    }

    pub fn complex_float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_float })
    }

    pub fn complex_double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_double })
    }

    pub fn complex_longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_longdouble })
    }

    pub fn structure(fields: Vec<FfiType>) -> Self {
        println!("FfiType::structure({:?})", fields);
        unsafe {
            FfiType(ffi_type_struct_create(fields))
        }
    }

    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        self.0
    }
}

impl FfiTypeArray {
    pub fn new(types: Vec<FfiType>) -> Self {
        let len = types.len();
        unsafe {
            FfiTypeArray {
                ptr: ffi_type_array_create(types),
                len: len,
            }
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        self.ptr
    }
}

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

    #[test]
    fn create_uint64() {
        FfiType::uint64();
    }

    #[test]
    fn create_struct() {
        FfiType::structure(vec![FfiType::sint64(),
                                FfiType::sint64(),
                                FfiType::uint64()]);
    }

}
<commit_msg>renaming to reflect usages<commit_after>use std::{mem, ptr};
use libc;

use c;
use low;

type FfiType_      = *mut low::ffi_type;
type FfiTypeArray_ = *mut FfiType_;

#[derive(Debug)]
pub struct FfiType(FfiType_);

#[derive(Debug)]
pub struct FfiTypeArray {
    ptr: FfiTypeArray_,
    len: usize,
}

/// Computes the length of a raw `FfiTypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: FfiTypeArray_) -> usize {
    let mut current = array;
    let mut count   = 0;
    while !(*current).is_null() {
        count += 1;
    }
    count
}

/// Creates an empty `FfiTypeArray_` with null terminator.
unsafe fn ffi_type_array_create_empty(len: usize) -> FfiTypeArray_ {
    let array = libc::malloc((len + 1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;
    *array.offset(len as isize) = ptr::null::<low::ffi_type>() as FfiType_;
    array
}

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>) -> FfiTypeArray_ {
    let size = elements.len();
    let new  = ffi_type_array_create_empty(size);
    for i in 0 .. size {
        *new.offset(i as isize) = elements[i].0;
    }

    for t in elements {
        mem::forget(t);
    }

    println!("ffi_type_array_create(...) = {:?}", new);

    new
}

unsafe fn ffi_type_struct_create_raw(elements: FfiTypeArray_) -> FfiType_ {
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as FfiType_;

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = c::ffi_type_enum::STRUCT as ::libc::c_ushort;
    (*new).elements  = elements;

    println!("ffi_type_struct_create_raw({:?}) = {:?}", elements, new);

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> FfiType_ {
    println!("ffi_type_array_create({:?})", elements);
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

unsafe fn ffi_type_array_clone(old: FfiTypeArray_) -> FfiTypeArray_ {
    let size = ffi_type_array_len(old);
    let new   = ffi_type_array_create_empty(size);

    for i in 0 .. size {
        *new.offset(i as isize) = ffi_type_clone(*old.offset(i as isize));
    }

    new
}

unsafe fn ffi_type_clone(old: FfiType_) -> FfiType_ {
    if (*old).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys an array of FfiType_ and all of its elements.
unsafe fn ffi_type_array_destroy(victim: FfiTypeArray_) {
    println!("ffi_type_array_destroy({:?})", victim);
    let mut current = victim;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(victim as *mut libc::c_void);
}

/// Destroys an FfiType_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(victim: FfiType_) {
    println!("ffi_type_destroy({:?})", victim);
    if (*victim).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_array_destroy((*victim).elements);
        libc::free(victim as *mut libc::c_void);
    }
}

impl Drop for FfiType {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0) }
    }
}

impl Drop for FfiTypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.ptr) }
    }
}

impl FfiType {
    pub fn void() -> Self {
        FfiType(unsafe { &mut low::ffi_type_void })
    }

    pub fn uint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint8 })
    }

    pub fn sint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint8 })
    }

    pub fn uint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint16 })
    }

    pub fn sint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint16 })
    }

    pub fn uint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint32 })
    }

    pub fn sint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint32 })
    }

    pub fn uint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint64 })
    }

    pub fn sint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint64 })
    }

    pub fn float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_float })
    }

    pub fn double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_double })
    }

    pub fn pointer() -> Self {
        FfiType(unsafe { &mut low::ffi_type_pointer })
    }

    pub fn longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_longdouble })
    }

    pub fn complex_float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_float })
    }

    pub fn complex_double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_double })
    }

    pub fn complex_longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_longdouble })
    }

    pub fn structure(fields: Vec<FfiType>) -> Self {
        println!("FfiType::structure({:?})", fields);
        unsafe {
            FfiType(ffi_type_struct_create(fields))
        }
    }

    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        self.0
    }
}

impl FfiTypeArray {
    pub fn new(types: Vec<FfiType>) -> Self {
        let len = types.len();
        unsafe {
            FfiTypeArray {
                ptr: ffi_type_array_create(types),
                len: len,
            }
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        self.ptr
    }
}

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

    #[test]
    fn create_uint64() {
        FfiType::uint64();
    }

    #[test]
    fn create_struct() {
        FfiType::structure(vec![FfiType::sint64(),
                                FfiType::sint64(),
                                FfiType::uint64()]);
    }

}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use gl;
use gl::types::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::sync::{Once, ONCE_INIT, RwLock};

use command;
use dl;
use encode;
use errors::*;
use function::Function;
use sdl;

lazy_static!{
    pub static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
    static ref CAPTURING: RwLock<bool> = RwLock::new(false);
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
    GL_EndRendering: Function<unsafe extern "C" fn()>,
    VideoMode_GetCurrentVideoMode: Function<unsafe extern "C" fn(*mut c_int,
                                                                 *mut c_int,
                                                                 *mut c_int)>,

    s_BackBufferFBO: Option<*mut FBO_Container_t>,
}

// TODO: think about how to deal with unsafety here.
// The compiler complaining about *mut not being Send/Sync is perfectly valid here.
// Our safe RwLock cannot guarantee there isn't some game thread accessing the values
// at the same time. Although reading/writing to a pointer is already unsafe?
unsafe impl Send for Pointers {}
unsafe impl Sync for Pointers {}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct FBO_Container_t {
    s_hBackBufferFBO: GLuint,
    s_hBackBufferCB: GLuint,
    s_hBackBufferDB: GLuint,
    s_hBackBufferTex: GLuint,
}

/// The "main" function of hw.so, called inside `CEngineAPI::Run()`.
///
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: `_restart` also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub unsafe extern "C" fn RunListenServer(instance: *mut c_void,
                                         basedir: *mut c_char,
                                         cmdline: *mut c_char,
                                         postRestartCmdLineArgs: *mut c_char,
                                         launcherFactory: *mut c_void,
                                         filesystemFactory: *mut c_void)
                                         -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    // Initialize the encoding.
    {
        static INIT: Once = ONCE_INIT;
        INIT.call_once(|| if let Err(ref e) = encode::initialize()
                              .chain_err(|| "error initializing encoding") {
                           panic!("{}", e.display());
                       });
    }

    let rv = real!(RunListenServer)(instance,
                                    basedir,
                                    cmdline,
                                    postRestartCmdLineArgs,
                                    launcherFactory,
                                    filesystemFactory);

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// Initializes the hunk memory.
///
/// After the hunk memory has been initialized we can register console commands and variables.
/// It's also a good place to get OpenGL function pointers.
#[no_mangle]
pub unsafe extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    real!(Memory_Init)(buf, size);

    register_cvars_and_commands();

    gl::ReadPixels::load_with(|s| sdl::get_proc_address(s) as _);
    con_print(&format!("gl::ReadPixels::is_loaded() = {}", gl::ReadPixels::is_loaded()));
}

/// Blits pixels from the framebuffer to screen and flips.
///
/// If framebuffers aren't used, simply flips the screen.
#[no_mangle]
pub unsafe extern "C" fn GL_EndRendering() {
    if *CAPTURING.read().unwrap() {
        let (w, h) = get_resolution();
        let buf = encode::get_buffer((w, h));
        gl::ReadPixels(0, 0, w as GLsizei, h as GLsizei,
                       gl::RGBA, gl::UNSIGNED_BYTE,
                       buf.as_mut_ptr() as _);
    }

    real!(GL_EndRendering)();

    // TODO: check if we're called from SCR_UpdateScreen().

    // println!("s_BackBufferFBO: {:?}", *POINTERS.read().unwrap().s_BackBufferFBO.unwrap());
}

/// Obtains and stores all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
        find!(pointers, hw, GL_EndRendering, "GL_EndRendering");
        find!(pointers, hw, VideoMode_GetCurrentVideoMode, "VideoMode_GetCurrentVideoMode");

        pointers.s_BackBufferFBO = Some(hw.sym("s_BackBufferFBO")
                .chain_err(|| "couldn't find s_BackBufferFBO")? as _);
    }

    Ok(())
}

/// Resets all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Registers console commands and variables.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.read().unwrap().iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Registers a console command.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: unsafe extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Prints the given string to the game console.
///
/// `string` must not contain null bytes.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Gets the console command argument count.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Gets a console command argument.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    CStr::from_ptr(arg).to_string_lossy().into_owned()
}

/// Returns the current game resolution.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn get_resolution() -> (u32, u32) {
    let mut width = mem::uninitialized();
    let mut height = mem::uninitialized();

    real!(VideoMode_GetCurrentVideoMode)(&mut width, &mut height, ptr::null_mut());

    width = cmp::max(0, width);
    height = cmp::max(0, height);

    (width as u32, height as u32)
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});

command!(cap_start, |engine| {
    *CAPTURING.write().unwrap() = true;
});

command!(cap_stop, |engine| {
    *CAPTURING.write().unwrap() = false;
});
<commit_msg>Fix getting the game resolution<commit_after>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use gl;
use gl::types::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::sync::{Once, ONCE_INIT, RwLock};

use command;
use dl;
use encode;
use errors::*;
use function::Function;
use sdl;

lazy_static!{
    pub static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
    static ref CAPTURING: RwLock<bool> = RwLock::new(false);
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
    GL_EndRendering: Function<unsafe extern "C" fn()>,
    VideoMode_GetCurrentVideoMode: Function<unsafe extern "C" fn(*mut c_int,
                                                                 *mut c_int,
                                                                 *mut c_int)>,
    VideoMode_IsWindowed: Function<unsafe extern "C" fn() -> c_int>,

    window_rect: Option<*mut RECT>,
    s_BackBufferFBO: Option<*mut FBO_Container_t>,
}

// TODO: think about how to deal with unsafety here.
// The compiler complaining about *mut not being Send/Sync is perfectly valid here.
// Our safe RwLock cannot guarantee there isn't some game thread accessing the values
// at the same time. Although reading/writing to a pointer is already unsafe?
unsafe impl Send for Pointers {}
unsafe impl Sync for Pointers {}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct RECT {
    left: c_int,
    right: c_int,
    top: c_int,
    bottom: c_int,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct FBO_Container_t {
    s_hBackBufferFBO: GLuint,
    s_hBackBufferCB: GLuint,
    s_hBackBufferDB: GLuint,
    s_hBackBufferTex: GLuint,
}

/// The "main" function of hw.so, called inside `CEngineAPI::Run()`.
///
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: `_restart` also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub unsafe extern "C" fn RunListenServer(instance: *mut c_void,
                                         basedir: *mut c_char,
                                         cmdline: *mut c_char,
                                         postRestartCmdLineArgs: *mut c_char,
                                         launcherFactory: *mut c_void,
                                         filesystemFactory: *mut c_void)
                                         -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    // Initialize the encoding.
    {
        static INIT: Once = ONCE_INIT;
        INIT.call_once(|| if let Err(ref e) = encode::initialize()
                              .chain_err(|| "error initializing encoding") {
                           panic!("{}", e.display());
                       });
    }

    let rv = real!(RunListenServer)(instance,
                                    basedir,
                                    cmdline,
                                    postRestartCmdLineArgs,
                                    launcherFactory,
                                    filesystemFactory);

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// Initializes the hunk memory.
///
/// After the hunk memory has been initialized we can register console commands and variables.
/// It's also a good place to get OpenGL function pointers.
#[no_mangle]
pub unsafe extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    real!(Memory_Init)(buf, size);

    register_cvars_and_commands();

    gl::ReadPixels::load_with(|s| sdl::get_proc_address(s) as _);
    con_print(&format!("gl::ReadPixels::is_loaded() = {}", gl::ReadPixels::is_loaded()));
}

/// Blits pixels from the framebuffer to screen and flips.
///
/// If framebuffers aren't used, simply flips the screen.
#[no_mangle]
pub unsafe extern "C" fn GL_EndRendering() {
    let (w, h) = get_resolution();
    let buf = encode::get_buffer((w, h));

    if *CAPTURING.read().unwrap() {
        gl::ReadPixels(0, 0, w as GLsizei, h as GLsizei,
                       gl::RGBA, gl::UNSIGNED_BYTE,
                       buf.as_mut_ptr() as _);
    }

    real!(GL_EndRendering)();

    // TODO: check if we're called from SCR_UpdateScreen().

    // println!("s_BackBufferFBO: {:?}", *POINTERS.read().unwrap().s_BackBufferFBO.unwrap());
}

/// Obtains and stores all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
        find!(pointers, hw, GL_EndRendering, "GL_EndRendering");
        find!(pointers, hw, VideoMode_GetCurrentVideoMode, "VideoMode_GetCurrentVideoMode");
        find!(pointers, hw, VideoMode_IsWindowed, "VideoMode_IsWindowed");

        pointers.window_rect = Some(hw.sym("window_rect")
                .chain_err(|| "couldn't find window_rect")? as _);
        pointers.s_BackBufferFBO = Some(hw.sym("s_BackBufferFBO")
                .chain_err(|| "couldn't find s_BackBufferFBO")? as _);
    }

    Ok(())
}

/// Resets all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Registers console commands and variables.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.read().unwrap().iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Registers a console command.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: unsafe extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Prints the given string to the game console.
///
/// `string` must not contain null bytes.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Gets the console command argument count.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Gets a console command argument.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    CStr::from_ptr(arg).to_string_lossy().into_owned()
}

/// Returns the current game resolution.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn get_resolution() -> (u32, u32) {
    let mut width;
    let mut height;

    if real!(VideoMode_IsWindowed)() != 0 {
        let window_rect = *POINTERS.read().unwrap().window_rect.unwrap();
        width = window_rect.right - window_rect.left;
        height = window_rect.bottom - window_rect.top;
    } else {
        width = mem::uninitialized();
        height = mem::uninitialized();
        real!(VideoMode_GetCurrentVideoMode)(&mut width, &mut height, ptr::null_mut());
    }

    width = cmp::max(0, width);
    height = cmp::max(0, height);

    (width as u32, height as u32)
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});

command!(cap_start, |engine| {
    *CAPTURING.write().unwrap() = true;
});

command!(cap_stop, |engine| {
    *CAPTURING.write().unwrap() = false;
});
<|endoftext|>


<commit_before>use std::collections::{HashMap, VecDeque};
use libusb::{Context, DeviceHandle, Result as UsbResult, Error as UsbError};
use handle::{Handle, ControlPacket, ToControlPacket};
use color::*;
use keys::*;
use parser::*;
use event::Handler;

pub trait Keyboard {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()>;
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()>;
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()>;
}

pub struct KeyboardInternal<'a> {
    handle: Handle<'a>,
    control_packet_queue: VecDeque<ControlPacket>,
    sending_control: bool,
}

impl<'a> KeyboardInternal<'a> {
    pub fn new(handle: Handle<'a>) -> KeyboardInternal<'a> {
        KeyboardInternal {
            handle: handle,
            control_packet_queue: VecDeque::new(),
            sending_control: false,
        }
    }

    pub fn queue_control_packet(&mut self, packet: ControlPacket) -> UsbResult<()> {
        self.control_packet_queue.push_back(packet);
        if !self.sending_control {
            self.send_next_control()
        } else {
            Ok(())
        }
    }

    pub fn send_next_control(&mut self) -> UsbResult<()> {
        if self.control_packet_queue.len() == 0 {
            self.sending_control = false;
            return Ok(());
        }
        if !self.sending_control {
            self.sending_control = true;
        }
        self.handle.send_control(self.control_packet_queue.pop_front().unwrap())
    }

    fn send_color<T: KeyType>(&mut self, color_packet: ColorPacket<T>) -> UsbResult<()> {
        self.queue_control_packet(color_packet.to_control_packet())
    }

    fn flush_color(&mut self) -> UsbResult<()> {
        self.queue_control_packet(FlushPacket::new().to_control_packet())
    }
}

impl<'a> Keyboard for KeyboardInternal<'a> {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        let mut standard_packet = ColorPacket::new();
        let mut gaming_packet = ColorPacket::new();
        let mut logo_packet = ColorPacket::new();

        for key_color in key_colors {
            match key_color.key {
                Key::Standard(s) => {
                    match standard_packet.add(s, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Gaming(g) => {
                    match gaming_packet.add(g, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Logo(l) => {
                    match logo_packet.add(l, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Media(_) => return Err(UsbError::InvalidParam)
            }
        }
        if standard_packet.len() > 0 {
            try!(self.send_color(standard_packet));
        }
        if gaming_packet.len() > 0 {
            try!(self.send_color(gaming_packet));
        }
        if logo_packet.len() > 0 {
            try!(self.send_color(logo_packet));
        }
        self.flush_color()
    }

    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        let key_colors = vec![key_color];
        self.set_key_colors(key_colors)
    }

    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        let mut values = Key::values();
        let key_colors = values.drain(..)
            .filter(|k| match k {
                // we can't set the color of media keys
                &Key::Media(_) => false,
                _ => true
            }).map(|k| KeyColor::new(k, color.clone()))
            .collect();
        self.set_key_colors(key_colors)
    }
}

pub struct KeyboardImpl<'a> {
    keyboard_internal: KeyboardInternal<'a>,
    parser_index: u32,
    parsers: HashMap<u32, Parser>,
    handler_index: u32,
    handlers: HashMap<u32, Handler>,
}

impl<'a> KeyboardImpl<'a> {
    pub fn new(context: &'a Context, handle: &'a DeviceHandle<'a>) -> UsbResult<KeyboardImpl<'a>> {
        let mut keyboard = KeyboardImpl {
            keyboard_internal: KeyboardInternal::new(try!(Handle::new(context, handle))),
            parser_index: 0,
            parsers: HashMap::new(),
            handler_index: 0,
            handlers: HashMap::new(),
        };
        keyboard.add_parser(KeyParser::new().into());
        keyboard.add_parser(ControlParser::new().into());
        Ok(keyboard)
    }

    pub fn add_handler(&mut self, mut handler: Handler) -> UsbResult<u32> {
        match &mut handler {
            &mut Handler::HandleKey(ref mut handler) => try!(handler.init(self)),
        }
        let index = self.handler_index;
        self.handlers.insert(index, handler);
        self.handler_index += 1;
        Ok(index)
    }

    pub fn remove_handler(&mut self, index: u32) -> Option<Handler> {
        self.handlers.remove(&index)
    }

    fn add_parser(&mut self, parser: Parser) -> u32 {
        let index = self.parser_index;
        self.parsers.insert(index, parser);
        self.parser_index += 1;
        index
    }

    // FIXME: Currently unused, but maybe needed later
    //fn remove_parser(&mut self, index: u32) -> Option<Parser> {
        //self.parsers.remove(&index)
    //}

    fn handle(&mut self) -> UsbResult<()> {
        let (endpoint_direction, buf) = try!(self.keyboard_internal.handle.recv());
        let packet = Packet::new(endpoint_direction, &buf);
        let mut handled = false;
        let &mut KeyboardImpl {
            ref mut keyboard_internal,
            parser_index: _,
            ref mut parsers,
            handler_index: _,
            ref mut handlers,
        } = self;
        for (_, parser) in parsers.iter_mut() {
            match parser {
                &mut Parser::ParseKey(ref mut p) if p.accept(&packet) => {
                    let key_events = try!(p.parse(&packet, keyboard_internal));
                    for key_event in key_events {
                        for (_, handler) in handlers.iter_mut() {
                            match handler {
                                &mut Handler::HandleKey(ref mut h) if h.accept(&key_event) => {
                                    handled = true;
                                    try!(h.handle(&key_event, keyboard_internal));
                                },
                                _ => {}
                            }
                        }
                    }
                },
                &mut Parser::ParseControl(ref mut p) if p.accept(&packet) => {
                    handled = true;
                    try!(p.parse(&packet, keyboard_internal));
                },
                _ => {}
            }
        }
        if !handled {
            println!("Packet not handled: {:?}", packet);
        }
        Ok(())
    }

    pub fn start_handle_loop(&mut self) -> UsbResult<()> {
        loop {
            try!(self.handle());
        }
    }
}

impl<'a> Keyboard for KeyboardImpl<'a> {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        self.keyboard_internal.set_key_colors(key_colors)
    }
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        self.keyboard_internal.set_color(key_color)
    }
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        self.keyboard_internal.set_all_colors(color)
    }
}

<commit_msg>wip(keyboard): Add debug print for unparsed packets<commit_after>use std::collections::{HashMap, VecDeque};
use libusb::{Context, DeviceHandle, Result as UsbResult, Error as UsbError};
use handle::{Handle, ControlPacket, ToControlPacket};
use color::*;
use keys::*;
use parser::*;
use event::Handler;

pub trait Keyboard {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()>;
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()>;
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()>;
}

pub struct KeyboardInternal<'a> {
    handle: Handle<'a>,
    control_packet_queue: VecDeque<ControlPacket>,
    sending_control: bool,
}

impl<'a> KeyboardInternal<'a> {
    pub fn new(handle: Handle<'a>) -> KeyboardInternal<'a> {
        KeyboardInternal {
            handle: handle,
            control_packet_queue: VecDeque::new(),
            sending_control: false,
        }
    }

    pub fn queue_control_packet(&mut self, packet: ControlPacket) -> UsbResult<()> {
        self.control_packet_queue.push_back(packet);
        if !self.sending_control {
            self.send_next_control()
        } else {
            Ok(())
        }
    }

    pub fn send_next_control(&mut self) -> UsbResult<()> {
        if self.control_packet_queue.len() == 0 {
            self.sending_control = false;
            return Ok(());
        }
        if !self.sending_control {
            self.sending_control = true;
        }
        self.handle.send_control(self.control_packet_queue.pop_front().unwrap())
    }

    fn send_color<T: KeyType>(&mut self, color_packet: ColorPacket<T>) -> UsbResult<()> {
        self.queue_control_packet(color_packet.to_control_packet())
    }

    fn flush_color(&mut self) -> UsbResult<()> {
        self.queue_control_packet(FlushPacket::new().to_control_packet())
    }
}

impl<'a> Keyboard for KeyboardInternal<'a> {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        let mut standard_packet = ColorPacket::new();
        let mut gaming_packet = ColorPacket::new();
        let mut logo_packet = ColorPacket::new();

        for key_color in key_colors {
            match key_color.key {
                Key::Standard(s) => {
                    match standard_packet.add(s, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Gaming(g) => {
                    match gaming_packet.add(g, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Logo(l) => {
                    match logo_packet.add(l, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Media(_) => return Err(UsbError::InvalidParam)
            }
        }
        if standard_packet.len() > 0 {
            try!(self.send_color(standard_packet));
        }
        if gaming_packet.len() > 0 {
            try!(self.send_color(gaming_packet));
        }
        if logo_packet.len() > 0 {
            try!(self.send_color(logo_packet));
        }
        self.flush_color()
    }

    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        let key_colors = vec![key_color];
        self.set_key_colors(key_colors)
    }

    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        let mut values = Key::values();
        let key_colors = values.drain(..)
            .filter(|k| match k {
                // we can't set the color of media keys
                &Key::Media(_) => false,
                _ => true
            }).map(|k| KeyColor::new(k, color.clone()))
            .collect();
        self.set_key_colors(key_colors)
    }
}

pub struct KeyboardImpl<'a> {
    keyboard_internal: KeyboardInternal<'a>,
    parser_index: u32,
    parsers: HashMap<u32, Parser>,
    handler_index: u32,
    handlers: HashMap<u32, Handler>,
}

impl<'a> KeyboardImpl<'a> {
    pub fn new(context: &'a Context, handle: &'a DeviceHandle<'a>) -> UsbResult<KeyboardImpl<'a>> {
        let mut keyboard = KeyboardImpl {
            keyboard_internal: KeyboardInternal::new(try!(Handle::new(context, handle))),
            parser_index: 0,
            parsers: HashMap::new(),
            handler_index: 0,
            handlers: HashMap::new(),
        };
        keyboard.add_parser(KeyParser::new().into());
        keyboard.add_parser(ControlParser::new().into());
        Ok(keyboard)
    }

    pub fn add_handler(&mut self, mut handler: Handler) -> UsbResult<u32> {
        match &mut handler {
            &mut Handler::HandleKey(ref mut handler) => try!(handler.init(self)),
        }
        let index = self.handler_index;
        self.handlers.insert(index, handler);
        self.handler_index += 1;
        Ok(index)
    }

    pub fn remove_handler(&mut self, index: u32) -> Option<Handler> {
        self.handlers.remove(&index)
    }

    fn add_parser(&mut self, parser: Parser) -> u32 {
        let index = self.parser_index;
        self.parsers.insert(index, parser);
        self.parser_index += 1;
        index
    }

    // FIXME: Currently unused, but maybe needed later
    //fn remove_parser(&mut self, index: u32) -> Option<Parser> {
        //self.parsers.remove(&index)
    //}

    fn handle(&mut self) -> UsbResult<()> {
        let (endpoint_direction, buf) = try!(self.keyboard_internal.handle.recv());
        let packet = Packet::new(endpoint_direction, &buf);
        let mut handled = false;
        let mut parsed = false;
        let &mut KeyboardImpl {
            ref mut keyboard_internal,
            parser_index: _,
            ref mut parsers,
            handler_index: _,
            ref mut handlers,
        } = self;
        for (_, parser) in parsers.iter_mut() {
            match parser {
                &mut Parser::ParseKey(ref mut p) if p.accept(&packet) => {
                    parsed = true;
                    let key_events = try!(p.parse(&packet, keyboard_internal));
                    for key_event in key_events {
                        for (_, handler) in handlers.iter_mut() {
                            match handler {
                                &mut Handler::HandleKey(ref mut h) if h.accept(&key_event) => {
                                    handled = true;
                                    try!(h.handle(&key_event, keyboard_internal));
                                },
                                _ => {}
                            }
                        }
                    }
                },
                &mut Parser::ParseControl(ref mut p) if p.accept(&packet) => {
                    parsed = true;
                    handled = true;
                    try!(p.parse(&packet, keyboard_internal));
                },
                _ => {}
            }
        }
        if !parsed {
            println!("Packet not parsed: {:?}", packet);
        } else if !handled {
            println!("Packet not handled: {:?}", packet);
        }
        Ok(())
    }

    pub fn start_handle_loop(&mut self) -> UsbResult<()> {
        loop {
            try!(self.handle());
        }
    }
}

impl<'a> Keyboard for KeyboardImpl<'a> {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        self.keyboard_internal.set_key_colors(key_colors)
    }
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        self.keyboard_internal.set_color(key_color)
    }
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        self.keyboard_internal.set_all_colors(color)
    }
}

<|endoftext|>


<commit_before>//!
//! A convenient structure to store and load settings.
//!
//! It is meant for items that are rarely read and stored, like command line flags or
//! application configuration.
//!
//! knob::Settings expects all values to implement ToStr + FromStr and stores them as
//! strings internally. This allows sideloading of settings through multiple means, e.g.
//! the command line or a simple config file. knob is not meant for structured data. If
//! you want to load such data, store the location of the data as a Knob setting and do
//! the loading parsing yourself.
//!
//! knob is typesafe in a sense that it will return you the type you wanted back if possible and
//! fails otherwise.
//!
//! knob allows you to decorate the Settings structure yourself for convenience (see examples).
//!
//! # Storing and fetching values
//!
//! The following example shows you how to store an ip in knob:
//!
//! ~~~{.rust}
//! extern mod knob;
//! use knob::*;
//! use std::rt::io::net::ip::IpAddr;
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set("ip", "0.0.0.0:4567");
//!   let socket: IpAddr = settings.socket();
//!   assert_eq!(socket.to_str(), ~"0.0.0.0:4567")
//! }
//! ~~~
//!
//! This works the same for IPv6 addresses:
//!
//! ~~~{.rust}
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set("ip", "::0.0.0.1");
//!   let socket: IpAddr = settings.fetch("ip");
//!   assert_eq!(socket.to_str(), ~"::0.0.0.1")
//! }
//! ~~~
//!
//! # Providing your own keys
//!
//! You can use enums as keys, as long as they implement ToStr:
//!
//! ~~~{.rust}
//! enum Keys {
//!   Port,
//!   Ip,
//!   Addr,
//! }
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set(Ip, "::0.0.0.1");
//!   let socket: IpAddr = settings.fetch(Ip);
//!   assert_eq!(socket.to_str(), ~"::0.0.0.1")
//! }
//! ~~~
//!
//! # Registering command line options
//!
//! Knob allows you to register command line options to read from the command line later.
//!
//! The options are getopts option groups.
//!
//! If the loading of the command line args fails, an error will be returned.
//!
//! ~~~{.rust}
//! use extra::getopts::groups::*;
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.opt(optopt("p", "port", "the port to bind to", "4000"))
//!   settings.opt(reqopt("e", "environment", "the environment to run in", ""));;
//!   let errors = settings.load_os_args();
//!   if errors.is_some() {
//!     println(settings.usage("Try one of these:"))
//!   }
//! }
//! ~~~
//!
//! # Decorating the settings struct
//!
//! To make matters more convenient, you can implement a decorator
//! to implement your own loading behaviour.
//!
//! ~~~{.rust}
//! enum Keys {
//!   Port,
//!   Ip,
//!   Addr,
//! }
//!
//! pub trait SocketSettings {
//!   fn socket(&self) -> SocketAddr;
//!   fn port(&self) -> u16;
//!   fn ip(&self) -> IpAddr;
//! }
//!
//! impl SocketSettings for Settings {
//!   fn socket(&self) -> SocketAddr {
//!     do self.fetch_with(Addr) |addr| {
//!       match addr {
//!         Some(socket_addr) => { socket_addr },
//!         None => {
//!           let port: u16 = self.port();
//!           let ip: IpAddr = self.ip();
//!           SocketAddr { ip: ip, port: port }
//!         }
//!       }
//!     }
//!   }
//!
//!   fn port(&self) -> u16 {
//!     self.fetch(Port).unwrap_or(8080)
//!   }
//!
//!   fn ip(&self) -> IpAddr {
//!     self.fetch(Ip).unwrap_or(Ipv4Addr(127,0,0,1))
//!   }
//! }
//! enum Keys {
//!   Port,
//!   Ip,
//! }
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set(Ip, "::0.0.0.1");
//!   let socket: IpAddr = settings.ip();
//!   assert_eq!(socket.to_str(), ~"::0.0.0.1")
//! }
//! ~~~
//!
//! knob goes up to 11.

#[crate_id = "knob#1.0.1"];

#[crate_type = "lib"];
#[comment = "A convenient Rust settings system"];
#[license = "MIT"];

extern mod extra;

use std::hashmap::HashMap;
use std::os;

use extra::getopts::groups::{OptGroup,getopts,usage};
use extra::getopts::Fail_;

/// The settings structure we save the options and settings in.
#[deriving(Clone)]
pub struct Settings {
  priv store: HashMap<~str,~str>,
  priv options: ~[OptGroup],
}

impl Settings {
  /// Create a new Settings struct.
  pub fn new() -> Settings {
    Settings { store: HashMap::new(), options: ~[] }
  }

  /// Set a settings key to a value. The value will be serialized.
  pub fn set<A: ToStr, T: ToStr>(&mut self, setting: A, value: T) {
    self.store.swap(setting.to_str(), value.to_str());
  }

  /// Set a value using an Option struct. The value will only be set if the
  /// Some value is given. This way, you can avoid unwrapping the result of a
  /// previous operation by yourself.
  pub fn set_opt<A: ToStr, T: ToStr>(&mut self, setting: A, value: Option<T>) {
    if !value.is_none() {
      self.store.swap(setting.to_str(), value.unwrap().to_str());
    }
  }

  /// Fetch a setting for a key. Fails if the setting is present but could not be
  /// parsed.
  pub fn fetch<A: ToStr, T: FromStr>(&self, setting: A) -> Option<T> {
    match self.store.find(&setting.to_str()) {
      Some(string) => {
        let value = from_str(string.to_owned());
        if value.is_none() {
          fail!("setting could not be parsed:" + setting.to_str())
        }
        value
      },
      None => { None }
    }
  }

  /// Fetch a setting for a key and pass it to given function. The result of the function
  /// will be returned.
  pub fn fetch_with<A: ToStr, T: FromStr>(&self, setting: A, f: |Option<T>| -> T) -> T {
    let value = self.fetch(setting.to_str());
    f(value)
  }

  /// Register a commandline for laster use with load_args.
  ///
  /// Currently, only optopt and reqopt are properly supported.
  pub fn opt(&mut self, opt: OptGroup) {
    self.options.push(opt);
  }

  /// Load the command line argument given by the OS.
  ///
  /// Optionally returns failures.
  pub fn load_os_args(&mut self) -> Option<Fail_> {
    let args = os::args();
    self.load_args(args)
  }

  /// Load a list of command line arguments.
  ///
  /// Automatically sets "knob.progname" to the name of the program.
  ///
  /// Optionally returns failures.
  pub fn load_args(&mut self, args: ~[~str]) -> Option<Fail_> {
    let ref prog_name = args[0];

    self.set("knob.progname", prog_name.clone());

    let matches = match getopts(args.tail(), self.options) {
      Ok(m) => { m }
      Err(fail) => { return Some(fail) }
    };

    let given_options = self.options.clone();
    for opt in given_options.iter() {
      let opt_strings = &[opt.short_name.clone(), opt.long_name.clone()];
      self.set_opt(opt.long_name.clone(), matches.opts_str(opt_strings))
    };
    None
  }

  /// Returns the usage string for the stored OptGroups. Pass `brief`
  /// to have it included.
  pub fn usage(&self, brief: &str) -> ~str {
    usage(brief, self.options)
  }
}

<commit_msg>Port to rust 0.10.pre<commit_after>//!
//! A convenient structure to store and load settings.
//!
//! It is meant for items that are rarely read and stored, like command line flags or
//! application configuration.
//!
//! knob::Settings expects all values to implement ToStr + FromStr and stores them as
//! strings internally. This allows sideloading of settings through multiple means, e.g.
//! the command line or a simple config file. knob is not meant for structured data. If
//! you want to load such data, store the location of the data as a Knob setting and do
//! the loading parsing yourself.
//!
//! knob is typesafe in a sense that it will return you the type you wanted back if possible and
//! fails otherwise.
//!
//! knob allows you to decorate the Settings structure yourself for convenience (see examples).
//!
//! # Storing and fetching values
//!
//! The following example shows you how to store an ip in knob:
//!
//! ~~~{.rust}
//! extern crate knob;
//! use knob::*;
//! use std::rt::io::net::ip::IpAddr;
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set("ip", "0.0.0.0:4567");
//!   let socket: IpAddr = settings.socket();
//!   assert_eq!(socket.to_str(), ~"0.0.0.0:4567")
//! }
//! ~~~
//!
//! This works the same for IPv6 addresses:
//!
//! ~~~{.rust}
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set("ip", "::0.0.0.1");
//!   let socket: IpAddr = settings.fetch("ip");
//!   assert_eq!(socket.to_str(), ~"::0.0.0.1")
//! }
//! ~~~
//!
//! # Providing your own keys
//!
//! You can use enums as keys, as long as they implement ToStr:
//!
//! ~~~{.rust}
//! enum Keys {
//!   Port,
//!   Ip,
//!   Addr,
//! }
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set(Ip, "::0.0.0.1");
//!   let socket: IpAddr = settings.fetch(Ip);
//!   assert_eq!(socket.to_str(), ~"::0.0.0.1")
//! }
//! ~~~
//!
//! # Registering command line options
//!
//! Knob allows you to register command line options to read from the command line later.
//!
//! The options are getopts option groups.
//!
//! If the loading of the command line args fails, an error will be returned.
//!
//! ~~~{.rust}
//! use extra::getopts::groups::*;
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.opt(optopt("p", "port", "the port to bind to", "4000"))
//!   settings.opt(reqopt("e", "environment", "the environment to run in", ""));;
//!   let errors = settings.load_os_args();
//!   if errors.is_some() {
//!     println(settings.usage("Try one of these:"))
//!   }
//! }
//! ~~~
//!
//! # Decorating the settings struct
//!
//! To make matters more convenient, you can implement a decorator
//! to implement your own loading behaviour.
//!
//! ~~~{.rust}
//! enum Keys {
//!   Port,
//!   Ip,
//!   Addr,
//! }
//!
//! pub trait SocketSettings {
//!   fn socket(&self) -> SocketAddr;
//!   fn port(&self) -> u16;
//!   fn ip(&self) -> IpAddr;
//! }
//!
//! impl SocketSettings for Settings {
//!   fn socket(&self) -> SocketAddr {
//!     do self.fetch_with(Addr) |addr| {
//!       match addr {
//!         Some(socket_addr) => { socket_addr },
//!         None => {
//!           let port: u16 = self.port();
//!           let ip: IpAddr = self.ip();
//!           SocketAddr { ip: ip, port: port }
//!         }
//!       }
//!     }
//!   }
//!
//!   fn port(&self) -> u16 {
//!     self.fetch(Port).unwrap_or(8080)
//!   }
//!
//!   fn ip(&self) -> IpAddr {
//!     self.fetch(Ip).unwrap_or(Ipv4Addr(127,0,0,1))
//!   }
//! }
//! enum Keys {
//!   Port,
//!   Ip,
//! }
//!
//! fn main() {
//!   let settings = Settings::new();
//!   settings.set(Ip, "::0.0.0.1");
//!   let socket: IpAddr = settings.ip();
//!   assert_eq!(socket.to_str(), ~"::0.0.0.1")
//! }
//! ~~~
//!
//! knob goes up to 11.

#[crate_id = "knob#1.0.1"];

#[crate_type = "lib"];
#[comment = "A convenient Rust settings system"];
#[license = "MIT"];

extern crate extra;
extern crate getopts;

use std::hashmap::HashMap;
use std::os;

use getopts::{usage,getopts,OptGroup};
use getopts::Fail_;

/// The settings structure we save the options and settings in.
#[deriving(Clone)]
pub struct Settings {
  priv store: HashMap<~str,~str>,
  priv options: ~[OptGroup],
}

impl Settings {
  /// Create a new Settings struct.
  pub fn new() -> Settings {
    Settings { store: HashMap::new(), options: ~[] }
  }

  /// Set a settings key to a value. The value will be serialized.
  pub fn set<A: ToStr, T: ToStr>(&mut self, setting: A, value: T) {
    self.store.swap(setting.to_str(), value.to_str());
  }

  /// Set a value using an Option struct. The value will only be set if the
  /// Some value is given. This way, you can avoid unwrapping the result of a
  /// previous operation by yourself.
  pub fn set_opt<A: ToStr, T: ToStr>(&mut self, setting: A, value: Option<T>) {
    if !value.is_none() {
      self.store.swap(setting.to_str(), value.unwrap().to_str());
    }
  }

  /// Fetch a setting for a key. Fails if the setting is present but could not be
  /// parsed.
  pub fn fetch<A: ToStr, T: FromStr>(&self, setting: A) -> Option<T> {
    match self.store.find(&setting.to_str()) {
      Some(string) => {
        let value = from_str(string.to_owned());
        if value.is_none() {
          fail!("setting could not be parsed:" + setting.to_str())
        }
        value
      },
      None => { None }
    }
  }

  /// Fetch a setting for a key and pass it to given function. The result of the function
  /// will be returned.
  pub fn fetch_with<A: ToStr, T: FromStr>(&self, setting: A, f: |Option<T>| -> T) -> T {
    let value = self.fetch(setting.to_str());
    f(value)
  }

  /// Register a commandline for laster use with load_args.
  ///
  /// Currently, only optopt and reqopt are properly supported.
  pub fn opt(&mut self, opt: OptGroup) {
    self.options.push(opt);
  }

  /// Load the command line argument given by the OS.
  ///
  /// Optionally returns failures.
  pub fn load_os_args(&mut self) -> Option<Fail_> {
    let args = os::args();
    self.load_args(args)
  }

  /// Load a list of command line arguments.
  ///
  /// Automatically sets "knob.progname" to the name of the program.
  ///
  /// Optionally returns failures.
  pub fn load_args(&mut self, args: ~[~str]) -> Option<Fail_> {
    let ref prog_name = args[0];

    self.set("knob.progname", prog_name.clone());

    let matches = match getopts(args.tail(), self.options) {
      Ok(m) => { m }
      Err(fail) => { return Some(fail) }
    };

    let given_options = self.options.clone();
    for opt in given_options.iter() {
      let opt_strings = &[opt.short_name.clone(), opt.long_name.clone()];
      self.set_opt(opt.long_name.clone(), matches.opts_str(opt_strings))
    };
    None
  }

  /// Returns the usage string for the stored OptGroups. Pass `brief`
  /// to have it included.
  pub fn usage(&self, brief: &str) -> ~str {
    usage(brief, self.options)
  }
}

<|endoftext|>


<commit_before>// TODO: drop all panic!

use std::mem;
use std::raw;
use std::fmt;
use std::default::Default;
use std::intrinsics::TypeId;

use clear::Clear;
use reflect::MessageDescriptor;
use reflect::EnumDescriptor;
use reflect::EnumValueDescriptor;
use unknown::UnknownFields;
use stream::WithCodedInputStream;
use stream::WithCodedOutputStream;
use stream::CodedInputStream;
use stream::CodedOutputStream;
use stream::with_coded_output_stream_to_bytes;
use error::ProtobufResult;

pub trait Message : PartialEq + Clone + Default + fmt::Show + Clear {
    fn new() -> Self;
    // all required fields set
    fn is_initialized(&self) -> bool;
    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;
    fn write_to_with_computed_sizes(&self, os: &mut CodedOutputStream, sizes: &[u32], sizes_pos: &mut uint)
            -> ProtobufResult<()>;
    fn compute_sizes(&self, sizes: &mut Vec<u32>) -> u32;

    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized();
        let mut sizes = mem::replace(&mut os.sizes, Vec::new());
        assert!(sizes.is_empty());
        self.compute_sizes(&mut sizes);
        let mut sizes_pos = 1; // first element is self
        try!(self.write_to_with_computed_sizes(os, sizes.as_slice(), &mut sizes_pos));
        assert_eq!(sizes_pos, sizes.len());
        // TODO: assert we've written same number of bytes as computed
        sizes.truncate(0);
        mem::replace(&mut os.sizes, sizes);
        Ok(())
    }

    fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let mut sizes = mem::replace(&mut os.sizes, Vec::new());
        assert!(sizes.is_empty());
        let size = self.compute_sizes(&mut sizes);
        try!(os.write_raw_varint32(size));
        let mut sizes_pos = 1; // first element is self
        try!(self.write_to_with_computed_sizes(os, sizes.as_slice(), &mut sizes_pos));
        assert_eq!(sizes_pos, sizes.len());
        // TODO: assert we've written same number of bytes as computed
        sizes.truncate(0);
        mem::replace(&mut os.sizes, sizes);
        Ok(())
    }

    fn serialized_size(&self) -> u32 {
        let mut sizes = Vec::new();
        self.compute_sizes(&mut sizes)
    }

    fn check_initialized(&self) {
        // TODO: report which fields are not initialized
        assert!(self.is_initialized());
    }

    fn write_to_writer(&self, w: &mut Writer) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| {
            self.write_to(os)
        })
    }

    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        with_coded_output_stream_to_bytes(|os| {
            self.write_to(os)
        })
    }

    fn write_length_delimited_to_writer(&self, w: &mut Writer) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| {
            self.write_length_delimited_to(os)
        })
    }

    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        with_coded_output_stream_to_bytes(|os| {
            self.write_length_delimited_to(os)
        })
    }

    fn get_unknown_fields<'s>(&'s self) -> &'s UnknownFields;
    fn mut_unknown_fields<'s>(&'s mut self) -> &'s mut UnknownFields;

    fn descriptor(&self) -> &'static MessageDescriptor {
        Message::descriptor_static(None::<Self>)
    }

    // http://stackoverflow.com/q/20342436/15018
    fn descriptor_static(_: Option<Self>) -> &'static MessageDescriptor {
        panic!("descriptor_static is not implemented for message, \
            LITE_RUNTIME must be used");
    }

    fn type_id(&self) -> TypeId {
        panic!();
    }

    // Rust does not allow implementation of trait for trait:
    // impl<M : Message> fmt::Show for M {
    // ...
    // }
    fn fmt_impl(&self, f: &mut fmt::Formatter) -> fmt::Result {
        ::text_format::fmt(self, f)
    }
}

pub fn message_is<M : 'static + Message>(m: &Message) -> bool {
    TypeId::of::<M>() == m.type_id()
}

pub fn message_down_cast<'a, M : 'static + Message>(m: &'a Message) -> &'a M {
    assert!(message_is::<M>(m));
    unsafe {
        // TODO: really weird
        let r: raw::TraitObject = mem::transmute(m);
        mem::transmute(r.data)
    }
}

pub trait ProtobufEnum : Eq {
    fn value(&self) -> i32;

    fn descriptor(&self) -> &'static EnumValueDescriptor {
        self.enum_descriptor().value_by_number(self.value())
    }

    fn enum_descriptor(&self) -> &'static EnumDescriptor {
        ProtobufEnum::enum_descriptor_static(None::<Self>)
    }

    // http://stackoverflow.com/q/20342436/15018
    fn enum_descriptor_static(_: Option<Self>) -> &'static EnumDescriptor {
        panic!();
    }
}

pub fn parse_from<M : Message>(is: &mut CodedInputStream) -> ProtobufResult<M> {
    let mut r: M = Message::new();
    try!(r.merge_from(is));
    r.check_initialized();
    Ok(r)
}

pub fn parse_from_reader<M : Message>(reader: &mut Reader) -> ProtobufResult<M> {
    reader.with_coded_input_stream(|is| {
        parse_from::<M>(is)
    })
}

pub fn parse_from_bytes<M : Message>(bytes: &[u8]) -> ProtobufResult<M> {
    bytes.with_coded_input_stream(|is| {
        parse_from::<M>(is)
    })
}

pub fn parse_length_delimited_from<M : Message>(is: &mut CodedInputStream) -> ProtobufResult<M> {
    is.read_message::<M>()
}

pub fn parse_length_delimited_from_reader<M : Message>(r: &mut Reader) -> ProtobufResult<M> {
    // TODO: wrong: we may read length first, and then read exact number of bytes needed
    r.with_coded_input_stream(|is| {
        is.read_message::<M>()
    })
}

pub fn parse_length_delimited_from_bytes<M : Message>(bytes: &[u8]) -> ProtobufResult<M> {
    bytes.with_coded_input_stream(|is| {
        is.read_message::<M>()
    })
}

<commit_msg>Message.merge_from_bytes shortcut<commit_after>// TODO: drop all panic!

use std::mem;
use std::raw;
use std::fmt;
use std::default::Default;
use std::intrinsics::TypeId;

use clear::Clear;
use reflect::MessageDescriptor;
use reflect::EnumDescriptor;
use reflect::EnumValueDescriptor;
use unknown::UnknownFields;
use stream::WithCodedInputStream;
use stream::WithCodedOutputStream;
use stream::CodedInputStream;
use stream::CodedOutputStream;
use stream::with_coded_output_stream_to_bytes;
use error::ProtobufResult;

pub trait Message : PartialEq + Clone + Default + fmt::Show + Clear {
    fn new() -> Self;
    // all required fields set
    fn is_initialized(&self) -> bool;
    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;
    fn write_to_with_computed_sizes(&self, os: &mut CodedOutputStream, sizes: &[u32], sizes_pos: &mut uint)
            -> ProtobufResult<()>;
    fn compute_sizes(&self, sizes: &mut Vec<u32>) -> u32;

    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized();
        let mut sizes = mem::replace(&mut os.sizes, Vec::new());
        assert!(sizes.is_empty());
        self.compute_sizes(&mut sizes);
        let mut sizes_pos = 1; // first element is self
        try!(self.write_to_with_computed_sizes(os, sizes.as_slice(), &mut sizes_pos));
        assert_eq!(sizes_pos, sizes.len());
        // TODO: assert we've written same number of bytes as computed
        sizes.truncate(0);
        mem::replace(&mut os.sizes, sizes);
        Ok(())
    }

    fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let mut sizes = mem::replace(&mut os.sizes, Vec::new());
        assert!(sizes.is_empty());
        let size = self.compute_sizes(&mut sizes);
        try!(os.write_raw_varint32(size));
        let mut sizes_pos = 1; // first element is self
        try!(self.write_to_with_computed_sizes(os, sizes.as_slice(), &mut sizes_pos));
        assert_eq!(sizes_pos, sizes.len());
        // TODO: assert we've written same number of bytes as computed
        sizes.truncate(0);
        mem::replace(&mut os.sizes, sizes);
        Ok(())
    }

    fn serialized_size(&self) -> u32 {
        let mut sizes = Vec::new();
        self.compute_sizes(&mut sizes)
    }

    fn merge_from_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
        let mut is = CodedInputStream::from_bytes(bytes);
        self.merge_from(&mut is)
    }

    fn check_initialized(&self) {
        // TODO: report which fields are not initialized
        assert!(self.is_initialized());
    }

    fn write_to_writer(&self, w: &mut Writer) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| {
            self.write_to(os)
        })
    }

    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        with_coded_output_stream_to_bytes(|os| {
            self.write_to(os)
        })
    }

    fn write_length_delimited_to_writer(&self, w: &mut Writer) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| {
            self.write_length_delimited_to(os)
        })
    }

    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        with_coded_output_stream_to_bytes(|os| {
            self.write_length_delimited_to(os)
        })
    }

    fn get_unknown_fields<'s>(&'s self) -> &'s UnknownFields;
    fn mut_unknown_fields<'s>(&'s mut self) -> &'s mut UnknownFields;

    fn descriptor(&self) -> &'static MessageDescriptor {
        Message::descriptor_static(None::<Self>)
    }

    // http://stackoverflow.com/q/20342436/15018
    fn descriptor_static(_: Option<Self>) -> &'static MessageDescriptor {
        panic!("descriptor_static is not implemented for message, \
            LITE_RUNTIME must be used");
    }

    fn type_id(&self) -> TypeId {
        panic!();
    }

    // Rust does not allow implementation of trait for trait:
    // impl<M : Message> fmt::Show for M {
    // ...
    // }
    fn fmt_impl(&self, f: &mut fmt::Formatter) -> fmt::Result {
        ::text_format::fmt(self, f)
    }
}

pub fn message_is<M : 'static + Message>(m: &Message) -> bool {
    TypeId::of::<M>() == m.type_id()
}

pub fn message_down_cast<'a, M : 'static + Message>(m: &'a Message) -> &'a M {
    assert!(message_is::<M>(m));
    unsafe {
        // TODO: really weird
        let r: raw::TraitObject = mem::transmute(m);
        mem::transmute(r.data)
    }
}

pub trait ProtobufEnum : Eq {
    fn value(&self) -> i32;

    fn descriptor(&self) -> &'static EnumValueDescriptor {
        self.enum_descriptor().value_by_number(self.value())
    }

    fn enum_descriptor(&self) -> &'static EnumDescriptor {
        ProtobufEnum::enum_descriptor_static(None::<Self>)
    }

    // http://stackoverflow.com/q/20342436/15018
    fn enum_descriptor_static(_: Option<Self>) -> &'static EnumDescriptor {
        panic!();
    }
}

pub fn parse_from<M : Message>(is: &mut CodedInputStream) -> ProtobufResult<M> {
    let mut r: M = Message::new();
    try!(r.merge_from(is));
    r.check_initialized();
    Ok(r)
}

pub fn parse_from_reader<M : Message>(reader: &mut Reader) -> ProtobufResult<M> {
    reader.with_coded_input_stream(|is| {
        parse_from::<M>(is)
    })
}

pub fn parse_from_bytes<M : Message>(bytes: &[u8]) -> ProtobufResult<M> {
    bytes.with_coded_input_stream(|is| {
        parse_from::<M>(is)
    })
}

pub fn parse_length_delimited_from<M : Message>(is: &mut CodedInputStream) -> ProtobufResult<M> {
    is.read_message::<M>()
}

pub fn parse_length_delimited_from_reader<M : Message>(r: &mut Reader) -> ProtobufResult<M> {
    // TODO: wrong: we may read length first, and then read exact number of bytes needed
    r.with_coded_input_stream(|is| {
        is.read_message::<M>()
    })
}

pub fn parse_length_delimited_from_bytes<M : Message>(bytes: &[u8]) -> ProtobufResult<M> {
    bytes.with_coded_input_stream(|is| {
        is.read_message::<M>()
    })
}

<|endoftext|>


<commit_before>/*
Module: rand

Random number generation
*/
native "cdecl" mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Use attributes for native module ABI and link name<commit_after>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>