<commit_before>use std::cell::{Cell, UnsafeCell};
use std::ops::{Deref, DerefMut};
use std::fmt;

/// This holds the backing allocation for the `Window` of a `Adaptor`.
///
/// See [sliding_windows](index.html) for more information.
pub struct Storage<T> {
    window_size: usize,
    // use elements just from this offset on
    window_offset: Cell<usize>,
    /// acts as a refcount
    uniquely_owned: Cell<bool>,
    data: UnsafeCell<Vec<T>>
}

impl<T> Storage<T> {
    /// Create a new `Storage` with a given window size optimized for a given Iterator.
    /// This will allocate an amount of memory big enough to avoid shifting elements during iteration.
    ///
    /// This should be the most performant option, which uses the most memory: ```Iterator::size_hint() * mem::size_of<Iterator::Item>```.
    /// If there is no size_hint, this is identical to `Storage::new()`.
    ///
    /// If you want to use less memory, but more CPU, consider using ```Storage::new()``` or ```Storage::new_exact()``` instead.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn optimized<I: Iterator>(iter: &I, window_size: usize) -> Storage<T> {
        let size = iter.size_hint();
        let mem = size.1.unwrap_or(size.0);

        if mem == 0 {
            Storage::new(window_size)
        } else if mem < window_size {
            Storage::new_exact(mem)
        } else {
            Storage::from_vec(Vec::with_capacity(mem), window_size)
        }
    }

    /// Create a new `Storage` with a given window size.
    /// This will allocate twice as much memory as is needed to store the Window for performance reasons.
    ///
    /// If you want to use as few memory as possible, but more CPU, consider using ```Storage::new_exact()``` instead.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(window_size: usize) -> Storage<T> {
        Storage::from_vec(Vec::with_capacity(window_size * 2), window_size)
    }

    /// Create a new `Storage` with a given window size.
    /// This will allocate exactly as much memory as is needed to store the Window.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new_exact(window_size: usize) -> Storage<T> {
        Storage::from_vec(Vec::with_capacity(window_size), window_size)
    }

    /// Create a new `Storage` with a given window size from a given struct implementing `Into<Vec>`.
    /// The contents of the Vec will be removed.
    /// This will reuse the allocation of the Vec instead of allocating new memory.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn from_vec<S: Into<Vec<T>>>(vec: S, window_size: usize) -> Storage<T> {
        Storage {
            window_size: window_size,
            window_offset: Cell::new(0),
            uniquely_owned: Cell::new(true),
            data: UnsafeCell::new(vec.into())
        }
    }

    fn new_window<'a>(&'a self) -> Window<'a, T> {
        // assert that the last window went out of scope
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        self.uniquely_owned.set(false);

        Window { drop_flag: &self.uniquely_owned, data: &mut data[window_offset..] }
    }

    // push value onto self
    // this should only be called if data.len() >= window_size
    fn push(&self, elt: T) -> bool {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        if data.len() >= self.window_size {
            // storage is full, copy elements to the front with drain
            if data.len() == data.capacity() {
                data.drain(0..window_offset+1);
                self.window_offset.set(0);
            // storage has min. window_size elements, so offset must be increased
            } else {
                self.window_offset.set(window_offset + 1);
            }
        }

        data.push(elt);
        data.len() >= self.window_size
    }

    // clear backing storage
    fn clear(&self) {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        data.clear();
    }
}

impl<T> Into<Vec<T>> for Storage<T> {
    fn into(self) -> Vec<T> {
        assert!(self.uniquely_owned.get(), "Storage dereferenced before previous Window went out of scope");
        unsafe {
            self.data.into_inner()
        }
    }
}

/// This is the `Item` type of the `Adaptor` iterator.
///
/// # Usage:
///
/// `Window<'a, T>` dereferences to `&'a [T]` or `&'a mut [T]`.
///
/// ```
/// use sliding_windows::IterExt;
/// use sliding_windows::Storage;
///
/// let mut storage: Storage<u32> = Storage::new(3);
/// let mut windowed_iter = (0..5).sliding_windows(&mut storage);
///
/// for mut window in windowed_iter {
///     // extra scope, so that later mutable borrow is possible
///     {
///         let slice: &[u32] = &window;
///         // work with slice
///     }
///
///     // mutable
///     let mut_slice: &mut [u32] = &mut window;
///     // work with data mutably
/// }
/// ```
///
/// See [sliding_windows](index.html) for more information.
pub struct Window<'a, T: 'a> {
    drop_flag: &'a Cell<bool>,
    data: &'a mut [T],
}

impl<'a, T> fmt::Debug for Window<'a, T> where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.data.fmt(f)
    }
}

impl<'a, T> Drop for Window<'a, T> {
    fn drop(&mut self) {
        // set flag to indicate this window was dropped
        self.drop_flag.set(true);
    }
}

// convenience impl &Window<T> => &[T]
impl<'a, T> Deref for Window<'a, T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        debug_assert!(!self.drop_flag.get());
        &*self.data
    }
}

// convenience impl &mut Window<T> => &mut [T]
impl<'a, T> DerefMut for Window<'a, T> {
    fn deref_mut(&mut self) -> &mut [T] {
        debug_assert!(!self.drop_flag.get());
        self.data
    }
}

impl<'a, 'b, T> PartialEq<&'b [T]> for Window<'a, T> where T: PartialEq
{
    fn eq(&self, other: &&'b [T]) -> bool {
        &self[..] == *other
    }
}

/// See [sliding_windows](index.html) for more information.
pub struct Adaptor<'a, I: Iterator> where <I as Iterator>::Item: 'a {
    iter: I,
    done: bool,
    storage: &'a Storage<I::Item>,
}

impl<'a, I: Iterator> Adaptor<'a, I> {
    /// This creates a new Adaptor. Usually you should be using
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(iter: I, storage: &'a Storage<I::Item>) -> Adaptor<'a, I> {
        // in case the storage was reused
        storage.clear();

        Adaptor {
            iter: iter,
            done: false,
            storage: storage,
        }
    }
}

impl<'a, I: Iterator> Iterator for Adaptor<'a, I> {
    type Item = Window<'a, I::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.done || self.storage.window_size == 0 {
            return None
        }
        self.done = true;
        for elt in &mut self.iter {
            if self.storage.push(elt) {
                self.done = false;
                break;
            }
        }
        if !self.done {
            // return new window
            Some(self.storage.new_window())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let size = self.storage.window_size;
        let (mut lower, mut upper): (usize, Option<usize>) = self.iter.size_hint();

        if size == 0 {
            return (0, None);
        }

        lower = match lower {
            0 => 0,
            x if x >= size => x - size + 1,
            _ => 1
        };

        upper = upper.map(|upper|
            match upper {
                0 => 0,
                x if x >= size => x - size + 1,
                _ => 1
            }
        );

        (lower, upper)
    }
}
<commit_msg>take a first stab at implementing the new logic<commit_after>use std::cell::{Cell, UnsafeCell};
use std::fmt;

/// This holds the backing allocation for the `Window` of a `Adaptor`.
///
/// See [sliding_windows](index.html) for more information.
pub struct Storage<T> {
    window_size: usize,
    // this is the offset of the first element
    window_offset: Cell<usize>,
    /// acts as a refcount
    uniquely_owned: Cell<bool>,
    data: UnsafeCell<Vec<T>>,
}

