<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 Kashyap
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![crate_name = "kernel"]
#![crate_type = "staticlib"]
#![feature(lang_items, asm)]
#![no_std]
#[lang="sized"]
#[lang="sync"]

extern crate core;

mod uart;
mod x86asm;
mod picirq;
mod traps;
mod spinlock;
mod kalloc;
mod mmu;
mod memlayout;
mod console;

fn main (end : u64) {
	unsafe {
		*((0xb8000 ) as *mut u8) = 65;
		*((0xb8001 ) as *mut u8) = 0x6;
		asm!("mov $$0xff, %eax" : /* no outputs */ : /* no inputs */ : "eax");
	}
	uart::early_init();
	kalloc::kinit1(end, memlayout::P2V(4*1024*1024));
}

#[no_mangle]
pub extern "C" fn cmain(end : u64)  {
	loop {
	main(end);
	}
        //return 255;
}

// Dummy functions to take care of missing libc function
#[no_mangle]
pub extern "C" fn trunc()  {}
#[no_mangle]
pub extern "C" fn truncf()  {}
#[no_mangle]
pub extern "C" fn floor()  {}
#[no_mangle]
pub extern "C" fn floorf()  {}
#[no_mangle]
pub extern "C" fn pow()  {}
#[no_mangle]
pub extern "C" fn powf()  {}
#[no_mangle]
pub extern "C" fn fmod()  {}
#[no_mangle]
pub extern "C" fn fmodf()  {}
#[no_mangle]
pub extern "C" fn log10()  {}
#[no_mangle]
pub extern "C" fn log10f()  {}
#[no_mangle]
pub extern "C" fn memcpy()  {}
#[no_mangle]
pub extern "C" fn memcmp()  {}
#[no_mangle]
pub extern "C" fn log()  {}
#[no_mangle]
pub extern "C" fn logf()  {}
#[no_mangle]
pub extern "C" fn log2()  {}
#[no_mangle]
pub extern "C" fn log2f()  {}
#[no_mangle]
pub extern "C" fn round()  {}
#[no_mangle]
pub extern "C" fn roundf()  {}
#[no_mangle]
pub extern "C" fn exp()  {}
#[no_mangle]
pub extern "C" fn expf()  {}
#[no_mangle]
pub extern "C" fn exp2()  {}
#[no_mangle]
pub extern "C" fn exp2f()  {}
#[no_mangle]
pub extern "C" fn ceil()  {}
#[no_mangle]
pub extern "C" fn ceilf()  {}
#[no_mangle]
pub extern "C" fn fma()  {}
#[no_mangle]
pub extern "C" fn fmaf()  {}
#[no_mangle]
pub extern "C" fn __powisf2()  {}
#[no_mangle]
pub extern "C" fn __powidf2()  {}

#[lang = "stack_exhausted"] extern fn stack_exhausted() { loop {} }
#[lang = "eh_personality"] extern fn eh_personality() {loop {} }
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
<commit_msg>call panic in the unimplemented functions<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 Kashyap
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![crate_name = "kernel"]
#![crate_type = "staticlib"]
#![feature(lang_items, asm)]
#![no_std]
#[lang="sized"]
#[lang="sync"]

extern crate core;

mod uart;
mod x86asm;
mod picirq;
mod traps;
mod spinlock;
mod kalloc;
mod mmu;
mod memlayout;
mod console;

fn main (end : u64) {
	unsafe {
		*((0xb8000 ) as *mut u8) = 65;
		*((0xb8001 ) as *mut u8) = 0x6;
		asm!("mov $$0xff, %eax" : /* no outputs */ : /* no inputs */ : "eax");
	}
	uart::early_init();
	kalloc::kinit1(end, memlayout::P2V(4*1024*1024));
}

#[no_mangle]
pub extern "C" fn cmain(end : u64)  {
	loop {
	main(end);
	}
        //return 255;
}