impl<T> Storage<T> {
    /// Create a new `Storage` with a given window size.
    /// This will allocate twice as much memory as is needed to store the Window for performance reasons.
    ///
    /// If you want to use as few memory as possible, but more CPU, consider using ```Storage::new_exact()``` instead.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(window_size: usize) -> Storage<T> {
        Storage::from_vec(Vec::with_capacity(window_size), window_size)
    }

    /// Create a new `Storage` with a given window size from a given struct implementing `Into<Vec>`.
    /// The contents of the Vec will be removed.
    /// This will reuse the allocation of the Vec instead of allocating new memory.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn from_vec<S: Into<Vec<T>>>(vec: S, window_size: usize) -> Storage<T> {
        Storage {
            window_size: window_size,
            window_offset: Cell::new(0),
            uniquely_owned: Cell::new(true),
            data: UnsafeCell::new(vec.into())
        }
    }

    fn new_window<'a>(&'a self) -> Window<'a, T> {
        // assert that the last window went out of scope
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        self.uniquely_owned.set(false);

        Window { drop_flag: &self.uniquely_owned, data: &mut data[..], window_offset: window_offset }
    }

    // push value onto self, return true if window is full (for initialization)
    // this assumes that data.capacity >= self.window_size
    fn push(&self, elt: T) -> bool {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        // if storage is not full simply push the element
        // this is only the case when filling storage initially
        if data.len() < self.window_size
        {
            data.push(elt);
            return data.len() == self.window_size;
        }

        debug_assert!(data.len() == self.window_size);

        // the storage is full, overwrite the last element
        let new_offset;
        if window_offset >= (self.window_size - 1) {
            new_offset = 0;
        } else {
            new_offset = window_offset + 1;
        }

        data[window_offset] = elt;
        self.window_offset.set(new_offset);
        true
    }

    // clear backing storage
    fn clear(&self) {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        data.clear();
    }
}

impl<T> Into<Vec<T>> for Storage<T> {
    fn into(self) -> Vec<T> {
        assert!(self.uniquely_owned.get(), "Storage dereferenced before previous Window went out of scope");
        unsafe {
            self.data.into_inner()
        }
    }
}

/// This is the `Item` type of the `Adaptor` iterator.
///
/// # Usage:
///
/// `Window<'a, T>` is an Iterator over &T.
///
/// ```
/// use sliding_windows::IterExt;
/// use sliding_windows::Storage;
///
/// let mut storage: Storage<u32> = Storage::new(3);
/// let mut windowed_iter = (0..5).sliding_windows(&mut storage);
///
/// for mut window in windowed_iter {
///     // extra scope, so that later mutable borrow is possible
///     {
///         let slice: &[u32] = &window;
///         // work with slice
///     }
///
///     // mutable
///     let mut_slice: &mut [u32] = &mut window;
///     // work with data mutably
/// }
/// ```
///
/// See [sliding_windows](index.html) for more information.
pub struct Window<'a, T: 'a> {
    drop_flag: &'a Cell<bool>,
    // index of first element
    window_offset: usize,
    data: &'a mut [T],
}

impl<'a, T> fmt::Debug for Window<'a, T> where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Window")?;
        return f.debug_list().entries(self.into_iter()).finish();
    }
}

impl<'a, T> Drop for Window<'a, T> {
    fn drop(&mut self) {
        // set flag to indicate this window was dropped
        self.drop_flag.set(true);
    }
}

impl<'a, 'b, T> PartialEq<&'b [T]> for Window<'a, T> where T: PartialEq
{
    fn eq(&self, other: &&'b [T]) -> bool {
        if self.data.len() != other.len() { return false }
        for (i, x) in self.into_iter().enumerate() {
            if *x != other[i] { return false }
        }
        true
    }
}

impl<'a, T> IntoIterator for &'a Window<'a, T>
{
    type Item = &'a T;
    type IntoIter = WindowIter<'a, T>;
    fn into_iter(self) -> Self::IntoIter {
        WindowIter {
            data: self.data,
            current_index: self.window_offset,
            iteration_num: 0
        }
    }
}

pub struct WindowIter<'a, T: 'a>
{
    data: &'a [T],
    current_index: usize,
    // number of next() calls made which returned Some(_)
    iteration_num: usize,
}

impl<'a, T> Iterator for WindowIter<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let current_element = &self.data[self.current_index];

        if self.iteration_num >= self.data.len() {
            // the end was reached
            return None;
        } else if self.current_index >= (self.data.len() - 1) {
            // wrap around if the increment would create an invalid index
            self.current_index = 0;
        } else {
            self.current_index += 1;
        }

        self.iteration_num += 1;
        Some(current_element)
    }
}

// TODO add WindowMutIter

// TODO add ExactSizeIterator
// TODO add other stuff like DoubleEndedIterator etc.

/// See [sliding_windows](index.html) for more information.
pub struct Adaptor<'a, I: Iterator> where <I as Iterator>::Item: 'a {
    iter: I,
    done: bool,
    storage: &'a Storage<I::Item>,
}

impl<'a, I: Iterator> Adaptor<'a, I> {
    /// This creates a new Adaptor. Usually you should be using
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(iter: I, storage: &'a Storage<I::Item>) -> Adaptor<'a, I> {
        // in case the storage was reused
        storage.clear();

        Adaptor {
            iter: iter,
            done: false,
            storage: storage,
        }
    }
}

impl<'a, I: Iterator> Iterator for Adaptor<'a, I> {
    type Item = Window<'a, I::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.done || self.storage.window_size == 0 {
            return None;
        }
        self.done = true;

        for elt in &mut self.iter {
            self.done = false;
            if self.storage.push(elt) {
                break;
            }
        }

        if !self.done {
            // return new window
            Some(self.storage.new_window())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let size = self.storage.window_size;
        let (mut lower, mut upper): (usize, Option<usize>) = self.iter.size_hint();

        if size == 0 {
            return (0, None);
        }

        lower = match lower {
            0 => 0,
            x if x >= size => x - size + 1,
            _ => 1
        };

        upper = upper.map(|upper|
            match upper {
                0 => 0,
                x if x >= size => x - size + 1,
                _ => 1
            }
        );

        (lower, upper)
    }
}
<|endoftext|>


<commit_before>
use spirv_utils::{self, desc, instruction};
use core;
use core::shade::{self, BaseType, ContainerType, TextureType};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Variable {
    id: desc::Id,
    name: String,
    ty: desc::Id,
    storage_class: desc::StorageClass,
    decoration: Vec<instruction::Decoration>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct EntryPoint {
    name: String,
    stage: shade::Stage,
    interface: Box<[desc::Id]>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Ty {
    Basic(BaseType, ContainerType),
    Image(BaseType, TextureType),
    Struct(Vec<Type>),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Type {
    id: desc::Id,
    ty: Ty,
    decoration: Vec<instruction::Decoration>,
}

fn map_execution_model_to_stage(model: desc::ExecutionModel) -> Option<shade::Stage> {
    use spirv_utils::desc::ExecutionModel::*;
    match model {
        Vertex => Some(shade::Stage::Vertex),
        Geometry => Some(shade::Stage::Geometry),
        Fragment => Some(shade::Stage::Pixel),

        _ => None,
    }
}

fn map_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Name { ref name, .. } => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_member_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberName { ref name, member, .. } if member == member_id => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Decorate { ref decoration, .. } => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_member_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberDecorate { ref decoration, member, .. } if member == member_id => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_scalar_to_basetype(instr: &instruction::Instruction) -> Option<BaseType> {
    use spirv_utils::instruction::Instruction;
    match *instr {
        Instruction::TypeBool { .. } => Some(BaseType::Bool),
        Instruction::TypeInt { width: 32, signed: false, .. } => Some(BaseType::U32),
        Instruction::TypeInt { width: 32, signed: true, .. } => Some(BaseType::I32),
        Instruction::TypeFloat { width: 32, ..} => Some(BaseType::F32),
        Instruction::TypeFloat { width: 64, ..} => Some(BaseType::F64),

        _ => None,
    }
}

fn map_instruction_to_type(module: &spirv_utils::RawModule, instr: &instruction::Instruction) -> Option<Type> {
    use spirv_utils::instruction::Instruction;
    match *instr {
        Instruction::TypeBool { result_type } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::Bool, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeInt { result_type, width: 32, signed: false } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::U32, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeInt { result_type, width: 32, signed: true } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::I32, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeFloat { result_type, width: 32 } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::F32, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeFloat { result_type, width: 64 } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::F64, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeVector { result_type, type_id, len } => {
            let comp_ty = module.def(type_id).unwrap();
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(map_scalar_to_basetype(comp_ty).unwrap(), ContainerType::Vector(len as u8)),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeMatrix { result_type, type_id, cols } => {
            // TODO:
            None
        },
        Instruction::TypeStruct { result_type, ref fields } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Struct(
                    fields.iter().filter_map(|field| // TODO: should be `map` only, just for testing due to unsupported types
                        map_instruction_to_type(module, module.def(*field).unwrap())
                    ).collect::<Vec<_>>()),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },

        _ => None,
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SpirvReflection {
    entry_points: Vec<EntryPoint>,
    variables: Vec<Variable>,
    types: Vec<Type>,
}

pub fn reflect_spirv_module(code: &[u8]) -> SpirvReflection {
    use spirv_utils::instruction::Instruction;

    let module = spirv_utils::RawModule::read_module(code).unwrap();

    let mut entry_points = Vec::new();
    let mut variables = Vec::new();
    let mut types = Vec::new();
    for instr in module.instructions() {
        match *instr {
            Instruction::EntryPoint { execution_model, ref name, ref interface, .. } => {
                if let Some(stage) = map_execution_model_to_stage(execution_model) {
                    entry_points.push(EntryPoint {
                        name: name.clone(),
                        stage: stage,
                        interface: interface.clone(),
                    });
                }
            },
            Instruction::Variable { result_type, result_id, storage_class, .. } => {
                let decoration = map_decorations_by_id(&module, result_id.into());
                let ty = {
                    // remove indirection layer as the type of every variable is a OpTypePointer
                    let ptr_ty = module.def::<desc::TypeId>(result_type.into()).unwrap();
                    match *ptr_ty {
                        Instruction::TypePointer { ref pointee, .. } => *pointee,
                        _ => unreachable!(), // SPIR-V module would be invalid
                    }
                };

                // Every variable MUST have an name annotation
                // `glslang` seems to emit empty strings for uniforms with struct type,
                // therefore we need to retrieve the name from the struct decl
                let name = {
                    let name = map_name_by_id(&module, result_id.into()).unwrap();
                    if name.is_empty() {
                        map_name_by_id(&module, ty.into()).unwrap()
                    } else {
                        name
                    }
                };

                variables.push(Variable {
                    id: result_id.into(),
                    name: name.into(),
                    ty: ty.into(),
                    storage_class: storage_class,
                    decoration: decoration,
                });
            },

            _ => {
                // Reflect types
                if let Some(ty) = map_instruction_to_type(&module, instr) {
                    types.push(ty);
                }
            },
        }
    }

    println!("{:?}", entry_points);
    println!("{:?}", variables);
    println!("{:?}", types);

    SpirvReflection {
        entry_points: entry_points,
        variables: variables,
        types: types,
    }
}

pub fn populate_info(info: &mut shade::ProgramInfo, stage: shade::Stage, reflection: &SpirvReflection) {
    if stage == shade::Stage::Vertex {
        // record vertex attributes
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for attrib in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *attrib && var.storage_class == desc::StorageClass::Input) {
                    let attrib_name = var.name.clone();
                    let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                    instruction::Decoration::Location(slot) => Some(slot),
                                    _ => None,
                                }).next().expect("Missing location decoration");

                    let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                    if let Ty::Basic(base, container) = ty.ty {
                        info.vertex_attributes.push(shade::AttributeVar {
                            name: attrib_name,
                            slot: slot as core::AttributeSlot,
                            base_type: base,
                            container: container,
                        });
                    }
                }
            }
        }
    } else if stage == shade::Stage::Pixel {
        // record pixel outputs
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for out in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *out && var.storage_class == desc::StorageClass::Output) {
                    let target_name = var.name.clone();
                    let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                    instruction::Decoration::Location(slot) => Some(slot),
                                    _ => None,
                                }).next().expect("Missing location decoration");

                    let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                    if let Ty::Basic(base, container) = ty.ty {
                        info.outputs.push(shade::OutputVar {
                            name: target_name,
                            slot: slot as core::ColorSlot,
                            base_type: base,
                            container: container,
                        });
                    }
                }
            }
        }
    }

    // Handle resources
    // We use only one descriptor set currently
    for var in reflection.variables.iter() {
        use spirv_utils::desc::StorageClass::*;
        match var.storage_class {
            Uniform | UniformConstant => {

            },
            _ => (),
        }
    }
}
<commit_msg>Vulkan: Reflect matrix types and basic support for const buffer reflection<commit_after>
use spirv_utils::{self, desc, instruction};
use core;
use core::shade::{self, BaseType, ContainerType, TextureType};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Variable {
    id: desc::Id,
    name: String,
    ty: desc::Id,
    storage_class: desc::StorageClass,
    decoration: Vec<instruction::Decoration>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct EntryPoint {
    name: String,
    stage: shade::Stage,
    interface: Box<[desc::Id]>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Ty {
    Basic(BaseType, ContainerType),
    Image(BaseType, TextureType),
    Struct(Vec<Type>),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Type {
    id: desc::Id,
    ty: Ty,
    decoration: Vec<instruction::Decoration>,
}

fn map_execution_model_to_stage(model: desc::ExecutionModel) -> Option<shade::Stage> {
    use spirv_utils::desc::ExecutionModel::*;
    match model {
        Vertex => Some(shade::Stage::Vertex),
        Geometry => Some(shade::Stage::Geometry),
        Fragment => Some(shade::Stage::Pixel),

        _ => None,
    }
}

fn map_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Name { ref name, .. } => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_member_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberName { ref name, member, .. } if member == member_id => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Decorate { ref decoration, .. } => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_member_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberDecorate { ref decoration, member, .. } if member == member_id => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_scalar_to_basetype(instr: &instruction::Instruction) -> Option<BaseType> {
    use spirv_utils::instruction::Instruction;
    match *instr {
        Instruction::TypeBool { .. } => Some(BaseType::Bool),
        Instruction::TypeInt { width: 32, signed: false, .. } => Some(BaseType::U32),
        Instruction::TypeInt { width: 32, signed: true, .. } => Some(BaseType::I32),
        Instruction::TypeFloat { width: 32, ..} => Some(BaseType::F32),
        Instruction::TypeFloat { width: 64, ..} => Some(BaseType::F64),

        _ => None,
    }
}

fn map_instruction_to_type(module: &spirv_utils::RawModule, instr: &instruction::Instruction) -> Option<Type> {
    use spirv_utils::instruction::{Decoration, Instruction};
    match *instr {
        Instruction::TypeBool { result_type } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::Bool, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeInt { result_type, width: 32, signed: false } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::U32, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeInt { result_type, width: 32, signed: true } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::I32, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeFloat { result_type, width: 32 } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::F32, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeFloat { result_type, width: 64 } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(BaseType::F64, ContainerType::Single),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeVector { result_type, type_id, len } => {
            let comp_ty = module.def(type_id).unwrap();
            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(map_scalar_to_basetype(comp_ty).unwrap(), ContainerType::Vector(len as u8)),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },
        Instruction::TypeMatrix { result_type, type_id, cols } => {
            let (base, rows) = match *module.def(type_id).unwrap() {
                Instruction::TypeVector { type_id, len, .. } => {
                    let comp_ty = module.def(type_id).unwrap();
                    (map_scalar_to_basetype(comp_ty).unwrap(), len)
                },
                _ => unreachable!(), // SPIR-V module would be invalid
            };

            let decoration = map_decorations_by_id(&module, result_type.into());

            // NOTE: temporary value, changes might be needed later depending on the decorations of the variable
            let matrix_format = if decoration.iter().find(|deco| **deco == Decoration::RowMajor).is_some() {
                shade::MatrixFormat::RowMajor
            } else {
                shade::MatrixFormat::ColumnMajor
            };

            Some(Type {
                id: result_type.into(),
                ty: Ty::Basic(base, ContainerType::Matrix(matrix_format, rows as u8, cols as u8)),
                decoration: decoration,
            })

        },
        Instruction::TypeStruct { result_type, ref fields } => {
            Some(Type {
                id: result_type.into(),
                ty: Ty::Struct(
                    fields.iter().filter_map(|field| // TODO: should be `map()`, currently to ignore unsupported types
                        map_instruction_to_type(module, module.def(*field).unwrap())
                    ).collect::<Vec<_>>()),
                decoration: map_decorations_by_id(&module, result_type.into()),
            })
        },

        _ => None,
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SpirvReflection {
    entry_points: Vec<EntryPoint>,
    variables: Vec<Variable>,
    types: Vec<Type>,
}

pub fn reflect_spirv_module(code: &[u8]) -> SpirvReflection {
    use spirv_utils::instruction::Instruction;

    let module = spirv_utils::RawModule::read_module(code).unwrap();

    let mut entry_points = Vec::new();
    let mut variables = Vec::new();
    let mut types = Vec::new();
    for instr in module.instructions() {
        match *instr {
            Instruction::EntryPoint { execution_model, ref name, ref interface, .. } => {
                if let Some(stage) = map_execution_model_to_stage(execution_model) {
                    entry_points.push(EntryPoint {
                        name: name.clone(),
                        stage: stage,
                        interface: interface.clone(),
                    });
                }
            },
            Instruction::Variable { result_type, result_id, storage_class, .. } => {
                let decoration = map_decorations_by_id(&module, result_id.into());
                let ty = {
                    // remove indirection layer as the type of every variable is a OpTypePointer
                    let ptr_ty = module.def::<desc::TypeId>(result_type.into()).unwrap();
                    match *ptr_ty {
                        Instruction::TypePointer { ref pointee, .. } => *pointee,
                        _ => unreachable!(), // SPIR-V module would be invalid
                    }
                };

                // Every variable MUST have an name annotation
                // `glslang` seems to emit empty strings for uniforms with struct type,
                // therefore we need to retrieve the name from the struct decl
                let name = {
                    let name = map_name_by_id(&module, result_id.into()).unwrap();
                    if name.is_empty() {
                        map_name_by_id(&module, ty.into()).unwrap()
                    } else {
                        name
                    }
                };

                variables.push(Variable {
                    id: result_id.into(),
                    name: name.into(),
                    ty: ty.into(),
                    storage_class: storage_class,
                    decoration: decoration,
                });
            },

            _ => {
                // Reflect types
                if let Some(ty) = map_instruction_to_type(&module, instr) {
                    types.push(ty);
                }
            },
        }
    }

    println!("{:?}", entry_points);
    println!("{:?}", variables);
    println!("{:?}", types);

    SpirvReflection {
        entry_points: entry_points,
        variables: variables,
        types: types,
    }
}

pub fn populate_info(info: &mut shade::ProgramInfo, stage: shade::Stage, reflection: &SpirvReflection) {
    if stage == shade::Stage::Vertex {
        // record vertex attributes
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for attrib in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *attrib && var.storage_class == desc::StorageClass::Input) {
                    let attrib_name = var.name.clone();
                    let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                    instruction::Decoration::Location(slot) => Some(slot),
                                    _ => None,
                                }).next().expect("Missing location decoration");

                    let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                    if let Ty::Basic(base, container) = ty.ty {
                        info.vertex_attributes.push(shade::AttributeVar {
                            name: attrib_name,
                            slot: slot as core::AttributeSlot,
                            base_type: base,
                            container: container,
                        });
                    }
                }
            }
        }
    } else if stage == shade::Stage::Pixel {
        // record pixel outputs
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for out in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *out && var.storage_class == desc::StorageClass::Output) {
                    let target_name = var.name.clone();
                    let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                    instruction::Decoration::Location(slot) => Some(slot),
                                    _ => None,
                                }).next().expect("Missing location decoration");

                    let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                    if let Ty::Basic(base, container) = ty.ty {
                        info.outputs.push(shade::OutputVar {
                            name: target_name,
                            slot: slot as core::ColorSlot,
                            base_type: base,
                            container: container,
                        });
                    }
                }
            }
        }
    }

    // Handle resources
    // We use only one descriptor set currently
    for var in reflection.variables.iter() {
        use spirv_utils::desc::StorageClass::*;
        match var.storage_class {
            Uniform | UniformConstant => {
                if let Some(ty) = reflection.types.iter().find(|ty| ty.id == var.ty) {
                    // constant buffers
                    if let Ty::Struct(ref fields) = ty.ty {
                        let mut elements = Vec::new();
                        for field in fields {
                            // TODO:
                        }

                        let buffer_name = var.name.clone();
                        let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                        instruction::Decoration::Binding(slot) => Some(slot),
                                        _ => None,
                                    }).next().expect("Missing binding decoration");

                        info.constant_buffers.push(shade::ConstantBufferVar {
                            name: buffer_name,
                            slot: slot as core::ConstantBufferSlot,
                            size: 0, // TODO:
                            usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            elements: elements,
                        });
                    }
                }
            },
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before>use redox::ops::DerefMut;
use redox::string::*;
use redox::vec::Vec;
use redox::boxed::Box;
use redox::fs::*;
use redox::io::*;
use redox::env::*;
use redox::time::Duration;
use redox::to_num::*;