// Dummy functions to take care of missing libc function
#[no_mangle]
pub extern "C" fn trunc()  {console::panic("trunc: console::panic!!!");}
#[no_mangle]
pub extern "C" fn truncf()  {console::panic("truncf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn floor()  {console::panic("floor: console::panic!!!");}
#[no_mangle]
pub extern "C" fn floorf()  {console::panic("floorf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn pow()  {console::panic("pow: console::panic!!!");}
#[no_mangle]
pub extern "C" fn powf()  {console::panic("powf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn fmod()  {console::panic("fmod: console::panic!!!");}
#[no_mangle]
pub extern "C" fn fmodf()  {console::panic("fmodf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn log10()  {console::panic("log10: console::panic!!!");}
#[no_mangle]
pub extern "C" fn log10f()  {console::panic("log10f: console::panic!!!");}
#[no_mangle]
pub extern "C" fn memcpy()  {console::panic("memcpy: console::panic!!!");}
#[no_mangle]
pub extern "C" fn memcmp()  {console::panic("memcmp: console::panic!!!");}
#[no_mangle]
pub extern "C" fn log()  {console::panic("log: console::panic!!!");}
#[no_mangle]
pub extern "C" fn logf()  {console::panic("logf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn log2()  {console::panic("log2: console::panic!!!");}
#[no_mangle]
pub extern "C" fn log2f()  {console::panic("log2f: console::panic!!!");}
#[no_mangle]
pub extern "C" fn round()  {console::panic("round: console::panic!!!");}
#[no_mangle]
pub extern "C" fn roundf()  {console::panic("roundf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn exp()  {console::panic("exp: console::panic!!!");}
#[no_mangle]
pub extern "C" fn expf()  {console::panic("expf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn exp2()  {console::panic("exp2: console::panic!!!");}
#[no_mangle]
pub extern "C" fn exp2f()  {console::panic("exp2f: console::panic!!!");}
#[no_mangle]
pub extern "C" fn ceil()  {console::panic("ceil: console::panic!!!");}
#[no_mangle]
pub extern "C" fn ceilf()  {console::panic("ceilf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn fma()  {console::panic("fma: console::panic!!!");}
#[no_mangle]
pub extern "C" fn fmaf()  {console::panic("fmaf: console::panic!!!");}
#[no_mangle]
pub extern "C" fn __powisf2()  {console::panic("__powisf2: console::panic!!!");}
#[no_mangle]
pub extern "C" fn __powidf2()  {console::panic("__powidf2: console::panic!!!");}

#[lang = "stack_exhausted"] extern fn stack_exhausted() { loop {} }
#[lang = "eh_personality"] extern fn eh_personality() {loop {} }
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
<|endoftext|>


<commit_before>mod object;
mod pointer;

pub use self::{
    object::{Builtin, Closure, Data, Int, Object, Struct, Symbol, Text},
    pointer::Pointer,
};
use crate::builtin_functions::BuiltinFunction;
use itertools::Itertools;
use num_bigint::BigInt;
use std::{cmp::Ordering, collections::HashMap};

#[derive(Clone)]
pub struct Heap {
    objects: HashMap<Pointer, Object>,
    next_address: Pointer,
}

impl std::fmt::Debug for Heap {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut objects = self.objects.clone().into_iter().collect_vec();
        objects.sort_by_key(|(address, _)| address.raw());

        writeln!(f, "{{")?;
        for (address, object) in objects {
            writeln!(
                f,
                "{address}: {} {}",
                object.reference_count,
                address.format(self),
            )?;
        }
        write!(f, "}}")
    }
}

impl Default for Heap {
    fn default() -> Self {
        Self {
            objects: HashMap::new(),
            next_address: Pointer::from_raw(1),
        }
    }
}
impl Heap {
    pub fn get(&self, address: Pointer) -> &Object {
        self.objects
            .get(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }
    pub fn get_mut(&mut self, address: Pointer) -> &mut Object {
        self.objects
            .get_mut(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }

    pub fn dup(&mut self, address: Pointer) {
        self.get_mut(address).reference_count += 1;
        log::trace!(
            "RefCount of {address} increased to {}. Value: {}",
            self.get(address).reference_count,
            address.format(self),
        );
    }
    pub fn drop(&mut self, address: Pointer) {
        let formatted_value = address.format(self);
        let object = self.get_mut(address);
        object.reference_count -= 1;
        log::trace!(
            "RefCount of {address} reduced to {}. Value: {formatted_value}",
            object.reference_count,
        );
        if object.reference_count == 0 {
            self.free(address);
        }
    }

    pub fn create(&mut self, object: Data) -> Pointer {
        let address = self.next_address;
        self.objects.insert(
            address,
            Object {
                reference_count: 1,
                data: object,
            },
        );
        log::trace!("Created object {} at {address}.", address.format(self));
        self.next_address = Pointer::from_raw(self.next_address.raw() + 1);
        address
    }
    pub fn free(&mut self, address: Pointer) {
        let object = self.objects.remove(&address).unwrap();
        log::trace!("Freeing object at {address}.");
        assert_eq!(object.reference_count, 0);
        for child in object.children() {
            self.drop(child);
        }
    }

    /// Clones all objects at the `root_addresses` into the `other` heap and
    /// returns a list of their addresses in the other heap.
    pub fn clone_multiple_to_other_heap(
        &self,
        other: &mut Heap,
        addresses: &[Pointer],
    ) -> Vec<Pointer> {
        let mut objects_to_refcounts = HashMap::new();
        for address in addresses {
            self.gather_objects_to_clone(&mut objects_to_refcounts, *address);
        }
        let num_objects = objects_to_refcounts.len();

        let address_map: HashMap<Pointer, Pointer> = objects_to_refcounts
            .keys()
            .copied()
            .zip(
                (other.next_address.raw()..other.next_address.raw() + num_objects)
                    .map(Pointer::from_raw),
            )
            .collect();

        for (address, refcount) in objects_to_refcounts {
            other.objects.insert(
                address_map[&address],
                Object {
                    reference_count: refcount,
                    data: Self::map_addresses_in_data(&address_map, &self.get(address).data),
                },
            );
        }
        other.next_address = Pointer::from_raw(other.next_address.raw() + num_objects);

        addresses
            .iter()
            .map(|address| address_map[address])
            .collect()
    }
    fn gather_objects_to_clone(
        &self,
        objects_to_refcounts: &mut HashMap<Pointer, usize>,
        address: Pointer,
    ) {
        *objects_to_refcounts.entry(address).or_default() += 1;
        for child in self.get(address).children() {
            self.gather_objects_to_clone(objects_to_refcounts, child);
        }
    }
    fn map_addresses_in_data(address_map: &HashMap<Pointer, Pointer>, data: &Data) -> Data {
        match data {
            Data::Int(int) => Data::Int(int.clone()),
            Data::Text(text) => Data::Text(text.clone()),
            Data::Symbol(symbol) => Data::Symbol(symbol.clone()),
            Data::Struct(struct_) => Data::Struct(Struct {
                fields: struct_
                    .fields
                    .iter()
                    .map(|(hash, key, value)| (*hash, address_map[key], address_map[value]))
                    .collect_vec(),
            }),
            Data::Closure(closure) => Data::Closure(Closure {
                captured: closure
                    .captured
                    .iter()
                    .map(|address| address_map[address])
                    .collect(),
                num_args: closure.num_args,
                body: closure.body.clone(),
            }),
            Data::Builtin(builtin) => Data::Builtin(builtin.clone()),
        }
    }
    pub fn clone_single_to_other_heap(&self, other: &mut Heap, address: Pointer) -> Pointer {
        self.clone_multiple_to_other_heap(other, &[address])
            .pop()
            .unwrap()
    }

    pub fn create_int(&mut self, int: BigInt) -> Pointer {
        self.create(Data::Int(Int { value: int }))
    }
    pub fn create_text(&mut self, text: String) -> Pointer {
        self.create(Data::Text(Text { value: text }))
    }
    pub fn create_symbol(&mut self, symbol: String) -> Pointer {
        self.create(Data::Symbol(Symbol { value: symbol }))
    }
    pub fn create_struct(&mut self, fields: HashMap<Pointer, Pointer>) -> Pointer {
        self.create(Data::Struct(Struct::from_fields(self, fields)))
    }
    pub fn create_closure(&mut self, closure: Closure) -> Pointer {
        self.create(Data::Closure(closure))
    }
    pub fn create_builtin(&mut self, builtin: BuiltinFunction) -> Pointer {
        self.create(Data::Builtin(Builtin { function: builtin }))
    }
    pub fn create_nothing(&mut self) -> Pointer {
        self.create_symbol("Nothing".to_string())
    }
    pub fn create_list(&mut self, items: Vec<Pointer>) -> Pointer {
        let mut fields = vec![];
        for (index, item) in items.into_iter().enumerate() {
            fields.push((self.create_int(index.into()), item));
        }
        self.create_struct(fields.into_iter().collect())
    }
    pub fn create_bool(&mut self, value: bool) -> Pointer {
        self.create_symbol(if value { "True" } else { "False" }.to_string())
    }
    pub fn create_result(&mut self, result: Result<Pointer, Pointer>) -> Pointer {
        let (type_, value) = match result {
            Ok(it) => ("Ok".to_string(), it),
            Err(it) => ("Error".to_string(), it),
        };
        let fields = HashMap::from([
            (
                self.create_symbol("Type".to_string()),
                self.create_symbol(type_),
            ),
            (self.create_symbol("Value".to_string()), value),
        ]);
        self.create_struct(fields)
    }
    pub fn create_ordering(&mut self, ordering: Ordering) -> Pointer {
        self.create_symbol(
            match ordering {
                Ordering::Less => "Less",
                Ordering::Equal => "Equal",
                Ordering::Greater => "Greater",
            }
            .to_string(),
        )
    }
}
<commit_msg>Make formatting of heap more efficient<commit_after>mod object;
mod pointer;

pub use self::{
    object::{Builtin, Closure, Data, Int, Object, Struct, Symbol, Text},
    pointer::Pointer,
};
use crate::builtin_functions::BuiltinFunction;
use itertools::Itertools;
use num_bigint::BigInt;
use std::{cmp::Ordering, collections::HashMap};

#[derive(Clone)]
pub struct Heap {
    objects: HashMap<Pointer, Object>,
    next_address: Pointer,
}

impl std::fmt::Debug for Heap {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut objects = self.objects.iter().collect_vec();
        objects.sort_by_key(|(address, _)| address.raw());

        writeln!(f, "{{")?;
        for (address, object) in objects {
            writeln!(
                f,
                "{address}: {} {}",
                object.reference_count,
                object.format(self),
            )?;
        }
        write!(f, "}}")
    }
}

impl Default for Heap {
    fn default() -> Self {
        Self {
            objects: HashMap::new(),
            next_address: Pointer::from_raw(1),
        }
    }
}
impl Heap {
    pub fn get(&self, address: Pointer) -> &Object {
        self.objects
            .get(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }
    pub fn get_mut(&mut self, address: Pointer) -> &mut Object {
        self.objects
            .get_mut(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }

    pub fn dup(&mut self, address: Pointer) {
        self.get_mut(address).reference_count += 1;
        log::trace!(
            "RefCount of {address} increased to {}. Value: {}",
            self.get(address).reference_count,
            address.format(self),
        );
    }
    pub fn drop(&mut self, address: Pointer) {
        let formatted_value = address.format(self);
        let object = self.get_mut(address);
        object.reference_count -= 1;
        log::trace!(
            "RefCount of {address} reduced to {}. Value: {formatted_value}",
            object.reference_count,
        );
        if object.reference_count == 0 {
            self.free(address);
        }
    }

    pub fn create(&mut self, object: Data) -> Pointer {
        let address = self.next_address;
        self.objects.insert(
            address,
            Object {
                reference_count: 1,
                data: object,
            },
        );
        log::trace!("Created object {} at {address}.", address.format(self));
        self.next_address = Pointer::from_raw(self.next_address.raw() + 1);
        address
    }
    pub fn free(&mut self, address: Pointer) {
        let object = self.objects.remove(&address).unwrap();
        log::trace!("Freeing object at {address}.");
        assert_eq!(object.reference_count, 0);
        for child in object.children() {
            self.drop(child);
        }
    }

    /// Clones all objects at the `root_addresses` into the `other` heap and
    /// returns a list of their addresses in the other heap.
    pub fn clone_multiple_to_other_heap(
        &self,
        other: &mut Heap,
        addresses: &[Pointer],
    ) -> Vec<Pointer> {
        let mut objects_to_refcounts = HashMap::new();
        for address in addresses {
            self.gather_objects_to_clone(&mut objects_to_refcounts, *address);
        }
        let num_objects = objects_to_refcounts.len();

        let address_map: HashMap<Pointer, Pointer> = objects_to_refcounts
            .keys()
            .copied()
            .zip(
                (other.next_address.raw()..other.next_address.raw() + num_objects)
                    .map(Pointer::from_raw),
            )
            .collect();

        for (address, refcount) in objects_to_refcounts {
            other.objects.insert(
                address_map[&address],
                Object {
                    reference_count: refcount,
                    data: Self::map_addresses_in_data(&address_map, &self.get(address).data),
                },
            );
        }
        other.next_address = Pointer::from_raw(other.next_address.raw() + num_objects);

        addresses
            .iter()
            .map(|address| address_map[address])
            .collect()
    }
    fn gather_objects_to_clone(
        &self,
        objects_to_refcounts: &mut HashMap<Pointer, usize>,
        address: Pointer,
    ) {
        *objects_to_refcounts.entry(address).or_default() += 1;
        for child in self.get(address).children() {
            self.gather_objects_to_clone(objects_to_refcounts, child);
        }
    }
    fn map_addresses_in_data(address_map: &HashMap<Pointer, Pointer>, data: &Data) -> Data {
        match data {
            Data::Int(int) => Data::Int(int.clone()),
            Data::Text(text) => Data::Text(text.clone()),
            Data::Symbol(symbol) => Data::Symbol(symbol.clone()),
            Data::Struct(struct_) => Data::Struct(Struct {
                fields: struct_
                    .fields
                    .iter()
                    .map(|(hash, key, value)| (*hash, address_map[key], address_map[value]))
                    .collect_vec(),
            }),
            Data::Closure(closure) => Data::Closure(Closure {
                captured: closure
                    .captured
                    .iter()
                    .map(|address| address_map[address])
                    .collect(),
                num_args: closure.num_args,
                body: closure.body.clone(),
            }),
            Data::Builtin(builtin) => Data::Builtin(builtin.clone()),
        }
    }
    pub fn clone_single_to_other_heap(&self, other: &mut Heap, address: Pointer) -> Pointer {
        self.clone_multiple_to_other_heap(other, &[address])
            .pop()
            .unwrap()
    }

    pub fn create_int(&mut self, int: BigInt) -> Pointer {
        self.create(Data::Int(Int { value: int }))
    }
    pub fn create_text(&mut self, text: String) -> Pointer {
        self.create(Data::Text(Text { value: text }))
    }
    pub fn create_symbol(&mut self, symbol: String) -> Pointer {
        self.create(Data::Symbol(Symbol { value: symbol }))
    }
    pub fn create_struct(&mut self, fields: HashMap<Pointer, Pointer>) -> Pointer {
        self.create(Data::Struct(Struct::from_fields(self, fields)))
    }
    pub fn create_closure(&mut self, closure: Closure) -> Pointer {
        self.create(Data::Closure(closure))
    }
    pub fn create_builtin(&mut self, builtin: BuiltinFunction) -> Pointer {
        self.create(Data::Builtin(Builtin { function: builtin }))
    }
    pub fn create_nothing(&mut self) -> Pointer {
        self.create_symbol("Nothing".to_string())
    }
    pub fn create_list(&mut self, items: Vec<Pointer>) -> Pointer {
        let mut fields = vec![];
        for (index, item) in items.into_iter().enumerate() {
            fields.push((self.create_int(index.into()), item));
        }
        self.create_struct(fields.into_iter().collect())
    }
    pub fn create_bool(&mut self, value: bool) -> Pointer {
        self.create_symbol(if value { "True" } else { "False" }.to_string())
    }
    pub fn create_result(&mut self, result: Result<Pointer, Pointer>) -> Pointer {
        let (type_, value) = match result {
            Ok(it) => ("Ok".to_string(), it),
            Err(it) => ("Error".to_string(), it),
        };
        let fields = HashMap::from([
            (
                self.create_symbol("Type".to_string()),
                self.create_symbol(type_),
            ),
            (self.create_symbol("Value".to_string()), value),
        ]);
        self.create_struct(fields)
    }
    pub fn create_ordering(&mut self, ordering: Ordering) -> Pointer {
        self.create_symbol(
            match ordering {
                Ordering::Less => "Less",
                Ordering::Equal => "Equal",
                Ordering::Greater => "Greater",
            }
            .to_string(),
        )
    }
}
<|endoftext|>


<commit_before>use crate::size_hint;

/// An iterator adaptor that allows putting multiple
/// items in front of the iterator.
///
/// Iterator element type is `I::Item`.
#[derive(Debug, Clone)]
pub struct PutBackN<I: Iterator> {
    top: Vec<I::Item>,
    iter: I,
}

/// Create an iterator where you can put back multiple values to the front
/// of the iteration.
///
/// Iterator element type is `I::Item`.
pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
    where I: IntoIterator
{
    PutBackN {
        top: Vec::new(),
        iter: iterable.into_iter(),
    }
}

impl<I: Iterator> PutBackN<I> {
    /// Puts x in front of the iterator.
    /// The values are yielded in order of the most recently put back
    /// values first.
    ///
    /// ```rust
    /// use itertools::put_back_n;
    ///
    /// let mut it = put_back_n(1..5);
    /// it.next();
    /// it.put_back(1);
    /// it.put_back(0);
    ///
    /// assert!(itertools::equal(it, 0..5));
    /// ```
    #[inline]
    pub fn put_back(&mut self, x: I::Item) {
        self.top.push(x);
    }
}

impl<I: Iterator> Iterator for PutBackN<I> {
    type Item = I::Item;
    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        if self.top.is_empty() {
            self.iter.next()
        } else {
            self.top.pop()
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.iter.size_hint(), self.top.len())
    }
}

<commit_msg>Prefer pop over explicit is_empty<commit_after>use crate::size_hint;

/// An iterator adaptor that allows putting multiple
/// items in front of the iterator.
///
/// Iterator element type is `I::Item`.
#[derive(Debug, Clone)]
pub struct PutBackN<I: Iterator> {
    top: Vec<I::Item>,
    iter: I,
}

/// Create an iterator where you can put back multiple values to the front
/// of the iteration.
///
/// Iterator element type is `I::Item`.
pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
    where I: IntoIterator
{
    PutBackN {
        top: Vec::new(),
        iter: iterable.into_iter(),
    }
}

impl<I: Iterator> PutBackN<I> {
    /// Puts x in front of the iterator.
    /// The values are yielded in order of the most recently put back
    /// values first.
    ///
    /// ```rust
    /// use itertools::put_back_n;
    ///
    /// let mut it = put_back_n(1..5);
    /// it.next();
    /// it.put_back(1);
    /// it.put_back(0);
    ///
    /// assert!(itertools::equal(it, 0..5));
    /// ```
    #[inline]
    pub fn put_back(&mut self, x: I::Item) {
        self.top.push(x);
    }
}

impl<I: Iterator> Iterator for PutBackN<I> {
    type Item = I::Item;
    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        self.top.pop().or_else(|| self.iter.next())
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.iter.size_hint(), self.top.len())
    }
}

<|endoftext|>


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

use resource_task::{Done, LoadResponse, LoadData, start_sending};
use http_loader;
use http::headers::HeaderEnum;
use servo_util::task::spawn_named;
use std::ascii::AsciiExt;
use std::comm::{channel, Sender};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    spawn_named("ws_loader", proc() load(load_data, start_chan))
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let(sen, rec) = channel();
    http_loader::load(load_data, sen);
    let response=rec.recv();
    let mut flag: int = 0;

    response.metadata.headers.as_ref().map(|headers| {
        let header = headers.iter().find(|h|
            h.header_name().as_slice().to_ascii_lower() == "upgrade".to_string()
        );
        match header {
            Some(h) => {    if h.header_value().as_slice().to_ascii_lower() == "websocket".to_string()
                            {
                                flag = flag + 1
                            }
                       },
            None => {}
        }
    });

    let progress_chan = start_sending(start_chan, response.metadata);
    if flag == 1
    {
       progress_chan.send(Done(Ok(())));
    } else {
       progress_chan.send(Done(Err("invalid upgrade header value".to_string())));
    }
}
<commit_msg>pending indentation issues<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use http_loader;
use http::headers::HeaderEnum;
use resource_task::{Done, LoadResponse, LoadData, start_sending};
use servo_util::task::spawn_named;
use std::ascii::AsciiExt;
use std::comm::{channel, Sender};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    spawn_named("ws_loader", proc() load(load_data, start_chan))
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let(sen, rec) = channel();
    http_loader::load(load_data, sen);
    let response=rec.recv();
    let mut flag: int = 0;

    response.metadata.headers.as_ref().map(|headers| {
        let header = headers.iter().find(|h|
            h.header_name().as_slice().to_ascii_lower() == "upgrade".to_string()
        );
        match header {
            Some(h) => {    if h.header_value().as_slice().to_ascii_lower() == "websocket".to_string()
                            {
                                flag = flag + 1
                            }
                       },
            None => {}
        }
    });

    let progress_chan = start_sending(start_chan, response.metadata);
    if flag == 1
    {
       progress_chan.send(Done(Ok(())));
    } else {
       progress_chan.send(Done(Err("invalid upgrade header value".to_string())));
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![allow(visible_private_types)]
#![allow(non_camel_case_types)]

extern "rust-intrinsic" {
    fn offset<T>(dst: *mut T, offset: int) -> *mut T;
}

extern "rust-intrinsic" {
    fn offset<T>(dst: *const T, offset: int) -> *const T;
}

type c_int = i32;

#[no_mangle]
pub extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: int) {
    unsafe {
        let mut i = 0;
        while i < n {
            *(offset(dest, i) as *mut u8) = *(offset(src, i));
            i += 1;
        }
    }
}

#[no_mangle]
pub extern "C" fn memmove(dest: *mut u8, src: *const u8, n: int) {
    unsafe {
        if src < dest as *const u8 { // copy from end
            let mut i = n;
            while i != 0 {
                i -= 1;
                *(offset(dest, i) as *mut u8) = *(offset(src, i));
            }
        } else { // copy from beginning
            let mut i = 0;
            while i < n {
                *(offset(dest, i) as *mut u8) = *(offset(src, i));
                i += 1;
            }
        }
    }
}

#[no_mangle]
pub extern "C" fn memset(s: *mut u8, c: c_int, n: int) {
    unsafe {
        let mut i = 0;
        while i < n {
            *(offset(s, i) as *mut u8) = c as u8;
            i += 1;
        }
    }
}
<commit_msg>minor pointer fix for arm build<commit_after>#![no_std]
#![allow(visible_private_types)]
#![allow(non_camel_case_types)]

extern "rust-intrinsic" {
    fn offset<T>(dst: *const T, offset: int) -> *const T;
}

type c_int = i32;

#[no_mangle]
pub extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: int) {
    unsafe {
        let mut i = 0;
        while i < n {
            *(offset(dest as *const u8, i) as *mut u8) = *(offset(src, i));
            i += 1;
        }
    }
}

#[no_mangle]
pub extern "C" fn memmove(dest: *mut u8, src: *const u8, n: int) {
    unsafe {
        if src < dest as *const u8 { // copy from end
            let mut i = n;
            while i != 0 {
                i -= 1;
                *(offset(dest as *const u8, i) as *mut u8) = *(offset(src, i));
            }
        } else { // copy from beginning
            let mut i = 0;
            while i < n {
                *(offset(dest as *const u8, i) as *mut u8) = *(offset(src, i));
                i += 1;
            }
        }
    }
}

#[no_mangle]
pub extern "C" fn memset(s: *mut u8, c: c_int, n: int) {
    unsafe {
        let mut i = 0;
        while i < n {
            *(offset(s as *const u8, i) as *mut u8) = c as u8;
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before>use parking_lot::Mutex;
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::{Arc, Weak};
use uuid::Uuid;

struct EventHandlersList<F> {
    index: usize,
    callbacks: HashMap<usize, F>,
}

impl<F> Default for EventHandlersList<F> {
    fn default() -> Self {
        Self {
            index: 0,
            callbacks: HashMap::new(),
        }
    }
}

#[derive(Clone)]
pub(super) struct EventHandlers<F> {
    handlers: Arc<Mutex<HashMap<SubscriptionTarget, EventHandlersList<F>>>>,
}

impl<F: Sized + Send + Sync + 'static> EventHandlers<F> {
    pub(super) fn new() -> Self {
        let handlers = Arc::<Mutex<HashMap<SubscriptionTarget, EventHandlersList<F>>>>::default();
        Self { handlers }
    }

    pub(super) fn add(&self, target_id: SubscriptionTarget, callback: F) -> SubscriptionHandler {
        let index;
        {
            let mut event_handlers = self.handlers.lock();
            let list = event_handlers
                .entry(target_id)
                .or_insert_with(EventHandlersList::default);
            index = list.index;
            list.index += 1;
            list.callbacks.insert(index, callback);
            drop(event_handlers);
        }

        SubscriptionHandler::new({
            let event_handlers_weak = Arc::downgrade(&self.handlers);

            Box::new(move || {
                if let Some(event_handlers) = event_handlers_weak.upgrade() {
                    // We store removed handler here in order to drop after `event_handlers` lock is
                    // released, otherwise handler will be dropped on removal from callbacks
                    // immediately and if it happens to hold another entity that held subscription
                    // handler, we may arrive here again trying to acquire lock that we didn't
                    // release yet. By dropping callback only when lock is released we avoid
                    // deadlocking.
                    let removed_handler;
                    {
                        let mut handlers = event_handlers.lock();
                        let is_empty = {
                            let list = handlers.get_mut(&target_id).unwrap();
                            removed_handler = list.callbacks.remove(&index);
                            list.callbacks.is_empty()
                        };
                        if is_empty {
                            handlers.remove(&target_id);
                        }
                    }
                    drop(removed_handler);
                }
            })
        })
    }

    pub(super) fn downgrade(&self) -> WeakEventHandlers<F> {
        WeakEventHandlers {
            handlers: Arc::downgrade(&self.handlers),
        }
    }
}

impl<V: ?Sized> EventHandlers<Arc<dyn Fn(&V) + Send + Sync + 'static>> {
    pub(super) fn call_callbacks_with_single_value(
        &self,
        target_id: &SubscriptionTarget,
        value: &V,
    ) {
        let handlers = self.handlers.lock();
        if let Some(list) = handlers.get(target_id) {
            // Tiny optimization that avoids cloning `value` unless necessary
            if list.callbacks.len() == 1 {
                let callback = list.callbacks.values().next().cloned().unwrap();
                // Drop mutex guard before running callbacks to avoid deadlocks
                drop(handlers);
                callback(value);
            } else {
                let callbacks = list.callbacks.values().cloned().collect::<Vec<_>>();
                // Drop mutex guard before running callbacks to avoid deadlocks
                drop(handlers);
                for callback in callbacks {
                    callback(value);
                }
            }
        }
    }
}

impl<V1: ?Sized, V2: ?Sized> EventHandlers<Arc<dyn Fn(&V1, &V2) + Send + Sync + 'static>> {
    pub(super) fn call_callbacks_with_two_values(
        &self,
        target_id: &SubscriptionTarget,
        value1: &V1,
        value2: &V2,
    ) {
        let handlers = self.handlers.lock();
        if let Some(list) = handlers.get(target_id) {
            // Tiny optimization that avoids cloning `value` unless necessary
            if list.callbacks.len() == 1 {
                let callback = list.callbacks.values().next().cloned().unwrap();
                // Drop mutex guard before running callbacks to avoid deadlocks
                drop(handlers);
                callback(value1, value2);
            } else {
                let callbacks = list.callbacks.values().cloned().collect::<Vec<_>>();
                // Drop mutex guard before running callbacks to avoid deadlocks
                drop(handlers);
                for callback in callbacks {
                    callback(value1, value2);
                }
            }
        }
    }
}

#[derive(Clone)]
pub(super) struct WeakEventHandlers<F> {
    handlers: Weak<Mutex<HashMap<SubscriptionTarget, EventHandlersList<F>>>>,
}

impl<F> WeakEventHandlers<F> {
    pub(super) fn upgrade(&self) -> Option<EventHandlers<F>> {
        self.handlers
            .upgrade()
            .map(|handlers| EventHandlers { handlers })
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize)]
#[serde(untagged)]
pub(crate) enum SubscriptionTarget {
    Uuid(Uuid),
    Number(u64),
}

impl From<u32> for SubscriptionTarget {
    fn from(number: u32) -> Self {
        Self::Number(u64::from(number))
    }
}

impl From<u64> for SubscriptionTarget {
    fn from(number: u64) -> Self {
        Self::Number(number)
    }
}

/// Subscription handler, will remove corresponding subscription when dropped
pub(crate) struct SubscriptionHandler {
    remove_callback: Option<Box<dyn FnOnce() + Send + Sync>>,
}

impl SubscriptionHandler {
    fn new(remove_callback: Box<dyn FnOnce() + Send + Sync>) -> Self {
        Self {
            remove_callback: Some(remove_callback),
        }
    }
}

impl Drop for SubscriptionHandler {
    fn drop(&mut self) {
        let remove_callback = self.remove_callback.take().unwrap();
        remove_callback();
    }
}
<commit_msg>Avoid cloning for internal notifications, they are guaranteed to be non-recursive and thus can't deadlock<commit_after>use parking_lot::Mutex;
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::{Arc, Weak};
use uuid::Uuid;

struct EventHandlersList<F> {
    index: usize,
    callbacks: HashMap<usize, F>,
}

impl<F> Default for EventHandlersList<F> {
    fn default() -> Self {
        Self {
            index: 0,
            callbacks: HashMap::new(),
        }
    }
}

#[derive(Clone)]
pub(super) struct EventHandlers<F> {
    handlers: Arc<Mutex<HashMap<SubscriptionTarget, EventHandlersList<F>>>>,
}

impl<F: Sized + Send + Sync + 'static> EventHandlers<F> {
    pub(super) fn new() -> Self {
        let handlers = Arc::<Mutex<HashMap<SubscriptionTarget, EventHandlersList<F>>>>::default();
        Self { handlers }
    }

    pub(super) fn add(&self, target_id: SubscriptionTarget, callback: F) -> SubscriptionHandler {
        let index;
        {
            let mut event_handlers = self.handlers.lock();
            let list = event_handlers
                .entry(target_id)
                .or_insert_with(EventHandlersList::default);
            index = list.index;
            list.index += 1;
            list.callbacks.insert(index, callback);
            drop(event_handlers);
        }

        SubscriptionHandler::new({
            let event_handlers_weak = Arc::downgrade(&self.handlers);

            Box::new(move || {
                if let Some(event_handlers) = event_handlers_weak.upgrade() {
                    // We store removed handler here in order to drop after `event_handlers` lock is
                    // released, otherwise handler will be dropped on removal from callbacks
                    // immediately and if it happens to hold another entity that held subscription
                    // handler, we may arrive here again trying to acquire lock that we didn't
                    // release yet. By dropping callback only when lock is released we avoid
                    // deadlocking.
                    let removed_handler;
                    {
                        let mut handlers = event_handlers.lock();
                        let is_empty = {
                            let list = handlers.get_mut(&target_id).unwrap();
                            removed_handler = list.callbacks.remove(&index);
                            list.callbacks.is_empty()
                        };
                        if is_empty {
                            handlers.remove(&target_id);
                        }
                    }
                    drop(removed_handler);
                }
            })
        })
    }

    pub(super) fn downgrade(&self) -> WeakEventHandlers<F> {
        WeakEventHandlers {
            handlers: Arc::downgrade(&self.handlers),
        }
    }
}

impl<V: ?Sized> EventHandlers<Arc<dyn Fn(&V) + Send + Sync + 'static>> {
    pub(super) fn call_callbacks_with_single_value(
        &self,
        target_id: &SubscriptionTarget,
        value: &V,
    ) {
        let handlers = self.handlers.lock();
        if let Some(list) = handlers.get(target_id) {
            for callback in list.callbacks.values() {
                callback(value);
            }
        }
    }
}

impl<V1: ?Sized, V2: ?Sized> EventHandlers<Arc<dyn Fn(&V1, &V2) + Send + Sync + 'static>> {
    pub(super) fn call_callbacks_with_two_values(
        &self,
        target_id: &SubscriptionTarget,
        value1: &V1,
        value2: &V2,
    ) {
        let handlers = self.handlers.lock();
        if let Some(list) = handlers.get(target_id) {
            for callback in list.callbacks.values() {
                callback(value1, value2);
            }
        }
    }
}

#[derive(Clone)]
pub(super) struct WeakEventHandlers<F> {
    handlers: Weak<Mutex<HashMap<SubscriptionTarget, EventHandlersList<F>>>>,
}

impl<F> WeakEventHandlers<F> {
    pub(super) fn upgrade(&self) -> Option<EventHandlers<F>> {
        self.handlers
            .upgrade()
            .map(|handlers| EventHandlers { handlers })
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize)]
#[serde(untagged)]
pub(crate) enum SubscriptionTarget {
    Uuid(Uuid),
    Number(u64),
}

impl From<u32> for SubscriptionTarget {
    fn from(number: u32) -> Self {
        Self::Number(u64::from(number))
    }
}

impl From<u64> for SubscriptionTarget {
    fn from(number: u64) -> Self {
        Self::Number(number)
    }
}

/// Subscription handler, will remove corresponding subscription when dropped
pub(crate) struct SubscriptionHandler {
    remove_callback: Option<Box<dyn FnOnce() + Send + Sync>>,
}

impl SubscriptionHandler {
    fn new(remove_callback: Box<dyn FnOnce() + Send + Sync>) -> Self {
        Self {
            remove_callback: Some(remove_callback),
        }
    }
}

impl Drop for SubscriptionHandler {
    fn drop(&mut self) {
        let remove_callback = self.remove_callback.take().unwrap();
        remove_callback();
    }
}
<|endoftext|>


<commit_before>pub mod specifiers_iterator;

use std::ffi::CString;
use std::vec::Vec;

/// Helper function for `fmt!`. Don't use directly.
pub fn fmt_arg<T>(format: &str, arg: T) -> Option<String> {
    // Might fail if `format` contains a null byte. TODO decide if this is a good
    // error-handling strategy, or we should report back to user, or panic, or what
    CString::new(format).ok().and_then(|local_format_cstring| {
        let buf_size = 1024usize;
        let mut buffer = Vec::<u8>::with_capacity(buf_size);
        // Filling the vector with ones because CString::new() doesn't want any zeroes in
        // there. The last byte is left unused, so that CString::new() can put a terminating
        // zero byte without triggering a re-allocation.
        buffer.resize(buf_size - 1, 1);
        CString::new(buffer).ok().and_then(|buffer| unsafe {
            let buffer_ptr = buffer.into_raw();
            // TODO: check how many bytes were written
            let bytes_written = libc::snprintf(
                buffer_ptr,
                buf_size as libc::size_t,
                local_format_cstring.as_ptr() as *const libc::c_char,
                arg,
            );
            let buffer = CString::from_raw(buffer_ptr);
            let _bytes_written = bytes_written as usize;
            buffer.into_string().ok()
        })
    })
}

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                if let Some(formatted_string) = $crate::fmt_arg(local_format, $arg) {
                    result.push_str(&formatted_string);
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_i32() {
        assert_eq!(fmt!("%i", 42i32), "42");
        assert_eq!(fmt!("%i", std::i32::MIN), "-2147483648");
        assert_eq!(fmt!("%i", std::i32::MAX), "2147483647");
    }

    #[test]
    fn formats_u32() {
        assert_eq!(fmt!("%u", 42u32), "42");
        assert_eq!(fmt!("%u", 0u32), "0");
        assert_eq!(fmt!("%u", std::u32::MAX), "4294967295");
    }

    #[test]
    fn formats_i64() {
        assert_eq!(fmt!("%li", 42i64), "42");
        assert_eq!(fmt!("%li", std::i32::MIN as i64 - 1), "-2147483649");
        assert_eq!(fmt!("%li", std::i32::MAX as i64 + 1), "2147483648");

        assert_eq!(fmt!("%lli", 42i64), "42");
        assert_eq!(fmt!("%lli", std::i64::MIN), "-9223372036854775808");
        assert_eq!(fmt!("%lli", std::i64::MAX), "9223372036854775807");
    }

    #[test]
    fn formats_u64() {
        assert_eq!(fmt!("%lu", 42u64), "42");
        assert_eq!(fmt!("%lu", 0u64), "0");
        assert_eq!(fmt!("%lu", std::u64::MAX), "18446744073709551615");

        assert_eq!(fmt!("%llu", 42u64), "42");
        assert_eq!(fmt!("%llu", 0u64), "0");
        assert_eq!(fmt!("%llu", std::u64::MAX), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");
    }

    /*
    XXX: can't be easily ported since Rust doesn't let us pass f32 to a variadic function like
    snprintf.
    TEST_CASE("strprintf::fmt() formats float", "[strprintf]")
    {
            const auto x = 42.0f;
            REQUIRE(strprintf::fmt("%f", x) == "42.000000");
            REQUIRE(strprintf::fmt("%.3f", x) == "42.000");

            const auto y = 42e3f;
            REQUIRE(strprintf::fmt("%e", y) == "4.200000e+04");
            REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+04");
    }

    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<commit_msg>Implement fmt! for f32<commit_after>pub mod specifiers_iterator;

use std::ffi::CString;
use std::vec::Vec;

/// A common trait for all types that can be passed into `fmt!`.
pub trait Printfable {
    /// The type this converts to through `to_c_repr`.
    type Holder;

    /// Converts Self into a type that C language (and thus `snprintf`) understands.
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder;
}

impl Printfable for i32 {
    type Holder = i32;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

impl Printfable for u32 {
    type Holder = u32;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

impl Printfable for i64 {
    type Holder = i64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

impl Printfable for u64 {
    type Holder = u64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

/// `f32` can't be passed to variadic functions like `snprintf`, so it's converted into `f64`
impl Printfable for f32 {
    type Holder = f64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self as f64
    }
}

impl Printfable for f64 {
    type Holder = f64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

/// Helper function for `fmt!`. Don't use directly.
pub fn fmt_arg<T>(format: &str, arg: T) -> Option<String>
where
    T: Printfable,
{
    // Might fail if `format` contains a null byte. TODO decide if this is a good
    // error-handling strategy, or we should report back to user, or panic, or what
    CString::new(format).ok().and_then(|local_format_cstring| {
        let buf_size = 1024usize;
        let mut buffer = Vec::<u8>::with_capacity(buf_size);
        // Filling the vector with ones because CString::new() doesn't want any zeroes in
        // there. The last byte is left unused, so that CString::new() can put a terminating
        // zero byte without triggering a re-allocation.
        buffer.resize(buf_size - 1, 1);
        CString::new(buffer).ok().and_then(|buffer| unsafe {
            let buffer_ptr = buffer.into_raw();
            // TODO: check how many bytes were written
            let bytes_written = libc::snprintf(
                buffer_ptr,
                buf_size as libc::size_t,
                local_format_cstring.as_ptr() as *const libc::c_char,
                arg.to_c_repr(),
            );
            let buffer = CString::from_raw(buffer_ptr);
            let _bytes_written = bytes_written as usize;
            buffer.into_string().ok()
        })
    })
}

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                if let Some(formatted_string) = $crate::fmt_arg(local_format, $arg) {
                    result.push_str(&formatted_string);
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_i32() {
        assert_eq!(fmt!("%i", 42i32), "42");
        assert_eq!(fmt!("%i", std::i32::MIN), "-2147483648");
        assert_eq!(fmt!("%i", std::i32::MAX), "2147483647");
    }

    #[test]
    fn formats_u32() {
        assert_eq!(fmt!("%u", 42u32), "42");
        assert_eq!(fmt!("%u", 0u32), "0");
        assert_eq!(fmt!("%u", std::u32::MAX), "4294967295");
    }

    #[test]
    fn formats_i64() {
        assert_eq!(fmt!("%li", 42i64), "42");
        assert_eq!(fmt!("%li", std::i32::MIN as i64 - 1), "-2147483649");
        assert_eq!(fmt!("%li", std::i32::MAX as i64 + 1), "2147483648");

        assert_eq!(fmt!("%lli", 42i64), "42");
        assert_eq!(fmt!("%lli", std::i64::MIN), "-9223372036854775808");
        assert_eq!(fmt!("%lli", std::i64::MAX), "9223372036854775807");
    }

    #[test]
    fn formats_u64() {
        assert_eq!(fmt!("%lu", 42u64), "42");
        assert_eq!(fmt!("%lu", 0u64), "0");
        assert_eq!(fmt!("%lu", std::u64::MAX), "18446744073709551615");

        assert_eq!(fmt!("%llu", 42u64), "42");
        assert_eq!(fmt!("%llu", 0u64), "0");
        assert_eq!(fmt!("%llu", std::u64::MAX), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");
    }

    #[test]
    fn formats_float() {
        let x = 42.0f32;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e3f32;
        assert_eq!(fmt!("%e", y), "4.200000e+04");
        assert_eq!(fmt!("%.3e", y), "4.200e+04");
    }

    /*
    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<|endoftext|>


<commit_before>// Some utility interfaces
use doc::ItemUtils;
use doc::Item;
use doc::util;

/// A single operation on the document model
type Pass = {
    name: ~str,
    f: fn~(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc
};

fn run_passes(
    srv: astsrv::Srv,
    doc: doc::Doc,
    passes: ~[Pass]
) -> doc::Doc {
    let mut passno = 0;
    do vec::foldl(doc, passes) |doc, pass| {
        log(debug, fmt!("pass #%d", passno));
        passno += 1;
        log(debug, doc);
        do time(pass.name) {
            pass.f(srv, doc)
        }
    }
}

#[test]
fn test_run_passes() {
    fn pass1(
        _srv: astsrv::Srv,
        doc: doc::Doc
    ) -> doc::Doc {
        doc::Doc_({
            pages: ~[
                doc::CratePage({
                    topmod: doc::ModDoc_({
                        item: {
                            name: doc.cratemod().name() + ~"two",
                            .. doc.cratemod().item
                        },
                        items: ~[],
                        index: None
                    })
                })
            ]
        })
    }
    fn pass2(
        _srv: astsrv::Srv,
        doc: doc::Doc
    ) -> doc::Doc {
        doc::Doc_({
            pages: ~[
                doc::CratePage({
                    topmod: doc::ModDoc_({
                        item: {
                            name: doc.cratemod().name() + ~"three",
                            .. doc.cratemod().item
                        },
                        items: ~[],
                        index: None
                    })
                })
            ]
        })
    }
    let source = ~"";
    do astsrv::from_str(source) |srv| {
        let passes = ~[
            {
                name: ~"",
                f: pass1
            },
            {
                name: ~"",
                f: pass2
            }
        ];
        let doc = extract::from_srv(srv, ~"one");
        let doc = run_passes(srv, doc, passes);
        assert doc.cratemod().name() == ~"onetwothree";
    }
}

fn main(args: ~[~str]) {

    if vec::contains(args, ~"-h") {
        config::usage();
        return;
    }

    let config = match config::parse_config(args) {
      result::Ok(config) => config,
      result::Err(err) => {
        io::println(fmt!("error: %s", err));
        return;
      }
    };

    run(config);
}

fn time<T>(what: ~str, f: fn() -> T) -> T {
    let start = std::time::precise_time_s();
    let rv = f();
    let end = std::time::precise_time_s();
    info!("time: %3.3f s    %s", end - start, what);
    return rv;
}

/// Runs rustdoc over the given file
fn run(config: config::Config) {

    let source_file = config.input_crate;
    do astsrv::from_file(source_file.to_str()) |srv| {
        do time(~"wait_ast") {
            do astsrv::exec(srv) |_ctxt| { }
        };
        let doc = time(~"extract", || {
            let default_name = source_file;
            extract::from_srv(srv, default_name.to_str())
        });
        run_passes(srv, doc, ~[
            tystr_pass::mk_pass(),
            path_pass::mk_pass(),
            attr_pass::mk_pass(),
            escape_pass::mk_pass(),
            prune_hidden_pass::mk_pass(),
            desc_to_brief_pass::mk_pass(),
            unindent_pass::mk_pass(),
            sectionalize_pass::mk_pass(),
            trim_pass::mk_pass(),
            sort_item_name_pass::mk_pass(),
            sort_item_type_pass::mk_pass(),
            markdown_index_pass::mk_pass(config),
            page_pass::mk_pass(config.output_style),
            markdown_pass::mk_pass(
                markdown_writer::make_writer_factory(config)
            )
        ]);
    }
}
<commit_msg>rustdoc: Support the --help option<commit_after>// Some utility interfaces
use doc::ItemUtils;
use doc::Item;
use doc::util;

/// A single operation on the document model
type Pass = {
    name: ~str,
    f: fn~(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc
};

fn run_passes(
    srv: astsrv::Srv,
    doc: doc::Doc,
    passes: ~[Pass]
) -> doc::Doc {
    let mut passno = 0;
    do vec::foldl(doc, passes) |doc, pass| {
        log(debug, fmt!("pass #%d", passno));
        passno += 1;
        log(debug, doc);
        do time(pass.name) {
            pass.f(srv, doc)
        }
    }
}

#[test]
fn test_run_passes() {
    fn pass1(
        _srv: astsrv::Srv,
        doc: doc::Doc
    ) -> doc::Doc {
        doc::Doc_({
            pages: ~[
                doc::CratePage({
                    topmod: doc::ModDoc_({
                        item: {
                            name: doc.cratemod().name() + ~"two",
                            .. doc.cratemod().item
                        },
                        items: ~[],
                        index: None
                    })
                })
            ]
        })
    }
    fn pass2(
        _srv: astsrv::Srv,
        doc: doc::Doc
    ) -> doc::Doc {
        doc::Doc_({
            pages: ~[
                doc::CratePage({
                    topmod: doc::ModDoc_({
                        item: {
                            name: doc.cratemod().name() + ~"three",
                            .. doc.cratemod().item
                        },
                        items: ~[],
                        index: None
                    })
                })
            ]
        })
    }
    let source = ~"";
    do astsrv::from_str(source) |srv| {
        let passes = ~[
            {
                name: ~"",
                f: pass1
            },
            {
                name: ~"",
                f: pass2
            }
        ];
        let doc = extract::from_srv(srv, ~"one");
        let doc = run_passes(srv, doc, passes);
        assert doc.cratemod().name() == ~"onetwothree";
    }
}

fn main(args: ~[~str]) {

    if args.contains(~"-h") || args.contains(~"--help") {
        config::usage();
        return;
    }

    let config = match config::parse_config(args) {
      result::Ok(config) => config,
      result::Err(err) => {
        io::println(fmt!("error: %s", err));
        return;
      }
    };

    run(config);
}

fn time<T>(what: ~str, f: fn() -> T) -> T {
    let start = std::time::precise_time_s();
    let rv = f();
    let end = std::time::precise_time_s();
    info!("time: %3.3f s    %s", end - start, what);
    return rv;
}

/// Runs rustdoc over the given file
fn run(config: config::Config) {

    let source_file = config.input_crate;
    do astsrv::from_file(source_file.to_str()) |srv| {
        do time(~"wait_ast") {
            do astsrv::exec(srv) |_ctxt| { }
        };
        let doc = time(~"extract", || {
            let default_name = source_file;
            extract::from_srv(srv, default_name.to_str())
        });
        run_passes(srv, doc, ~[
            tystr_pass::mk_pass(),
            path_pass::mk_pass(),
            attr_pass::mk_pass(),
            escape_pass::mk_pass(),
            prune_hidden_pass::mk_pass(),
            desc_to_brief_pass::mk_pass(),
            unindent_pass::mk_pass(),
            sectionalize_pass::mk_pass(),
            trim_pass::mk_pass(),
            sort_item_name_pass::mk_pass(),
            sort_item_type_pass::mk_pass(),
            markdown_index_pass::mk_pass(config),
            page_pass::mk_pass(config.output_style),
            markdown_pass::mk_pass(
                markdown_writer::make_writer_factory(config)
            )
        ]);
    }
}
<|endoftext|>


<commit_before>//! Madgwick's orientation filter
//!
//! This demo runs Madgwick's orientation filter and logs the orientation of the board as
//! quaternions via the ITM. The data is encoded in binary format and logged as COBS frame. The
//! binary format is as follows:
//!
//! - `w`: `f32`, LE (Little Endian), 4 bytes
//! - `x`: `f32`, LE, 4 bytes
//! - `y`: `f32`, LE, 4 bytes
//! - `z`: `f32`, LE, 4 bytes
//!
//! where the quaternion is the tuple `(w, x, y, z)`
//!
//! The suggested way to receive this data is to connect the F3 SWO pin to a UART to USB converter
//! and then to read out the associated device file using `itmdump`. Make sure you configure the
//! serial device before calling `itmdump`. The commands to run are:
//!
//! ``` console
//! $ stty -F /dev/ttyUSB0 raw 2000000 -echo
//!
//! $ itmdump -f /dev/ttyUSB0 > data.txt
//! ```
//!
//! You can pipe the quaternions through the `viz` program (shipped with this crate) to get real
//! time [visualization]. The command to run is:
//!
//! [visualization]: https://mobile.twitter.com/japaricious/status/962770003325005824
//!
//! ``` console
//! $ itmdump -f /dev/ttyUSB0 | viz
//! ```
//!
//! ```
//! // #![deny(unsafe_code)]
//! #![deny(warnings)]
//! #![no_main]
//! #![no_std]
//!
//! extern crate panic_semihosting;
//!
//! use core::{f32::consts::PI, ptr};
//!
//! use aligned::Aligned;
//! use byteorder::{ByteOrder, LE};
//! use cast::{f32, i32};
//! use cortex_m::itm;
//! use cortex_m_rt::entry;
//! use f3::{
//!     hal::{i2c::I2c, prelude::*, spi::Spi, stm32f30x, timer::Timer},
//!     l3gd20::{self, Odr},
//!     lsm303dlhc::{AccelOdr, MagOdr},
//!     L3gd20, Lsm303dlhc,
//! };
//! use madgwick::{F32x3, Marg};
//! use nb::block;
//!
//! // Number of samples to use for gyroscope calibration
//! const NSAMPLES: i32 = 256;
//!
//! // Magnetometer calibration parameters
//! // NOTE you need to use the right parameters for *your* magnetometer
//! // You can use the `log-sensors` example to calibrate your magnetometer. The producer is explained
//! // in https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration
//! const M_BIAS_X: f32 = -183.;
//! const M_SCALE_X: f32 = 435.;
//!
//! const M_BIAS_Y: f32 = -172.;
//! const M_SCALE_Y: f32 = 507.;
//!
//! const M_BIAS_Z: f32 = -136.;
//! const M_SCALE_Z: f32 = 632.;
//!
//! // Sensitivities of the accelerometer and gyroscope, respectively
//! const K_G: f32 = 2. / (1 << 15) as f32; // LSB -> g
//! const K_AR: f32 = 8.75e-3 * PI / 180.; // LSB -> rad/s
//!
//! // Madgwick filter parameters
//! const SAMPLE_FREQ: u32 = 220;
//! const BETA: f32 = 1e-3;
//!
//! #[entry]
//! fn main() -> ! {
//!     let mut cp = cortex_m::Peripherals::take().unwrap();
//!     let dp = stm32f30x::Peripherals::take().unwrap();
//!
//!     let mut flash = dp.FLASH.constrain();
//!     let mut rcc = dp.RCC.constrain();
//!
//!     let clocks = rcc
//!         .cfgr
//!         .sysclk(64.mhz())
//!         .pclk1(32.mhz())
//!         .freeze(&mut flash.acr);
//!
//!     // enable ITM
//!     // TODO this should be some high level API in the cortex-m crate
//!     unsafe {
//!         // enable TPIU and ITM
//!         cp.DCB.demcr.modify(|r| r | (1 << 24));
//!
//!         // prescaler
//!         let swo_freq = 2_000_000;
//!         cp.TPIU.acpr.write((clocks.sysclk().0 / swo_freq) - 1);
//!
//!         // SWO NRZ
//!         cp.TPIU.sppr.write(2);
//!
//!         cp.TPIU.ffcr.modify(|r| r & !(1 << 1));
//!
//!         // STM32 specific: enable tracing in the DBGMCU_CR register
//!         const DBGMCU_CR: *mut u32 = 0xe0042004 as *mut u32;
//!         let r = ptr::read_volatile(DBGMCU_CR);
//!         ptr::write_volatile(DBGMCU_CR, r | (1 << 5));
//!
//!         // unlock the ITM
//!         cp.ITM.lar.write(0xC5ACCE55);
//!
//!         cp.ITM.tcr.write(
//!             (0b000001 << 16) | // TraceBusID
//!             (1 << 3) | // enable SWO output
//!             (1 << 0), // enable the ITM
//!         );
//!
//!         // enable stimulus port 0
//!         cp.ITM.ter[0].write(1);
//!     }
//!
//!     let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
//!     let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
//!     let mut gpioe = dp.GPIOE.split(&mut rcc.ahb);
//!
//!     let mut nss = gpioe
//!         .pe3
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!     nss.set_high();
//!     let mut led = gpioe
//!         .pe9
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!
//!     let sck = gpioa.pa5.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let miso = gpioa.pa6.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let mosi = gpioa.pa7.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!
//!     let spi = Spi::spi1(
//!         dp.SPI1,
//!         (sck, miso, mosi),
//!         l3gd20::MODE,
//!         1.mhz(),
//!         clocks,
//!         &mut rcc.apb2,
//!     );
//!
//!     let mut l3gd20 = L3gd20::new(spi, nss).unwrap();
//!
//!     l3gd20.set_odr(Odr::Hz380).unwrap();
//!
//!     let scl = gpiob.pb6.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!     let sda = gpiob.pb7.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!
//!     let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 400.khz(), clocks, &mut rcc.apb1);
//!
//!     let mut lsm303dlhc = Lsm303dlhc::new(i2c).unwrap();
//!
//!     lsm303dlhc.accel_odr(AccelOdr::Hz400).unwrap();
//!     lsm303dlhc.mag_odr(MagOdr::Hz220).unwrap();
//!
//!     let mut timer = Timer::tim2(dp.TIM2, 380.hz(), clocks, &mut rcc.apb1);
//!
//!     // Calibrate the gyroscope
//!     let mut ar_bias_x = 0;
//!     let mut ar_bias_y = 0;
//!     let mut ar_bias_z = 0;
//!     for _ in 0..NSAMPLES {
//!         block!(timer.wait()).unwrap();
//!
//!         let ar = l3gd20.gyro().unwrap();
//!
//!         ar_bias_x += i32(ar.x);
//!         ar_bias_y += i32(ar.y);
//!         ar_bias_z += i32(ar.z);
//!     }
//!     let ar_bias_x = (ar_bias_x / NSAMPLES) as i16;
//!     let ar_bias_y = (ar_bias_y / NSAMPLES) as i16;
//!     let ar_bias_z = (ar_bias_z / NSAMPLES) as i16;
//!
//!     // Turn on the LED after calibrating the gyroscope
//!     led.set_high();
//!
//!     let mut marg = Marg::new(BETA, 1. / f32(SAMPLE_FREQ));
//!     let mut timer = Timer::tim2(timer.free(), SAMPLE_FREQ.hz(), clocks, &mut rcc.apb1);
//!
//!     let mut tx_buf: Aligned<u32, [u8; 18]> = Aligned([0; 18]);
//!     loop {
//!         block!(timer.wait()).unwrap();
//!
//!         let m = lsm303dlhc.mag().unwrap();
//!         let ar = l3gd20.gyro().unwrap();
//!         let g = lsm303dlhc.accel().unwrap();
//!
//!         let m_x = (f32(m.x) - M_BIAS_X) / M_SCALE_X;
//!         let m_y = (f32(m.y) - M_BIAS_Y) / M_SCALE_Y;
//!         let m_z = (f32(m.z) - M_BIAS_Z) / M_SCALE_Z;
//!
//!         // Fix the X Y Z components of the magnetometer so they match the gyro axes
//!         let m = F32x3 {
//!             x: m_y,
//!             y: -m_x,
//!             z: m_z,
//!         };
//!
//!         let ar_x = f32(ar.x - ar_bias_x) * K_AR;
//!         let ar_y = f32(ar.y - ar_bias_y) * K_AR;
//!         let ar_z = f32(ar.z - ar_bias_z) * K_AR;
//!         let ar = F32x3 {
//!             x: ar_x,
//!             y: ar_y,
//!             z: ar_z,
//!         };
//!
//!         // Fix the X Y Z components of the accelerometer so they match the gyro axes
//!         let g_x = f32(g.x) * K_G;
//!         let g_y = f32(g.y) * K_G;
//!         let g_z = f32(g.z) * K_G;
//!         let g = F32x3 {
//!             x: g_y,
//!             y: -g_x,
//!             z: g_z,
//!         };
//!
//!         // Run the filter
//!         let quat = marg.update(m, ar, g);
//!
//!         // Serialize the quaternion
//!         let mut start = 0;
//!         let mut buf = [0; 16];
//!         LE::write_f32(&mut buf[start..start + 4], quat.0);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.1);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.2);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.3);
//!         // start += 4;
//!
//!         // Log data
//!         cobs::encode(&buf, &mut tx_buf.array);
//!
//!         itm::write_aligned(&mut cp.ITM.stim[0], &tx_buf);
//!     }
//! }
//! ```
// Auto-generated. Do not modify.
<commit_msg>re-generate example docs (once more)<commit_after>//! Madgwick's orientation filter
//!
//! This demo runs Madgwick's orientation filter and logs the orientation of the board as
//! quaternions via the ITM. The data is encoded in binary format and logged as COBS frame. The
//! binary format is as follows:
//!
//! - `w`: `f32`, LE (Little Endian), 4 bytes
//! - `x`: `f32`, LE, 4 bytes
//! - `y`: `f32`, LE, 4 bytes
//! - `z`: `f32`, LE, 4 bytes
//!
//! where the quaternion is the tuple `(w, x, y, z)`
//!
//! The suggested way to receive this data is to connect the F3 SWO pin to a UART to USB converter
//! and then to read out the associated device file using `itmdump`. Make sure you configure the
//! serial device before calling `itmdump`. The commands to run are:
//!
//! ``` console
//! $ stty -F /dev/ttyUSB0 raw 2000000 -echo
//!
//! $ itmdump -f /dev/ttyUSB0 > data.txt
//! ```
//!
//! You can pipe the quaternions through the `viz` program (shipped with this crate) to get real
//! time [visualization]. The command to run is:
//!
//! [visualization]: https://mobile.twitter.com/japaricious/status/962770003325005824
//!
//! ``` console
//! $ itmdump -f /dev/ttyUSB0 | viz
//! ```
//!
//! ```
//! // #![deny(unsafe_code)]
//! #![deny(warnings)]
//! #![no_main]
//! #![no_std]
//!
//! extern crate panic_semihosting;
//!
//! use core::{f32::consts::PI, ptr};
//!
//! use aligned::Aligned;
//! use byteorder::{ByteOrder, LE};
//! use cast::{f32, i32};
//! use cortex_m::itm;
//! use cortex_m_rt::entry;
//! use f3::{
//!     hal::{i2c::I2c, prelude::*, spi::Spi, stm32f30x, timer::Timer},
//!     l3gd20::{self, Odr},
//!     lsm303dlhc::{AccelOdr, MagOdr},
//!     L3gd20, Lsm303dlhc,
//! };
//! use madgwick::{F32x3, Marg};
//! use nb::block;
//!
//! // Number of samples to use for gyroscope calibration
//! const NSAMPLES: i32 = 256;
//!
//! // Magnetometer calibration parameters
//! // NOTE you need to use the right parameters for *your* magnetometer
//! // You can use the `log-sensors` example to calibrate your magnetometer. The producer is explained
//! // in https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration
//! const M_BIAS_X: f32 = -183.;
//! const M_SCALE_X: f32 = 435.;
//!
//! const M_BIAS_Y: f32 = -172.;
//! const M_SCALE_Y: f32 = 507.;
//!
//! const M_BIAS_Z: f32 = -136.;
//! const M_SCALE_Z: f32 = 632.;
//!
//! // Sensitivities of the accelerometer and gyroscope, respectively
//! const K_G: f32 = 2. / (1 << 15) as f32; // LSB -> g
//! const K_AR: f32 = 8.75e-3 * PI / 180.; // LSB -> rad/s
//!
//! // Madgwick filter parameters
//! const SAMPLE_FREQ: u32 = 220;
//! const BETA: f32 = 1e-3;
//!
//! #[entry]
//! fn main() -> ! {
//!     let mut cp = cortex_m::Peripherals::take().unwrap();
//!     let dp = stm32f30x::Peripherals::take().unwrap();
//!
//!     let mut flash = dp.FLASH.constrain();
//!     let mut rcc = dp.RCC.constrain();
//!
//!     let clocks = rcc
//!         .cfgr
//!         .sysclk(64.mhz())
//!         .pclk1(32.mhz())
//!         .freeze(&mut flash.acr);
//!
//!     // enable ITM
//!     // TODO this should be some high level API in the cortex-m crate
//!     unsafe {
//!         // enable TPIU and ITM
//!         cp.DCB.demcr.modify(|r| r | (1 << 24));
//!
//!         // prescaler
//!         let swo_freq = 2_000_000;
//!         cp.TPIU.acpr.write((clocks.sysclk().0 / swo_freq) - 1);
//!
//!         // SWO NRZ
//!         cp.TPIU.sppr.write(2);
//!
//!         cp.TPIU.ffcr.modify(|r| r & !(1 << 1));
//!
//!         // STM32 specific: enable tracing in the DBGMCU_CR register
//!         const DBGMCU_CR: *mut u32 = 0xe0042004 as *mut u32;
//!         let r = ptr::read_volatile(DBGMCU_CR);
//!         ptr::write_volatile(DBGMCU_CR, r | (1 << 5));
//!
//!         // unlock the ITM
//!         cp.ITM.lar.write(0xC5ACCE55);
//!
//!         cp.ITM.tcr.write(
//!             (0b000001 << 16) | // TraceBusID
//!             (1 << 3) | // enable SWO output
//!             (1 << 0), // enable the ITM
//!         );
//!
//!         // enable stimulus port 0
//!         cp.ITM.ter[0].write(1);
//!     }
//!
//!     let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
//!     let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
//!     let mut gpioe = dp.GPIOE.split(&mut rcc.ahb);
//!
//!     let mut nss = gpioe
//!         .pe3
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!     nss.set_high();
//!     let mut led = gpioe
//!         .pe9
//!         .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
//!
//!     let sck = gpioa.pa5.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let miso = gpioa.pa6.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!     let mosi = gpioa.pa7.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
//!
//!     let spi = Spi::spi1(
//!         dp.SPI1,
//!         (sck, miso, mosi),
//!         l3gd20::MODE,
//!         1.mhz(),
//!         clocks,
//!         &mut rcc.apb2,
//!     );
//!
//!     let mut l3gd20 = L3gd20::new(spi, nss).unwrap();
//!
//!     l3gd20.set_odr(Odr::Hz380).unwrap();
//!
//!     let scl = gpiob.pb6.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!     let sda = gpiob.pb7.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
//!
//!     let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 400.khz(), clocks, &mut rcc.apb1);
//!
//!     let mut lsm303dlhc = Lsm303dlhc::new(i2c).unwrap();
//!
//!     lsm303dlhc.accel_odr(AccelOdr::Hz400).unwrap();
//!     lsm303dlhc.mag_odr(MagOdr::Hz220).unwrap();
//!
//!     let mut timer = Timer::tim2(dp.TIM2, 380.hz(), clocks, &mut rcc.apb1);
//!
//!     // Calibrate the gyroscope
//!     let mut ar_bias_x = 0;
//!     let mut ar_bias_y = 0;
//!     let mut ar_bias_z = 0;
//!     for _ in 0..NSAMPLES {
//!         block!(timer.wait()).unwrap();
//!
//!         let ar = l3gd20.all().unwrap().gyro;
//!
//!         ar_bias_x += i32(ar.x);
//!         ar_bias_y += i32(ar.y);
//!         ar_bias_z += i32(ar.z);
//!     }
//!     let ar_bias_x = (ar_bias_x / NSAMPLES) as i16;
//!     let ar_bias_y = (ar_bias_y / NSAMPLES) as i16;
//!     let ar_bias_z = (ar_bias_z / NSAMPLES) as i16;
//!
//!     // Turn on the LED after calibrating the gyroscope
//!     led.set_high();
//!
//!     let mut marg = Marg::new(BETA, 1. / f32(SAMPLE_FREQ));
//!     let mut timer = Timer::tim2(timer.free(), SAMPLE_FREQ.hz(), clocks, &mut rcc.apb1);
//!
//!     let mut tx_buf: Aligned<u32, [u8; 18]> = Aligned([0; 18]);
//!     loop {
//!         block!(timer.wait()).unwrap();
//!
//!         let m = lsm303dlhc.mag().unwrap();
//!         let ar = l3gd20.all().unwrap().gyro;
//!         let g = lsm303dlhc.accel().unwrap();
//!
//!         let m_x = (f32(m.x) - M_BIAS_X) / M_SCALE_X;
//!         let m_y = (f32(m.y) - M_BIAS_Y) / M_SCALE_Y;
//!         let m_z = (f32(m.z) - M_BIAS_Z) / M_SCALE_Z;
//!
//!         // Fix the X Y Z components of the magnetometer so they match the gyro axes
//!         let m = F32x3 {
//!             x: m_y,
//!             y: -m_x,
//!             z: m_z,
//!         };
//!
//!         let ar_x = f32(ar.x - ar_bias_x) * K_AR;
//!         let ar_y = f32(ar.y - ar_bias_y) * K_AR;
//!         let ar_z = f32(ar.z - ar_bias_z) * K_AR;
//!         let ar = F32x3 {
//!             x: ar_x,
//!             y: ar_y,
//!             z: ar_z,
//!         };
//!
//!         // Fix the X Y Z components of the accelerometer so they match the gyro axes
//!         let g_x = f32(g.x) * K_G;
//!         let g_y = f32(g.y) * K_G;
//!         let g_z = f32(g.z) * K_G;
//!         let g = F32x3 {
//!             x: g_y,
//!             y: -g_x,
//!             z: g_z,
//!         };
//!
//!         // Run the filter
//!         let quat = marg.update(m, ar, g);
//!
//!         // Serialize the quaternion
//!         let mut start = 0;
//!         let mut buf = [0; 16];
//!         LE::write_f32(&mut buf[start..start + 4], quat.0);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.1);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.2);
//!         start += 4;
//!         LE::write_f32(&mut buf[start..start + 4], quat.3);
//!         // start += 4;
//!
//!         // Log data
//!         cobs::encode(&buf, &mut tx_buf.array);
//!
//!         itm::write_aligned(&mut cp.ITM.stim[0], &tx_buf);
//!     }
//! }
//! ```
// Auto-generated. Do not modify.
<|endoftext|>


<commit_before>use nom::{
  IResult,
  ErrorCode, Err,
  Needed,
};

use frame::subframe;

fn leading_zeros(input: (&[u8], usize)) -> IResult<(&[u8], usize), u32> {
  let (bytes, mut offset) = input;

  let mut index     = 0;
  let mut count     = 0;
  let mut is_parsed = false;
  let bytes_len     = bytes.len();

  for i in 0..bytes_len {
    // Clear the number of offset bits
    let byte  = bytes[i] << offset;
    let zeros = byte.leading_zeros() as usize;

    if byte > 0 {
      index     = i;
      is_parsed = true;
      count    += zeros;
      offset   += zeros + 1;

      if offset >= 8 {
        index  += 1;
        offset -= 8;
      }

      break;
    } else {
      count += zeros - offset;
      offset = 0;
    }
  }

  if is_parsed {
    IResult::Done((&bytes[index..], offset), count as u32)
  } else if index + 1 > bytes_len {
    IResult::Incomplete(Needed::Size(index + 1))
  } else {
    IResult::Error(Err::Position(ErrorCode::TakeUntil as u32, bytes))
  }
}

fn header(input: (&[u8], usize)) -> IResult<(&[u8], usize), (u8, bool)> {
  let result = chain!(input,
    bit_padding: take_bits!(u8, 1) ~
    subframe_type: take_bits!(u8, 6) ~
    wasted_bit_flag: take_bits!(u8, 1),
    || {
      let is_valid        = bit_padding == 0;
      let has_wasted_bits = wasted_bit_flag == 1;

      (is_valid, subframe_type, has_wasted_bits)
    }
  );

  match result {
    IResult::Done(i, data)    => {
      let (is_valid, subframe_type, has_wasted_bits) = data;

      if is_valid {
        IResult::Done(i, (subframe_type, has_wasted_bits))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input.0))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn constant(input: (&[u8], usize), bits_per_sample: usize)
            -> IResult<(&[u8], usize), subframe::Data> {
  map!(input, take_bits!(i32, bits_per_sample), subframe::Data::Constant)
}
<commit_msg>Add alt parser for parsing the four subframe data<commit_after>use nom::{
  IResult,
  ErrorCode, Err,
  Needed,
};

use frame;
use frame::subframe;

fn leading_zeros(input: (&[u8], usize)) -> IResult<(&[u8], usize), u32> {
  let (bytes, mut offset) = input;

  let mut index     = 0;
  let mut count     = 0;
  let mut is_parsed = false;
  let bytes_len     = bytes.len();

  for i in 0..bytes_len {
    // Clear the number of offset bits
    let byte  = bytes[i] << offset;
    let zeros = byte.leading_zeros() as usize;

    if byte > 0 {
      index     = i;
      is_parsed = true;
      count    += zeros;
      offset   += zeros + 1;

      if offset >= 8 {
        index  += 1;
        offset -= 8;
      }

      break;
    } else {
      count += zeros - offset;
      offset = 0;
    }
  }

  if is_parsed {
    IResult::Done((&bytes[index..], offset), count as u32)
  } else if index + 1 > bytes_len {
    IResult::Incomplete(Needed::Size(index + 1))
  } else {
    IResult::Error(Err::Position(ErrorCode::TakeUntil as u32, bytes))
  }
}

fn header(input: (&[u8], usize)) -> IResult<(&[u8], usize), (u8, bool)> {
  let result = chain!(input,
    bit_padding: take_bits!(u8, 1) ~
    subframe_type: take_bits!(u8, 6) ~
    wasted_bit_flag: take_bits!(u8, 1),
    || {
      let is_valid        = bit_padding == 0;
      let has_wasted_bits = wasted_bit_flag == 1;

      (is_valid, subframe_type, has_wasted_bits)
    }
  );

  match result {
    IResult::Done(i, data)    => {
      let (is_valid, subframe_type, has_wasted_bits) = data;

      if is_valid {
        IResult::Done(i, (subframe_type, has_wasted_bits))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input.0))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn data<'a>(input: (&'a [u8], usize),
            frame_header: &frame::Header,
            subframe_type: usize,
            wasted_bits: usize)
            -> IResult<'a, (&'a [u8], usize), subframe::Data> {
  let bits_per_sample = frame_header.bits_per_sample - wasted_bits;
  let block_size      = frame_header.block_size as usize;

  match subframe_type {
    0b000000 => constant(input, bits_per_sample),
    _        => IResult::Error(Err::Position(ErrorCode::Alt as u32, input.0))
  }
}

fn constant(input: (&[u8], usize), bits_per_sample: usize)
            -> IResult<(&[u8], usize), subframe::Data> {
  map!(input, take_bits!(i32, bits_per_sample), subframe::Data::Constant)
}
<|endoftext|>


<commit_before>use color::Color;
use tile::Tile;
use ::Axis;

pub const ALIGN_HORIZONTAL: usize = 0;
pub const ALIGN_DIAGONAL_UP: usize  = 1;
pub const ALIGN_VERTICAL: usize  = 2;
pub const ALIGN_DIAGONAL_DOWN: usize  = 3;

pub fn alignement_horizontal(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for y in (pos.y...0).rev() {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for y in pos.y + 1..::GRID_LEN {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn alignement_diagonal_up(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    {
        let Axis { mut x, mut y } = pos;
        while x < ::GRID_LEN && y < ::GRID_LEN { // y will overflow to usize::max()
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x += 1;
            y = y.wrapping_sub(1);
        }
    }
    {
        let Axis { mut x, mut y } = pos;
        x = x.wrapping_sub(1);
        y += 1;
        while x < ::GRID_LEN && y < ::GRID_LEN {
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x = x.wrapping_sub(1);
            y += 1;
        }
    }
    count
}

pub fn alignement_vertical(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for x in (pos.x...0).rev() {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for x in pos.x + 1..::GRID_LEN {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn alignement_diagonal_down(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    {
        let Axis { mut x, mut y } = pos;
        while x < ::GRID_LEN && y < ::GRID_LEN { // x and y will overflow to usize::max()
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x = x.wrapping_sub(1);
            y = y.wrapping_sub(1);
        }
    }
    {
        let Axis { mut x, mut y } = pos;
        x += 1;
        y += 1;
        while x < ::GRID_LEN && y < ::GRID_LEN {
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x += 1;
            y += 1;
        }
    }
    count
}

/// returns a list of alignements with the tile at `pos` position in Clockwise
/// (e.g. top_to_bot, top_right_to_bot_left, right_to_left, bot_right_to_top_left)
/// a None value means no alignement (e.g. less than 2 stones)
pub fn list_alignements(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> [Option<usize>; 4] {
    let mut alignements = [None; 4];

    alignements[ALIGN_HORIZONTAL] = match alignement_horizontal(grid, pos) {
        0 | 1 | 2 => None,
        x => Some(x),
    };

    alignements[ALIGN_DIAGONAL_UP] = match alignement_diagonal_up(grid, pos) {
        0 | 1 | 2 => None,
        x => Some(x),
    };

    alignements[ALIGN_VERTICAL] = match alignement_vertical(grid, pos) {
        0 | 1 | 2 => None,
        x => Some(x),
    };

    alignements[ALIGN_DIAGONAL_DOWN] = match alignement_diagonal_down(grid, pos) {
        0 | 1 | 2 => None,
        x => Some(x),
    };

    alignements
}

#[cfg(test)]
mod tests {

    use test::Bencher;
    use functions::alignements::*;
    use color::Color;

    // #[bench]
    // fn diagonal_up_top_bounds(bencher: &mut Bencher) {
    //     let b = Some(Color::Black);
    //     let n = None;

    //     let grid = [[n, n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n]];

    //     bencher.iter(||
    //         assert_eq!(check_diagonal_up_alignement(&grid, Color::Black), true)
    //     );
    // }
}
<commit_msg>alignements: Fix alignements conditions<commit_after>use color::Color;
use tile::Tile;
use ::Axis;

pub const ALIGN_HORIZONTAL: usize = 0;
pub const ALIGN_DIAGONAL_UP: usize  = 1;
pub const ALIGN_VERTICAL: usize  = 2;
pub const ALIGN_DIAGONAL_DOWN: usize  = 3;

pub fn alignement_horizontal(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for y in (pos.y...0).rev() {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for y in pos.y + 1..::GRID_LEN {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn alignement_diagonal_up(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    {
        let Axis { mut x, mut y } = pos;
        while x < ::GRID_LEN && y < ::GRID_LEN { // y will overflow to usize::max()
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x += 1;
            y = y.wrapping_sub(1);
        }
    }
    {
        let Axis { mut x, mut y } = pos;
        x = x.wrapping_sub(1);
        y += 1;
        while x < ::GRID_LEN && y < ::GRID_LEN {
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x = x.wrapping_sub(1);
            y += 1;
        }
    }
    count
}

pub fn alignement_vertical(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for x in (pos.x...0).rev() {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for x in pos.x + 1..::GRID_LEN {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn alignement_diagonal_down(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    {
        let Axis { mut x, mut y } = pos;
        while x < ::GRID_LEN && y < ::GRID_LEN { // x and y will overflow to usize::max()
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x = x.wrapping_sub(1);
            y = y.wrapping_sub(1);
        }
    }
    {
        let Axis { mut x, mut y } = pos;
        x += 1;
        y += 1;
        while x < ::GRID_LEN && y < ::GRID_LEN {
            match grid[x][y] {
                Some(c) if c == tile => count += 1,
                _ => break,
            }
            x += 1;
            y += 1;
        }
    }
    count
}

/// returns a list of alignements with the tile at `pos` position in Clockwise
/// (e.g. top_to_bot, top_right_to_bot_left, right_to_left, bot_right_to_top_left)
/// a None value means no alignement (e.g. less than 2 stones)
pub fn list_alignements(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> [Option<usize>; 4] {
    let mut alignements = [None; 4];
    alignements[ALIGN_HORIZONTAL] = match alignement_horizontal(grid, pos) {
        0 => unreachable!("alignement_horizontal cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_DIAGONAL_UP] = match alignement_diagonal_up(grid, pos) {
        0 => unreachable!("alignement_diagonal_up cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_VERTICAL] = match alignement_vertical(grid, pos) {
        0 => unreachable!("alignement_vertical cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_DIAGONAL_DOWN] = match alignement_diagonal_down(grid, pos) {
        0 => unreachable!("alignement_diagonal_down cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements
}

#[cfg(test)]
mod tests {

    use test::Bencher;
    use functions::alignements::*;
    use color::Color;

    // #[bench]
    // fn diagonal_up_top_bounds(bencher: &mut Bencher) {
    //     let b = Some(Color::Black);
    //     let n = None;

    //     let grid = [[n, n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n]];

    //     bencher.iter(||
    //         assert_eq!(check_diagonal_up_alignement(&grid, Color::Black), true)
    //     );
    // }
}
<|endoftext|>