/* Magic Macros { */
static mut application: *mut Application<'static> = 0 as *mut Application;

/// Execute a command
macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd.to_string());
        }
    })
}
/* } Magic Macros */

/// A command
pub struct Command<'a> {
    pub name: &'a str,
    pub main: Box<Fn(&Vec<String>)>,
}

impl<'a> Command<'a> {
    /// Return the vector of the commands
    // TODO: Use a more efficient collection instead
    pub fn vec() -> Vec<Self> {
        let mut commands: Vec<Self> = Vec::new();

        commands.push(Command {
            name: "cat",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read: {}", path),
                    }
                } else {
                    println!("Failed to open file: {}", path);
                }
            },
        });

        commands.push(Command {
            name: "cd",
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(path) => {
                        if !change_cwd(&path) {
                            println!("Bad path: {}", path);
                        }
                    }
                    None => println!("No path given")
                }
            },
        });

        commands.push(Command {
            name: "echo",
            main: box |args: &Vec<String>| {
                let echo = args.iter()
                    .skip(1)
                    .fold(String::new(), |string, arg| string + " " + arg);
                println!("{}", echo.trim());
            },
        });

        commands.push(Command {
            name: "exec",
            main: box |args: &Vec<String>| {
                if let Some(arg) = args.get(1) {
                    File::exec(arg);
                }
            },
        });

        commands.push(Command {
            name: "exit",
            main: box |_: &Vec<String>| {
            },
        });

        commands.push(Command {
            name: "ls",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(dir) = read_dir(&path) {
                    for entry in dir {
                        println!("{}", entry.path());
                    }
                } else {
                    println!("Failed to open directory: {}", path);
                }
            }
        });

        commands.push(Command {
            name: "run",
            main: box |args: &Vec<String>| {
                if let Some(path) = args.get(1) {

                    let mut commands = String::new();
                    if let Some(mut file) = File::open(path) {
                        file.read_to_string(&mut commands);
                    }

                    for command in commands.split('\n') {
                        exec!(command);
                    }
                }
            },
        });

        commands.push(Command {
            name: "pwd",
            main: box |_: &Vec<String>| {
                let mut err = false;
                if let Some(file) = File::open("") {
                    if let Some(path) = file.path() {
                        println!("{}", path);
                    } else {
                        err = true;
                    }
                } else {
                    err = true;
                }
                if err {
                    println!("Could not get the path");
                }
            },
        });

        commands.push(Command {
            name: "sleep",
            main: box |args: &Vec<String>| {
                let secs = {
                    match args.get(1) {
                        Some(arg) => arg.to_num() as i64,
                        None => 0,
                    }
                };

                let nanos = {
                    match args.get(2) {
                        Some(arg) => arg.to_num() as i32,
                        None => 0,
                    }
                };

                println!("Sleep: {} {}", secs, nanos);
                let remaining = Duration::new(secs, nanos).sleep();
                println!("Remaining: {} {}", remaining.secs, remaining.nanos);
            },
        });

        commands.push(Command {
            name: "send",
            main: box |args: &Vec<String>| {
                if args.len() < 3 {
                    println!("Error: incorrect arguments");
                    println!("Usage: send [url] [data]");
                    return;
                }

                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    println!("URL: {:?}", file.path());

                    let string: String = args.iter()
                        .skip(2)
                        .fold(String::new(), |s, arg| s + " " + arg)
                        + "\r\n\r\n";

                    match file.write(string.trim_left().as_bytes()) {
                        Some(size) => println!("Wrote {} bytes", size),
                        None => println!("Failed to write"),
                    }

                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "test_ht",
            main: box |_: &Vec<String>| {
                ::redox::hashmap::test();
            },
        });

        commands.push(Command {
            name: "url_hex",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut vec: Vec<u8> = Vec::new();
                    match file.read_to_end(&mut vec) {
                        Some(_) => {
                            let mut line = "HEX:".to_string();
                            for byte in vec.iter() {
                                line = line + " " + &format!("{:X}", *byte);
                            }
                            println!("{}", line);
                        }
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "wget",
            main: box |args: &Vec<String>| {
                if let Some(host) = args.get(1) {
                    if let Some(req) = args.get(2) {
                        if let Some(mut con) = File::open(&("tcp://".to_string() + host)) {
                            con.write(("GET ".to_string() + req + " HTTP/1.1").as_bytes());

                            let mut res = Vec::new();
                            con.read_to_end(&mut res);

                            if let Some(mut file) = File::open(&req) {
                                file.write(&res);
                            }
                        }
                    } else {
                        println!("No request given");
                    }
                } else {
                    println!("No url given");
                }
            },
        });

        let command_list = commands.iter().fold(String::new(), |l , c| l + " " + c.name);

        commands.push(Command {
            name: "help",
            main: box move |_: &Vec<String>| {
                println!("Commands:{}", command_list);
            },
         });

        commands
    }
}

/// A (env) variable
pub struct Variable {
    pub name: String,
    pub value: String,
}

pub struct Mode {
    value: bool,
}

/// An application
pub struct Application<'a> {
    commands: Vec<Command<'a>>,
    variables: Vec<Variable>,
    modes: Vec<Mode>,
}

impl<'a> Application<'a> {
    /// Create a new empty application
    pub fn new() -> Self {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new(),
        };
    }

    fn on_command(&mut self, command_string: &str) {
        //Comment
        if command_string.starts_with('#') {
            return;
        }

        //Show variables
        if command_string == "$" {
            let variables = self.variables.iter()
                .fold(String::new(),
                      |string, variable| string + "\n" + &variable.name + "=" + &variable.value);
            println!("{}", variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(' ') {
            if !arg.is_empty() {
                if arg.starts_with('$') {
                    let name = arg[1 .. arg.len()].to_string();
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                } else {
                    args.push(arg.to_string());
                }
            }
        }

        //Execute commands
        if let Some(cmd) = args.get(0) {
            if cmd == "if" {
                let mut value = false;

                if let Some(left) = args.get(1) {
                    if let Some(cmp) = args.get(2) {
                        if let Some(right) = args.get(3) {
                            if cmp == "==" {
                                value = *left == *right;
                            } else if cmp == "!=" {
                                value = *left != *right;
                            } else if cmp == ">" {
                                value = left.to_num_signed() > right.to_num_signed();
                            } else if cmp == ">=" {
                                value = left.to_num_signed() >= right.to_num_signed();
                            } else if cmp == "<" {
                                value = left.to_num_signed() < right.to_num_signed();
                            } else if cmp == "<=" {
                                value = left.to_num_signed() <= right.to_num_signed();
                            } else {
                                println!("Unknown comparison: {}", cmp);
                            }
                        }
                    }
                }

                self.modes.insert(0, Mode { value: value });
                return;
            }

            if cmd == "else" {
                let mut syntax_error = false;
                match self.modes.get_mut(0) {
                    Some(mode) => mode.value = !mode.value,
                    None => syntax_error = true,
                }
                if syntax_error {
                    println!("Syntax error: else found with no previous if");
                }
                return;
            }

            if cmd == "fi" {
                let mut syntax_error = false;
                if !self.modes.is_empty() {
                    self.modes.remove(0);
                } else {
                    syntax_error = true;
                }
                if syntax_error {
                    println!("Syntax error: fi found with no previous if");
                }
                return;
            }

            for mode in self.modes.iter() {
                if !mode.value {
                    return;
                }
            }

            //Set variables
            if let Some(i) = cmd.find('=') {
                let name = cmd[0 .. i].to_string();
                let mut value = cmd[i + 1 .. cmd.len()].to_string();

                if name.is_empty() {
                    return;
                }

                for i in 1..args.len() {
                    if let Some(arg) = args.get(i) {
                        value = value + " " + &arg;
                    }
                }

                if value.is_empty() {
                    let mut remove = -1;
                    for i in 0..self.variables.len() {
                        match self.variables.get(i) {
                            Some(variable) => if variable.name == name {
                                remove = i as isize;
                                break;
                            },
                            None => break,
                        }
                    }

                    if remove >= 0 {
                        self.variables.remove(remove as usize);
                    }
                } else {
                    for variable in self.variables.iter_mut() {
                        if variable.name == name {
                            variable.value = value;
                            return;
                        }
                    }

                    self.variables.push(Variable {
                        name: name,
                        value: value,
                    });
                }
                return;
            }

            //Commands
            for command in self.commands.iter() {
                if &command.name == cmd {
                    (*command.main)(&args);
                    return;
                }
            }

            println!("Unknown command: '{}'", cmd);
        }
    }

    /// Run the application
    pub fn main(&mut self) {
        println!("Type help for a command list");
        if let Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# {}", command);
            self.on_command(&command);
        }

        loop {
            for mode in self.modes.iter().rev() {
                if mode.value {
                    print!("+");
                } else {
                    print!("-");
                }
            }
            print!("# ");
            if let Some(command_original) = readln!() {
                let command = command_original.trim();
                if command == "exit" {
                    println!("Exit temporarily blocked (due to using terminal as init)")
                    //break;
                } else if !command.is_empty() {
                    self.on_command(&command);
                }
            } else {
                println!("Failed to read from stdin");
            }
        }
    }
}

pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<commit_msg>Add if/else/fi to command list<commit_after>use redox::ops::DerefMut;
use redox::string::*;
use redox::vec::Vec;
use redox::boxed::Box;
use redox::fs::*;
use redox::io::*;
use redox::env::*;
use redox::time::Duration;
use redox::to_num::*;

/* Magic Macros { */
static mut application: *mut Application<'static> = 0 as *mut Application;

/// Execute a command
macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd.to_string());
        }
    })
}
/* } Magic Macros */

/// A command
pub struct Command<'a> {
    pub name: &'a str,
    pub main: Box<Fn(&Vec<String>)>,
}

impl<'a> Command<'a> {
    /// Return the vector of the commands
    // TODO: Use a more efficient collection instead
    pub fn vec() -> Vec<Self> {
        let mut commands: Vec<Self> = Vec::new();

        commands.push(Command {
            name: "cat",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read: {}", path),
                    }
                } else {
                    println!("Failed to open file: {}", path);
                }
            },
        });

        commands.push(Command {
            name: "cd",
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(path) => {
                        if !change_cwd(&path) {
                            println!("Bad path: {}", path);
                        }
                    }
                    None => println!("No path given")
                }
            },
        });

        commands.push(Command {
            name: "echo",
            main: box |args: &Vec<String>| {
                let echo = args.iter()
                    .skip(1)
                    .fold(String::new(), |string, arg| string + " " + arg);
                println!("{}", echo.trim());
            },
        });

        commands.push(Command {
            name: "else",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "exec",
            main: box |args: &Vec<String>| {
                if let Some(arg) = args.get(1) {
                    File::exec(arg);
                }
            },
        });

        commands.push(Command {
            name: "exit",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "fi",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "if",
            main: box |_: &Vec<String>| {},
        });

        commands.push(Command {
            name: "ls",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(dir) = read_dir(&path) {
                    for entry in dir {
                        println!("{}", entry.path());
                    }
                } else {
                    println!("Failed to open directory: {}", path);
                }
            }
        });

        commands.push(Command {
            name: "run",
            main: box |args: &Vec<String>| {
                if let Some(path) = args.get(1) {

                    let mut commands = String::new();
                    if let Some(mut file) = File::open(path) {
                        file.read_to_string(&mut commands);
                    }

                    for command in commands.split('\n') {
                        exec!(command);
                    }
                }
            },
        });

        commands.push(Command {
            name: "pwd",
            main: box |_: &Vec<String>| {
                let mut err = false;
                if let Some(file) = File::open("") {
                    if let Some(path) = file.path() {
                        println!("{}", path);
                    } else {
                        err = true;
                    }
                } else {
                    err = true;
                }
                if err {
                    println!("Could not get the path");
                }
            },
        });

        commands.push(Command {
            name: "sleep",
            main: box |args: &Vec<String>| {
                let secs = {
                    match args.get(1) {
                        Some(arg) => arg.to_num() as i64,
                        None => 0,
                    }
                };

                let nanos = {
                    match args.get(2) {
                        Some(arg) => arg.to_num() as i32,
                        None => 0,
                    }
                };

                println!("Sleep: {} {}", secs, nanos);
                let remaining = Duration::new(secs, nanos).sleep();
                println!("Remaining: {} {}", remaining.secs, remaining.nanos);
            },
        });

        commands.push(Command {
            name: "send",
            main: box |args: &Vec<String>| {
                if args.len() < 3 {
                    println!("Error: incorrect arguments");
                    println!("Usage: send [url] [data]");
                    return;
                }

                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    println!("URL: {:?}", file.path());

                    let string: String = args.iter()
                        .skip(2)
                        .fold(String::new(), |s, arg| s + " " + arg)
                        + "\r\n\r\n";

                    match file.write(string.trim_left().as_bytes()) {
                        Some(size) => println!("Wrote {} bytes", size),
                        None => println!("Failed to write"),
                    }

                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "test_ht",
            main: box |_: &Vec<String>| {
                ::redox::hashmap::test();
            },
        });

        commands.push(Command {
            name: "url_hex",
            main: box |args: &Vec<String>| {
                let path = {
                    match args.get(1) {
                        Some(arg) => arg.clone(),
                        None => String::new(),
                    }
                };

                if let Some(mut file) = File::open(&path) {
                    let mut vec: Vec<u8> = Vec::new();
                    match file.read_to_end(&mut vec) {
                        Some(_) => {
                            let mut line = "HEX:".to_string();
                            for byte in vec.iter() {
                                line = line + " " + &format!("{:X}", *byte);
                            }
                            println!("{}", line);
                        }
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "wget",
            main: box |args: &Vec<String>| {
                if let Some(host) = args.get(1) {
                    if let Some(req) = args.get(2) {
                        if let Some(mut con) = File::open(&("tcp://".to_string() + host)) {
                            con.write(("GET ".to_string() + req + " HTTP/1.1").as_bytes());

                            let mut res = Vec::new();
                            con.read_to_end(&mut res);

                            if let Some(mut file) = File::open(&req) {
                                file.write(&res);
                            }
                        }
                    } else {
                        println!("No request given");
                    }
                } else {
                    println!("No url given");
                }
            },
        });

        let command_list = commands.iter().fold(String::new(), |l , c| l + " " + c.name);

        commands.push(Command {
            name: "help",
            main: box move |_: &Vec<String>| {
                println!("Commands:{}", command_list);
            },
         });

        commands
    }
}

/// A (env) variable
pub struct Variable {
    pub name: String,
    pub value: String,
}

pub struct Mode {
    value: bool,
}

/// An application
pub struct Application<'a> {
    commands: Vec<Command<'a>>,
    variables: Vec<Variable>,
    modes: Vec<Mode>,
}

impl<'a> Application<'a> {
    /// Create a new empty application
    pub fn new() -> Self {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new(),
        };
    }

    fn on_command(&mut self, command_string: &str) {
        //Comment
        if command_string.starts_with('#') {
            return;
        }

        //Show variables
        if command_string == "$" {
            let variables = self.variables.iter()
                .fold(String::new(),
                      |string, variable| string + "\n" + &variable.name + "=" + &variable.value);
            println!("{}", variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(' ') {
            if !arg.is_empty() {
                if arg.starts_with('$') {
                    let name = arg[1 .. arg.len()].to_string();
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                } else {
                    args.push(arg.to_string());
                }
            }
        }

        //Execute commands
        if let Some(cmd) = args.get(0) {
            if cmd == "if" {
                let mut value = false;

                if let Some(left) = args.get(1) {
                    if let Some(cmp) = args.get(2) {
                        if let Some(right) = args.get(3) {
                            if cmp == "==" {
                                value = *left == *right;
                            } else if cmp == "!=" {
                                value = *left != *right;
                            } else if cmp == ">" {
                                value = left.to_num_signed() > right.to_num_signed();
                            } else if cmp == ">=" {
                                value = left.to_num_signed() >= right.to_num_signed();
                            } else if cmp == "<" {
                                value = left.to_num_signed() < right.to_num_signed();
                            } else if cmp == "<=" {
                                value = left.to_num_signed() <= right.to_num_signed();
                            } else {
                                println!("Unknown comparison: {}", cmp);
                            }
                        }
                    }
                }

                self.modes.insert(0, Mode { value: value });
                return;
            }

            if cmd == "else" {
                let mut syntax_error = false;
                match self.modes.get_mut(0) {
                    Some(mode) => mode.value = !mode.value,
                    None => syntax_error = true,
                }
                if syntax_error {
                    println!("Syntax error: else found with no previous if");
                }
                return;
            }

            if cmd == "fi" {
                let mut syntax_error = false;
                if !self.modes.is_empty() {
                    self.modes.remove(0);
                } else {
                    syntax_error = true;
                }
                if syntax_error {
                    println!("Syntax error: fi found with no previous if");
                }
                return;
            }

            for mode in self.modes.iter() {
                if !mode.value {
                    return;
                }
            }

            //Set variables
            if let Some(i) = cmd.find('=') {
                let name = cmd[0 .. i].to_string();
                let mut value = cmd[i + 1 .. cmd.len()].to_string();

                if name.is_empty() {
                    return;
                }

                for i in 1..args.len() {
                    if let Some(arg) = args.get(i) {
                        value = value + " " + &arg;
                    }
                }

                if value.is_empty() {
                    let mut remove = -1;
                    for i in 0..self.variables.len() {
                        match self.variables.get(i) {
                            Some(variable) => if variable.name == name {
                                remove = i as isize;
                                break;
                            },
                            None => break,
                        }
                    }

                    if remove >= 0 {
                        self.variables.remove(remove as usize);
                    }
                } else {
                    for variable in self.variables.iter_mut() {
                        if variable.name == name {
                            variable.value = value;
                            return;
                        }
                    }

                    self.variables.push(Variable {
                        name: name,
                        value: value,
                    });
                }
                return;
            }

            //Commands
            for command in self.commands.iter() {
                if &command.name == cmd {
                    (*command.main)(&args);
                    return;
                }
            }

            println!("Unknown command: '{}'", cmd);
        }
    }

    /// Run the application
    pub fn main(&mut self) {
        println!("Type help for a command list");
        if let Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# {}", command);
            self.on_command(&command);
        }

        loop {
            for mode in self.modes.iter().rev() {
                if mode.value {
                    print!("+ ");
                } else {
                    print!("- ");
                }
            }
            print!("# ");
            if let Some(command_original) = readln!() {
                let command = command_original.trim();
                if command == "exit" {
                    println!("Exit temporarily blocked (due to using terminal as init)")
                    //break;
                } else if !command.is_empty() {
                    self.on_command(&command);
                }
            } else {
                println!("Failed to read from stdin");
            }
        }
    }
}

pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<|endoftext|>


<commit_before>use Rng;
use calx_ecs::Entity;
use calx_grid::HexFov;
use command::{Command, CommandResult};
use components;
use errors::*;
use event::Event;
use flags::Flags;
use fov::SightFov;
use item::Slot;
use location::{Location, Portal};
use mutate::Mutate;
use query::Query;
use rand::SeedableRng;
use ron;
use spatial::{Place, Spatial};
use std::collections::HashSet;
use std::io::{Read, Write};
use std::iter::FromIterator;
use std::slice;
use terraform::{Terraform, TerrainQuery};
use terrain::Terrain;
use volume::Volume;
use worldgen::Worldgen;

pub const GAME_VERSION: &'static str = "0.1.0";

Ecs! {
    desc: components::Desc,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    stats: components::StatsComponent,
    status: components::Statuses,
}

/// Toplevel game state object.
#[derive(Serialize, Deserialize)]
pub struct World {
    /// Game version. Not mutable in the slightest, but the simplest way to
    /// get versioned save files is to just drop it here.
    version: String,
    /// Entity component system.
    ecs: Ecs,
    /// Static startup game world
    worldgen: Worldgen,
    /// Spatial index for game entities.
    spatial: Spatial,
    /// Global gamestate flags.
    flags: Flags,
    /// Persistent random number generator.
    rng: Rng,
    /// Event queue
    events: Vec<Event>,
}

impl<'a> World {
    pub fn new(seed: u32) -> World {
        let mut ret = World {
            version: GAME_VERSION.to_string(),
            ecs: Ecs::new(),
            worldgen: Worldgen::new(seed),
            spatial: Spatial::new(),
            flags: Flags::new(),
            rng: SeedableRng::from_seed([seed, seed, seed, seed]),
            events: Vec::new(),
        };

        // XXX: Clone to not run into borrow checker...
        for (loc, spawn) in ret.worldgen
            .spawns()
            .cloned()
            .collect::<Vec<(Location, Loadout)>>()
            .into_iter()
        {
            ret.spawn(&spawn, loc);
        }

        // TODO non-lexical borrow
        let player_entry = ret.worldgen.player_entry();
        ret.spawn_player(player_entry);

        ret
    }

    pub fn load<R: Read>(reader: &mut R) -> Result<World> {
        let ret: ron::de::Result<World> = ron::de::from_reader(reader);
        if let Ok(ref x) = ret {
            if x.version != GAME_VERSION {
                panic!(
                    "Save game version {} does not match current version {}",
                    x.version,
                    GAME_VERSION
                );
            }
        }
        Ok(ret?)
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> Result<()> {
        let enc = ron::ser::pretty::to_string(self)?;
        // TODO: Handle error from writer too...
        writeln!(writer, "{}", enc)?;
        Ok(())
    }
}

impl TerrainQuery for World {
    fn is_valid_location(&self, _loc: Location) -> bool {
        //Location::origin().v2_at(loc).map_or(false, ::on_screen)
        true
    }

    fn terrain(&self, loc: Location) -> Terrain {
        let mut t = self.worldgen.get_terrain(loc);

        if t == Terrain::Door && self.has_mobs(loc) {
            // Standing in the doorway opens the door.
            t = Terrain::OpenDoor;
        }

        t
    }

    fn portal(&self, loc: Location) -> Option<Location> { self.worldgen.get_portal(loc) }

    fn is_untouched(&self, _loc: Location) -> bool { unimplemented!() }
}

impl Query for World {
    fn location(&self, e: Entity) -> Option<Location> {
        match self.spatial.get(e) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(container, _)) => self.location(container),
            _ => None,
        }
    }

    fn player(&self) -> Option<Entity> {
        if let Some(p) = self.flags.player {
            if self.is_alive(p) {
                return Some(p);
            }
        }

        None
    }

    fn tick(&self) -> u64 { self.flags.tick }

    fn rng_seed(&self) -> u32 { self.worldgen.seed() }

    fn entities(&self) -> slice::Iter<Entity> { self.ecs.iter() }

    fn entities_at(&self, loc: Location) -> Vec<Entity> { self.spatial.entities_at(loc) }

    fn entities_in(&self, parent: Entity) -> Vec<Entity> { self.spatial.entities_in(parent) }

    fn ecs(&self) -> &Ecs { &self.ecs }

    fn entity_equipped(&self, parent: Entity, slot: Slot) -> Option<Entity> {
        self.spatial.entity_equipped(parent, slot)
    }

    fn entity_contains(&self, parent: Entity, child: Entity) -> bool {
        self.spatial.contains(parent, child)
    }

    fn sphere_volume(&self, origin: Location, radius: u32) -> Volume {
        Volume::sphere(self, origin, radius)
    }
}

impl Mutate for World {
    fn next_tick(&mut self) -> CommandResult {
        use std::mem;

        self.ai_main();

        self.clean_dead();
        self.flags.tick += 1;

        // Dump events.
        let mut events = Vec::new();
        mem::swap(&mut self.events, &mut events);
        Ok(events)
    }

    fn set_entity_location(&mut self, e: Entity, loc: Location) { self.spatial.insert_at(e, loc); }

    fn equip_item(&mut self, e: Entity, parent: Entity, slot: Slot) {
        self.spatial.equip(e, parent, slot)
    }

    fn set_player(&mut self, player: Option<Entity>) { self.flags.player = player; }

    fn spawn(&mut self, loadout: &Loadout, loc: Location) -> Entity {
        let e = loadout.make(&mut self.ecs);
        self.place_entity(e, loc);
        e
    }

    fn kill_entity(&mut self, e: Entity) { self.spatial.remove(e); }

    fn remove_entity(&mut self, e: Entity) { self.ecs.remove(e); }

    fn do_fov(&mut self, e: Entity) {
        if !self.ecs.map_memory.contains(e) {
            return;
        }

        if let Some(loc) = self.location(e) {
            const DEFAULT_FOV_RANGE: u32 = 12;

            let fov: HashSet<Location> = HashSet::from_iter(
                HexFov::new(SightFov::new(self, DEFAULT_FOV_RANGE, loc))
                    .map(|(pos, a)| a.origin + pos),
            );

            let memory = &mut self.ecs.map_memory[e];
            memory.seen.clear();

            for &loc in &fov {
                memory.seen.insert(loc);
                memory.remembered.insert(loc);
            }
        }
    }

    fn push_event(&mut self, event: Event) { self.events.push(event); }

    fn rng(&mut self) -> &mut Rng { &mut self.rng }

    fn ecs_mut(&mut self) -> &mut Ecs { &mut self.ecs }
}

impl Command for World {}

impl Terraform for World {
    fn set_terrain(&mut self, _loc: Location, _terrain: Terrain) {
        unimplemented!();
    }

    fn set_portal(&mut self, _loc: Location, _portal: Portal) {
        unimplemented!();
    }

    fn remove_portal(&mut self, _loc: Location) {
        unimplemented!();
    }
}
<commit_msg>Use new RON prettyprint API<commit_after>use Rng;
use calx_ecs::Entity;
use calx_grid::HexFov;
use command::{Command, CommandResult};
use components;
use errors::*;
use event::Event;
use flags::Flags;
use fov::SightFov;
use item::Slot;
use location::{Location, Portal};
use mutate::Mutate;
use query::Query;
use rand::SeedableRng;
use ron;
use spatial::{Place, Spatial};
use std::collections::HashSet;
use std::io::{Read, Write};
use std::iter::FromIterator;
use std::slice;
use terraform::{Terraform, TerrainQuery};
use terrain::Terrain;
use volume::Volume;
use worldgen::Worldgen;

pub const GAME_VERSION: &'static str = "0.1.0";

Ecs! {
    desc: components::Desc,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    stats: components::StatsComponent,
    status: components::Statuses,
}

/// Toplevel game state object.
#[derive(Serialize, Deserialize)]
pub struct World {
    /// Game version. Not mutable in the slightest, but the simplest way to
    /// get versioned save files is to just drop it here.
    version: String,
    /// Entity component system.
    ecs: Ecs,
    /// Static startup game world
    worldgen: Worldgen,
    /// Spatial index for game entities.
    spatial: Spatial,
    /// Global gamestate flags.
    flags: Flags,
    /// Persistent random number generator.
    rng: Rng,
    /// Event queue
    events: Vec<Event>,
}

impl<'a> World {
    pub fn new(seed: u32) -> World {
        let mut ret = World {
            version: GAME_VERSION.to_string(),
            ecs: Ecs::new(),
            worldgen: Worldgen::new(seed),
            spatial: Spatial::new(),
            flags: Flags::new(),
            rng: SeedableRng::from_seed([seed, seed, seed, seed]),
            events: Vec::new(),
        };

        // XXX: Clone to not run into borrow checker...
        for (loc, spawn) in ret.worldgen
            .spawns()
            .cloned()
            .collect::<Vec<(Location, Loadout)>>()
            .into_iter()
        {
            ret.spawn(&spawn, loc);
        }

        // TODO non-lexical borrow
        let player_entry = ret.worldgen.player_entry();
        ret.spawn_player(player_entry);

        ret
    }

    pub fn load<R: Read>(reader: &mut R) -> Result<World> {
        let ret: ron::de::Result<World> = ron::de::from_reader(reader);
        if let Ok(ref x) = ret {
            if x.version != GAME_VERSION {
                panic!(
                    "Save game version {} does not match current version {}",
                    x.version,
                    GAME_VERSION
                );
            }
        }
        Ok(ret?)
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> Result<()> {
        let enc = ron::ser::to_string_pretty(self, Default::default())?;
        // TODO: Handle error from writer too...
        writeln!(writer, "{}", enc)?;
        Ok(())
    }
}

impl TerrainQuery for World {
    fn is_valid_location(&self, _loc: Location) -> bool {
        //Location::origin().v2_at(loc).map_or(false, ::on_screen)
        true
    }

    fn terrain(&self, loc: Location) -> Terrain {
        let mut t = self.worldgen.get_terrain(loc);

        if t == Terrain::Door && self.has_mobs(loc) {
            // Standing in the doorway opens the door.
            t = Terrain::OpenDoor;
        }

        t
    }

    fn portal(&self, loc: Location) -> Option<Location> { self.worldgen.get_portal(loc) }

    fn is_untouched(&self, _loc: Location) -> bool { unimplemented!() }
}

impl Query for World {
    fn location(&self, e: Entity) -> Option<Location> {
        match self.spatial.get(e) {
            Some(Place::At(loc)) => Some(loc),
            Some(Place::In(container, _)) => self.location(container),
            _ => None,
        }
    }

    fn player(&self) -> Option<Entity> {
        if let Some(p) = self.flags.player {
            if self.is_alive(p) {
                return Some(p);
            }
        }

        None
    }

    fn tick(&self) -> u64 { self.flags.tick }

    fn rng_seed(&self) -> u32 { self.worldgen.seed() }

    fn entities(&self) -> slice::Iter<Entity> { self.ecs.iter() }

    fn entities_at(&self, loc: Location) -> Vec<Entity> { self.spatial.entities_at(loc) }

    fn entities_in(&self, parent: Entity) -> Vec<Entity> { self.spatial.entities_in(parent) }

    fn ecs(&self) -> &Ecs { &self.ecs }

    fn entity_equipped(&self, parent: Entity, slot: Slot) -> Option<Entity> {
        self.spatial.entity_equipped(parent, slot)
    }

    fn entity_contains(&self, parent: Entity, child: Entity) -> bool {
        self.spatial.contains(parent, child)
    }

    fn sphere_volume(&self, origin: Location, radius: u32) -> Volume {
        Volume::sphere(self, origin, radius)
    }
}

impl Mutate for World {
    fn next_tick(&mut self) -> CommandResult {
        use std::mem;

        self.ai_main();

        self.clean_dead();
        self.flags.tick += 1;

        // Dump events.
        let mut events = Vec::new();
        mem::swap(&mut self.events, &mut events);
        Ok(events)
    }

    fn set_entity_location(&mut self, e: Entity, loc: Location) { self.spatial.insert_at(e, loc); }

    fn equip_item(&mut self, e: Entity, parent: Entity, slot: Slot) {
        self.spatial.equip(e, parent, slot)
    }

    fn set_player(&mut self, player: Option<Entity>) { self.flags.player = player; }

    fn spawn(&mut self, loadout: &Loadout, loc: Location) -> Entity {
        let e = loadout.make(&mut self.ecs);
        self.place_entity(e, loc);
        e
    }

    fn kill_entity(&mut self, e: Entity) { self.spatial.remove(e); }

    fn remove_entity(&mut self, e: Entity) { self.ecs.remove(e); }

    fn do_fov(&mut self, e: Entity) {
        if !self.ecs.map_memory.contains(e) {
            return;
        }

        if let Some(loc) = self.location(e) {
            const DEFAULT_FOV_RANGE: u32 = 12;

            let fov: HashSet<Location> = HashSet::from_iter(
                HexFov::new(SightFov::new(self, DEFAULT_FOV_RANGE, loc))
                    .map(|(pos, a)| a.origin + pos),
            );

            let memory = &mut self.ecs.map_memory[e];
            memory.seen.clear();

            for &loc in &fov {
                memory.seen.insert(loc);
                memory.remembered.insert(loc);
            }
        }
    }

    fn push_event(&mut self, event: Event) { self.events.push(event); }

    fn rng(&mut self) -> &mut Rng { &mut self.rng }

    fn ecs_mut(&mut self) -> &mut Ecs { &mut self.ecs }
}

impl Command for World {}

impl Terraform for World {
    fn set_terrain(&mut self, _loc: Location, _terrain: Terrain) {
        unimplemented!();
    }

    fn set_portal(&mut self, _loc: Location, _portal: Portal) {
        unimplemented!();
    }

    fn remove_portal(&mut self, _loc: Location) {
        unimplemented!();
    }
}
<|endoftext|>