<commit_before>// lock-free stack
use std::fmt::{self, Debug};
use std::ptr;
use std::ops::Deref;
use std::sync::atomic::Ordering::{Relaxed, SeqCst};

use coco::epoch::{Atomic, Owned, Ptr, Scope, pin, unprotected};

use test_fail;

#[derive(Debug)]
pub struct Node<T> {
    inner: T,
    next: Atomic<Node<T>>,
}

impl<T> Drop for Node<T> {
    fn drop(&mut self) {
        unsafe {
            unprotected(|scope| {
                let next = self.next.load(Relaxed, scope).as_raw();
                if !next.is_null() {
                    drop(Box::from_raw(next as *mut Node<T>));
                }
            })
        }
    }
}

pub struct Stack<T> {
    head: Atomic<Node<T>>,
}

impl<T> Default for Stack<T> {
    fn default() -> Stack<T> {
        Stack {
            head: Atomic::null(),
        }
    }
}

impl<T> Drop for Stack<T> {
    fn drop(&mut self) {
        unsafe {
            unprotected(|scope| {
                let curr = self.head.load(Relaxed, scope).as_raw();
                if !curr.is_null() {
                    drop(Box::from_raw(curr as *mut Node<T>));
                }
            })
        }
    }
}

impl<T: Debug> Debug for Stack<T> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        pin(|scope| {
            let head = self.head(scope);
            let iter = StackIter::from_ptr(head, scope);

            formatter.write_str("Stack [")?;
            let mut written = false;
            for node in iter {
                if written {
                    formatter.write_str(", ")?;
                }
                formatter.write_str(&*format!("({:?})", &node as *const _))?;
                node.fmt(formatter)?;
                written = true;
            }
            formatter.write_str("]")?;
            Ok(())
        })
    }
}

impl<T> Deref for Node<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.inner
    }
}

impl<T> Node<T> {
    pub fn next<'s>(&self, scope: &'s Scope) -> Ptr<'s, Node<T>> {
        self.next.load(SeqCst, scope)
    }
}

impl<T> Stack<T> {
    pub fn push(&self, inner: T) {
        pin(|scope| {
            let node = Owned::new(Node {
                inner: inner,
                next: Atomic::null(),
            }).into_ptr(scope);

            loop {
                let head = self.head(scope);
                unsafe { node.deref().next.store(head, SeqCst) };
                if self.head
                    .compare_and_swap(head, node, SeqCst, scope)
                    .is_ok()
                {
                    return;
                }
            }
        })
    }

    pub fn pop(&self) -> Option<T> {
        pin(|scope| {
            let mut head = self.head(scope);
            loop {
                match unsafe { head.as_ref() } {
                    Some(h) => {
                        let next = h.next.load(SeqCst, scope);
                        match self.head.compare_and_swap(head, next, SeqCst, scope) {
                            Ok(()) => unsafe {
                                scope.defer_free(head);
                                return Some(ptr::read(&h.inner));
                            },
                            Err(h) => head = h,
                        }
                    }
                    None => return None,
                }
            }
        })
    }

    /// compare and push
    pub fn cap<'s>(
        &self,
        old: Ptr<Node<T>>,
        new: T,
        scope: &'s Scope,
    ) -> Result<Ptr<'s, Node<T>>, Ptr<'s, Node<T>>> {
        let node = Owned::new(Node {
            inner: new,
            next: Atomic::null(),
        });

        node.next.store(old, SeqCst);

        let node = node.into_ptr(scope);

        let res = self.head.compare_and_swap(old, node, SeqCst, scope);
        if res.is_err() {
            unsafe {
                node.deref().next.store(Ptr::null(), SeqCst);
                scope.defer_drop(node);
            }
            Err(res.unwrap_err())
        } else if test_fail() {
            unimplemented!()
        } else {
            Ok(node)
        }
    }

    /// attempt consolidation
    pub fn cas<'s>(
        &self,
        old: Ptr<'s, Node<T>>,
        new: Ptr<'s, Node<T>>,
        scope: &'s Scope,
    ) -> Result<Ptr<'s, Node<T>>, Ptr<'s, Node<T>>> {
        let res = self.head.compare_and_swap(old, new, SeqCst, scope);
        if res.is_ok() && !test_fail() {
            if !old.is_null() {
                unsafe { scope.defer_drop(old) };
            }
            Ok(new)
        } else {
            if !new.is_null() {
                unsafe { scope.defer_drop(new) };
            }

            Err(res.unwrap_err())
        }
    }

    pub fn head<'s>(&self, scope: &'s Scope) -> Ptr<'s, Node<T>> {
        self.head.load(SeqCst, scope)
    }
}

pub struct StackIter<'a, T: 'a> {
    inner: Ptr<'a, Node<T>>,
    scope: &'a Scope,
}

impl<'a, T: 'a> StackIter<'a, T> {
    pub fn from_ptr<'b>(ptr: Ptr<'b, Node<T>>, scope: &'b Scope) -> StackIter<'b, T> {
        StackIter {
            inner: ptr,
            scope: scope,
        }
    }
}

impl<'a, T> Iterator for StackIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<Self::Item> {
        if self.inner.is_null() {
            None
        } else {
            unsafe {
                let ret = &self.inner.deref().inner;
                self.inner = self.inner.deref().next.load(SeqCst, self.scope);
                Some(ret)
            }
        }
    }
}

pub fn node_from_frag_vec<T>(from: Vec<T>) -> Owned<Node<T>> {
    let mut last = None;

    for item in from.into_iter().rev() {
        let node = Owned::new(Node {
            inner: item,
            next: Atomic::null(),
        });

        if let Some(last) = last {
            node.next.store_owned(last, SeqCst);
        }

        last = Some(node);
    }

    last.unwrap()
}

#[test]
fn basic_functionality() {
    use std::thread;
    use std::sync::Arc;

    let ll = Arc::new(Stack::default());
    assert_eq!(ll.pop(), None);
    ll.push(1);
    let ll2 = ll.clone();
    let t = thread::spawn(move || {
        ll2.push(2);
        ll2.push(3);
        ll2.push(4);
    });
    t.join().unwrap();
    ll.push(5);
    assert_eq!(ll.pop(), Some(5));
    assert_eq!(ll.pop(), Some(4));
    let ll3 = ll.clone();
    let t = thread::spawn(move || {
        assert_eq!(ll3.pop(), Some(3));
        assert_eq!(ll3.pop(), Some(2));
    });
    t.join().unwrap();
    assert_eq!(ll.pop(), Some(1));
    let ll4 = ll.clone();
    let t = thread::spawn(move || {
        assert_eq!(ll4.pop(), None);
    });
    t.join().unwrap();
}
<commit_msg>fix bug where the garbage system was dropped before calling epoch::pin (#86)<commit_after>// lock-free stack
use std::fmt::{self, Debug};
use std::ptr;
use std::ops::Deref;
use std::sync::atomic::Ordering::{Relaxed, SeqCst};

use coco::epoch::{Atomic, Owned, Ptr, Scope, pin, unprotected};

use test_fail;

#[derive(Debug)]
pub struct Node<T> {
    inner: T,
    next: Atomic<Node<T>>,
}

impl<T> Drop for Node<T> {
    fn drop(&mut self) {
        unsafe {
            unprotected(|scope| {
                let next = self.next.load(Relaxed, scope).as_raw();
                if !next.is_null() {
                    drop(Box::from_raw(next as *mut Node<T>));
                }
            })
        }
    }
}

pub struct Stack<T> {
    head: Atomic<Node<T>>,
}

impl<T> Default for Stack<T> {
    fn default() -> Stack<T> {
        Stack {
            head: Atomic::null(),
        }
    }
}

impl<T> Drop for Stack<T> {
    fn drop(&mut self) {
        unsafe {
            unprotected(|scope| {
                let curr = self.head.load(Relaxed, scope).as_raw();
                if !curr.is_null() {
                    drop(Box::from_raw(curr as *mut Node<T>));
                }
            })
        }
    }
}

impl<T: Debug> Debug for Stack<T> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        pin(|scope| {
            let head = self.head(scope);
            let iter = StackIter::from_ptr(head, scope);

            formatter.write_str("Stack [")?;
            let mut written = false;
            for node in iter {
                if written {
                    formatter.write_str(", ")?;
                }
                formatter.write_str(&*format!("({:?})", &node as *const _))?;
                node.fmt(formatter)?;
                written = true;
            }
            formatter.write_str("]")?;
            Ok(())
        })
    }
}

impl<T> Deref for Node<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.inner
    }
}

impl<T> Node<T> {
    pub fn next<'s>(&self, scope: &'s Scope) -> Ptr<'s, Node<T>> {
        self.next.load(SeqCst, scope)
    }
}

impl<T> Stack<T> {
    pub fn push(&self, inner: T) {
        let node = Owned::new(Node {
            inner: inner,
            next: Atomic::null(),
        });

        unsafe {
            unprotected(|scope| {
                let node = node.into_ptr(scope);

                loop {
                    let head = self.head(scope);
                    node.deref().next.store(head, SeqCst);
                    if self.head
                        .compare_and_swap(head, node, SeqCst, scope)
                        .is_ok()
                    {
                        return;
                    }
                }
            })
        }
    }

    pub fn pop(&self) -> Option<T> {
        pin(|scope| {
            let mut head = self.head(scope);
            loop {
                match unsafe { head.as_ref() } {
                    Some(h) => {
                        let next = h.next.load(SeqCst, scope);
                        match self.head.compare_and_swap(head, next, SeqCst, scope) {
                            Ok(()) => unsafe {
                                scope.defer_free(head);
                                return Some(ptr::read(&h.inner));
                            },
                            Err(h) => head = h,
                        }
                    }
                    None => return None,
                }
            }
        })
    }

    /// compare and push
    pub fn cap<'s>(
        &self,
        old: Ptr<Node<T>>,
        new: T,
        scope: &'s Scope,
    ) -> Result<Ptr<'s, Node<T>>, Ptr<'s, Node<T>>> {
        let node = Owned::new(Node {
            inner: new,
            next: Atomic::null(),
        });

        node.next.store(old, SeqCst);

        let node = node.into_ptr(scope);

        let res = self.head.compare_and_swap(old, node, SeqCst, scope);
        if res.is_err() {
            unsafe {
                node.deref().next.store(Ptr::null(), SeqCst);
                scope.defer_drop(node);
            }
            Err(res.unwrap_err())
        } else if test_fail() {
            unimplemented!()
        } else {
            Ok(node)
        }
    }

    /// attempt consolidation
    pub fn cas<'s>(
        &self,
        old: Ptr<'s, Node<T>>,
        new: Ptr<'s, Node<T>>,
        scope: &'s Scope,
    ) -> Result<Ptr<'s, Node<T>>, Ptr<'s, Node<T>>> {
        let res = self.head.compare_and_swap(old, new, SeqCst, scope);
        if res.is_ok() && !test_fail() {
            if !old.is_null() {
                unsafe { scope.defer_drop(old) };
            }
            Ok(new)
        } else {
            if !new.is_null() {
                unsafe { scope.defer_drop(new) };
            }

            Err(res.unwrap_err())
        }
    }

    pub fn head<'s>(&self, scope: &'s Scope) -> Ptr<'s, Node<T>> {
        self.head.load(SeqCst, scope)
    }
}

pub struct StackIter<'a, T: 'a> {
    inner: Ptr<'a, Node<T>>,
    scope: &'a Scope,
}

impl<'a, T: 'a> StackIter<'a, T> {
    pub fn from_ptr<'b>(ptr: Ptr<'b, Node<T>>, scope: &'b Scope) -> StackIter<'b, T> {
        StackIter {
            inner: ptr,
            scope: scope,
        }
    }
}

impl<'a, T> Iterator for StackIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<Self::Item> {
        if self.inner.is_null() {
            None
        } else {
            unsafe {
                let ret = &self.inner.deref().inner;
                self.inner = self.inner.deref().next.load(SeqCst, self.scope);
                Some(ret)
            }
        }
    }
}

pub fn node_from_frag_vec<T>(from: Vec<T>) -> Owned<Node<T>> {
    let mut last = None;

    for item in from.into_iter().rev() {
        let node = Owned::new(Node {
            inner: item,
            next: Atomic::null(),
        });

        if let Some(last) = last {
            node.next.store_owned(last, SeqCst);
        }

        last = Some(node);
    }

    last.unwrap()
}

#[test]
fn basic_functionality() {
    use std::thread;
    use std::sync::Arc;

    let ll = Arc::new(Stack::default());
    assert_eq!(ll.pop(), None);
    ll.push(1);
    let ll2 = ll.clone();
    let t = thread::spawn(move || {
        ll2.push(2);
        ll2.push(3);
        ll2.push(4);
    });
    t.join().unwrap();
    ll.push(5);
    assert_eq!(ll.pop(), Some(5));
    assert_eq!(ll.pop(), Some(4));
    let ll3 = ll.clone();
    let t = thread::spawn(move || {
        assert_eq!(ll3.pop(), Some(3));
        assert_eq!(ll3.pop(), Some(2));
    });
    t.join().unwrap();
    assert_eq!(ll.pop(), Some(1));
    let ll4 = ll.clone();
    let t = thread::spawn(move || {
        assert_eq!(ll4.pop(), None);
    });
    t.join().unwrap();
}
<|endoftext|>


<commit_before>use crate::paging::{RmmA, RmmArch, TableKind};

#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
    println!("DEBUGGER TODO");
    println!();
}

// Super unsafe due to page table switching and raw pointers!
#[cfg(target_arch = "x86")]
pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
    println!("DEBUGGER START");
    println!();

    let old_table = RmmA::table(TableKind::User);

    for (id, context_lock) in crate::context::contexts().iter() {
        if target_id.map_or(false, |target_id| *id != target_id) { continue; }
        let context = context_lock.read();
        println!("{}: {}", (*id).into(), context.name.read());

        // Switch to context page table to ensure syscall debug and stack dump will work
        if let Some(ref space) = context.addr_space {
            RmmA::set_table(TableKind::User, space.read().table.utable.table().phys());
            //TODO check_consistency(&mut space.write());
        }

        println!("status: {:?}", context.status);
        if ! context.status_reason.is_empty() {
            println!("reason: {}", context.status_reason);
        }
        if let Some((a, b, c, d, e, f)) = context.syscall {
            println!("syscall: {}", crate::syscall::debug::format_call(a, b, c, d, e, f));
        }
        if let Some(ref addr_space) = context.addr_space {
            let addr_space = addr_space.read();
            if ! addr_space.grants.is_empty() {
                println!("grants:");
                for grant in addr_space.grants.iter() {
                    let region = grant.region();
                    println!(
                        "    virt 0x{:08x}:0x{:08x} size 0x{:08x} {}",
                        region.start_address().data(), region.final_address().data(), region.size(),
                        if grant.is_owned() { "owned" } else { "borrowed" },
                    );
                }
            }
        }
        if let Some(regs) = crate::ptrace::regs_for(&context) {
            println!("regs:");
            regs.dump();

            let mut sp = regs.iret.esp;
            println!("stack: {:>08x}", sp);
            //Maximum 64 dwords
            for _ in 0..64 {
                if context.addr_space.as_ref().map_or(false, |space| space.read().table.utable.translate(crate::paging::VirtualAddress::new(sp)).is_some()) {
                    let value = *(sp as *const usize);
                    println!("    {:>08x}: {:>08x}", sp, value);
                    if let Some(next_sp) = sp.checked_add(core::mem::size_of::<usize>()) {
                        sp = next_sp;
                    } else {
                        println!("    {:>08x}: OVERFLOW", sp);
                        break;
                    }
                } else {
                    println!("    {:>08x}: GUARD PAGE", sp);
                    break;
                }
            }
        }

        // Switch to original page table
        RmmA::set_table(TableKind::User, old_table);

        println!();
    }

    println!("DEBUGGER END");
}

// Super unsafe due to page table switching and raw pointers!
#[cfg(target_arch = "x86_64")]
pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
    println!("DEBUGGER START");
    println!();

    let old_table = RmmA::table(TableKind::User);

    for (id, context_lock) in crate::context::contexts().iter() {
        if target_id.map_or(false, |target_id| *id != target_id) { continue; }
        let context = context_lock.read();
        println!("{}: {}", (*id).into(), context.name.read());

        // Switch to context page table to ensure syscall debug and stack dump will work
        if let Some(ref space) = context.addr_space {
            RmmA::set_table(TableKind::User, space.read().table.utable.table().phys());
            check_consistency(&mut space.write());
        }

        println!("status: {:?}", context.status);
        if ! context.status_reason.is_empty() {
            println!("reason: {}", context.status_reason);
        }
        if let Some((a, b, c, d, e, f)) = context.syscall {
            println!("syscall: {}", crate::syscall::debug::format_call(a, b, c, d, e, f));
        }
        if let Some(ref addr_space) = context.addr_space {
            let addr_space = addr_space.read();
            if ! addr_space.grants.is_empty() {
                println!("grants:");
                for grant in addr_space.grants.iter() {
                    let region = grant.region();
                    println!(
                        "    virt 0x{:016x}:0x{:016x} size 0x{:08x} {}",
                        region.start_address().data(), region.final_address().data(), region.size(),
                        if grant.is_owned() { "owned" } else { "borrowed" },
                    );
                }
            }
        }
        if let Some(regs) = crate::ptrace::regs_for(&context) {
            println!("regs:");
            regs.dump();

            let mut rsp = regs.iret.rsp;
            println!("stack: {:>016x}", rsp);
            //Maximum 64 qwords
            for _ in 0..64 {
                if context.addr_space.as_ref().map_or(false, |space| space.read().table.utable.translate(crate::paging::VirtualAddress::new(rsp)).is_some()) {
                    let value = *(rsp as *const usize);
                    println!("    {:>016x}: {:>016x}", rsp, value);
                    if let Some(next_rsp) = rsp.checked_add(core::mem::size_of::<usize>()) {
                        rsp = next_rsp;
                    } else {
                        println!("    {:>016x}: OVERFLOW", rsp);
                        break;
                    }
                } else {
                    println!("    {:>016x}: GUARD PAGE", rsp);
                    break;
                }
            }
        }

        // Switch to original page table
        RmmA::set_table(TableKind::User, old_table);

        println!();
    }

    println!("DEBUGGER END");
}

#[cfg(target_arch = "x86_64")]
pub unsafe fn check_consistency(addr_space: &mut crate::context::memory::AddrSpace) {
    use crate::paging::*;

    let p4 = addr_space.table.utable.table();

    for p4i in 0..256 {
        let p3 = match p4.next(p4i) {
            Some(p3) => p3,
            None => continue,
        };

        for p3i in 0..512 {
            let p2 = match p3.next(p3i) {
                Some(p2) => p2,
                None => continue,
            };

            for p2i in 0..512 {
                let p1 = match p2.next(p2i) {
                    Some(p1) => p1,
                    None => continue,
                };

                for p1i in 0..512 {
                    let (physaddr, flags) = match p1.entry(p1i) {
                        Some(e) => if let Ok(address) = e.address() {
                            (address, e.flags())
                        } else {
                            continue;
                        }
                        _ => continue,
                    };
                    let address = VirtualAddress::new((p1i << 12) | (p2i << 21) | (p3i << 30) | (p4i << 39));

                    let grant = match addr_space.grants.contains(address) {
                        Some(g) => g,
                        None => {
                            log::error!("ADDRESS {:p} LACKING GRANT BUT MAPPED TO {:#0x} FLAGS {:?}!", address.data() as *const u8, physaddr.data(), flags);
                            continue;
                        }
                    };
                    const STICKY: usize = (1 << 5) | (1 << 6); // accessed+dirty
                    if grant.flags().data() & !STICKY != flags.data() & !STICKY {
                        log::error!("FLAG MISMATCH: {:?} != {:?}, address {:p} in grant at {:?}", grant.flags(), flags, address.data() as *const u8, grant.region());
                    }
                }
            }
        }
    }

    for grant in addr_space.grants.iter() {
        for page in grant.pages() {
            let _entry = match addr_space.table.utable.translate(page.start_address()) {
                Some(e) => e,
                None => {
                    log::error!("GRANT AT {:?} LACKING MAPPING AT PAGE {:p}", grant.region(), page.start_address().data() as *const u8);
                    continue;
                }
            };
        }
    }
}
<commit_msg>Add aarch64 debugger<commit_after>use crate::paging::{RmmA, RmmArch, TableKind};

//TODO: combine arches into one function (aarch64 one is newest)

// Super unsafe due to page table switching and raw pointers!
#[cfg(target_arch = "aarch64")]
pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
    println!("DEBUGGER START");
    println!();

    let old_table = RmmA::table(TableKind::User);

    for (id, context_lock) in crate::context::contexts().iter() {
        if target_id.map_or(false, |target_id| *id != target_id) { continue; }
        let context = context_lock.read();
        println!("{}: {}", (*id).into(), context.name.read());

        println!("status: {:?}", context.status);
        if ! context.status_reason.is_empty() {
            println!("reason: {}", context.status_reason);
        }

        // Switch to context page table to ensure syscall debug and stack dump will work
        if let Some(ref space) = context.addr_space {
            RmmA::set_table(TableKind::User, space.read().table.utable.table().phys());

            if let Some((a, b, c, d, e, f)) = context.syscall {
                println!("syscall: {}", crate::syscall::debug::format_call(a, b, c, d, e, f));
            }

            {
                let space = space.read();
                if ! space.grants.is_empty() {
                    println!("grants:");
                    for grant in space.grants.iter() {
                        let region = grant.region();
                        println!(
                            "    virt 0x{:016x}:0x{:016x} size 0x{:08x} {}",
                            region.start_address().data(), region.final_address().data(), region.size(),
                            if grant.is_owned() { "owned" } else { "borrowed" },
                        );
                    }
                }
            }

            if let Some(regs) = crate::ptrace::regs_for(&context) {
                println!("regs:");
                regs.dump();

                let mut sp = regs.iret.sp_el0;
                println!("stack: {:>016x}", sp);
                //Maximum 64 usizes
                for _ in 0..64 {
                    if context.addr_space.as_ref().map_or(false, |space| space.read().table.utable.translate(crate::paging::VirtualAddress::new(sp)).is_some()) {
                        let value = *(sp as *const usize);
                        println!("    {:>016x}: {:>016x}", sp, value);
                        if let Some(next_sp) = sp.checked_add(core::mem::size_of::<usize>()) {
                            sp = next_sp;
                        } else {
                            println!("    {:>016x}: OVERFLOW", sp);
                            break;
                        }
                    } else {
                        println!("    {:>016x}: GUARD PAGE", sp);
                        break;
                    }
                }
            }

            // Switch to original page table
            RmmA::set_table(TableKind::User, old_table);
        }

        println!();
    }

    println!("DEBUGGER END");
}

// Super unsafe due to page table switching and raw pointers!
#[cfg(target_arch = "x86")]
pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
    println!("DEBUGGER START");
    println!();

    let old_table = RmmA::table(TableKind::User);

    for (id, context_lock) in crate::context::contexts().iter() {
        if target_id.map_or(false, |target_id| *id != target_id) { continue; }
        let context = context_lock.read();
        println!("{}: {}", (*id).into(), context.name.read());

        // Switch to context page table to ensure syscall debug and stack dump will work
        if let Some(ref space) = context.addr_space {
            RmmA::set_table(TableKind::User, space.read().table.utable.table().phys());
            //TODO check_consistency(&mut space.write());
        }

        println!("status: {:?}", context.status);
        if ! context.status_reason.is_empty() {
            println!("reason: {}", context.status_reason);
        }
        if let Some((a, b, c, d, e, f)) = context.syscall {
            println!("syscall: {}", crate::syscall::debug::format_call(a, b, c, d, e, f));
        }
        if let Some(ref addr_space) = context.addr_space {
            let addr_space = addr_space.read();
            if ! addr_space.grants.is_empty() {
                println!("grants:");
                for grant in addr_space.grants.iter() {
                    let region = grant.region();
                    println!(
                        "    virt 0x{:08x}:0x{:08x} size 0x{:08x} {}",
                        region.start_address().data(), region.final_address().data(), region.size(),
                        if grant.is_owned() { "owned" } else { "borrowed" },
                    );
                }
            }
        }
        if let Some(regs) = crate::ptrace::regs_for(&context) {
            println!("regs:");
            regs.dump();

            let mut sp = regs.iret.esp;
            println!("stack: {:>08x}", sp);
            //Maximum 64 dwords
            for _ in 0..64 {
                if context.addr_space.as_ref().map_or(false, |space| space.read().table.utable.translate(crate::paging::VirtualAddress::new(sp)).is_some()) {
                    let value = *(sp as *const usize);
                    println!("    {:>08x}: {:>08x}", sp, value);
                    if let Some(next_sp) = sp.checked_add(core::mem::size_of::<usize>()) {
                        sp = next_sp;
                    } else {
                        println!("    {:>08x}: OVERFLOW", sp);
                        break;
                    }
                } else {
                    println!("    {:>08x}: GUARD PAGE", sp);
                    break;
                }
            }
        }

        // Switch to original page table
        RmmA::set_table(TableKind::User, old_table);

        println!();
    }

    println!("DEBUGGER END");
}

// Super unsafe due to page table switching and raw pointers!
#[cfg(target_arch = "x86_64")]
pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
    println!("DEBUGGER START");
    println!();

    let old_table = RmmA::table(TableKind::User);

    for (id, context_lock) in crate::context::contexts().iter() {
        if target_id.map_or(false, |target_id| *id != target_id) { continue; }
        let context = context_lock.read();
        println!("{}: {}", (*id).into(), context.name.read());

        // Switch to context page table to ensure syscall debug and stack dump will work
        if let Some(ref space) = context.addr_space {
            RmmA::set_table(TableKind::User, space.read().table.utable.table().phys());
            check_consistency(&mut space.write());
        }

        println!("status: {:?}", context.status);
        if ! context.status_reason.is_empty() {
            println!("reason: {}", context.status_reason);
        }
        if let Some((a, b, c, d, e, f)) = context.syscall {
            println!("syscall: {}", crate::syscall::debug::format_call(a, b, c, d, e, f));
        }
        if let Some(ref addr_space) = context.addr_space {
            let addr_space = addr_space.read();
            if ! addr_space.grants.is_empty() {
                println!("grants:");
                for grant in addr_space.grants.iter() {
                    let region = grant.region();
                    println!(
                        "    virt 0x{:016x}:0x{:016x} size 0x{:08x} {}",
                        region.start_address().data(), region.final_address().data(), region.size(),
                        if grant.is_owned() { "owned" } else { "borrowed" },
                    );
                }
            }
        }
        if let Some(regs) = crate::ptrace::regs_for(&context) {
            println!("regs:");
            regs.dump();

            let mut rsp = regs.iret.rsp;
            println!("stack: {:>016x}", rsp);
            //Maximum 64 qwords
            for _ in 0..64 {
                if context.addr_space.as_ref().map_or(false, |space| space.read().table.utable.translate(crate::paging::VirtualAddress::new(rsp)).is_some()) {
                    let value = *(rsp as *const usize);
                    println!("    {:>016x}: {:>016x}", rsp, value);
                    if let Some(next_rsp) = rsp.checked_add(core::mem::size_of::<usize>()) {
                        rsp = next_rsp;
                    } else {
                        println!("    {:>016x}: OVERFLOW", rsp);
                        break;
                    }
                } else {
                    println!("    {:>016x}: GUARD PAGE", rsp);
                    break;
                }
            }
        }

        // Switch to original page table
        RmmA::set_table(TableKind::User, old_table);

        println!();
    }

    println!("DEBUGGER END");
}

#[cfg(target_arch = "x86_64")]
pub unsafe fn check_consistency(addr_space: &mut crate::context::memory::AddrSpace) {
    use crate::paging::*;

    let p4 = addr_space.table.utable.table();

    for p4i in 0..256 {
        let p3 = match p4.next(p4i) {
            Some(p3) => p3,
            None => continue,
        };

        for p3i in 0..512 {
            let p2 = match p3.next(p3i) {
                Some(p2) => p2,
                None => continue,
            };

            for p2i in 0..512 {
                let p1 = match p2.next(p2i) {
                    Some(p1) => p1,
                    None => continue,
                };

                for p1i in 0..512 {
                    let (physaddr, flags) = match p1.entry(p1i) {
                        Some(e) => if let Ok(address) = e.address() {
                            (address, e.flags())
                        } else {
                            continue;
                        }
                        _ => continue,
                    };
                    let address = VirtualAddress::new((p1i << 12) | (p2i << 21) | (p3i << 30) | (p4i << 39));

                    let grant = match addr_space.grants.contains(address) {
                        Some(g) => g,
                        None => {
                            log::error!("ADDRESS {:p} LACKING GRANT BUT MAPPED TO {:#0x} FLAGS {:?}!", address.data() as *const u8, physaddr.data(), flags);
                            continue;
                        }
                    };
                    const STICKY: usize = (1 << 5) | (1 << 6); // accessed+dirty
                    if grant.flags().data() & !STICKY != flags.data() & !STICKY {
                        log::error!("FLAG MISMATCH: {:?} != {:?}, address {:p} in grant at {:?}", grant.flags(), flags, address.data() as *const u8, grant.region());
                    }
                }
            }
        }
    }

    for grant in addr_space.grants.iter() {
        for page in grant.pages() {
            let _entry = match addr_space.table.utable.translate(page.start_address()) {
                Some(e) => e,
                None => {
                    log::error!("GRANT AT {:?} LACKING MAPPING AT PAGE {:p}", grant.region(), page.start_address().data() as *const u8);
                    continue;
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>use tokenizer::{Token, TokenType};
use std::collections::HashMap;

// get operation priority
fn get_priority(operator: &str) -> Option<i8> {
    match operator {
        "(" => Some(-1),
        "*" | "/" => Some(1),
        "+" | "-" => Some(2),
        _ => None,
    }
}

// check for the possibility of pulling out of the stack
fn can_pop(op1: &Token, stack: &Vec<Token>) -> bool {
    if stack.len() == 0 {
        return false;
    }
    let p1 = match get_priority(&op1.param) {
        Some(value) => value,
        None => {
            println!("> error: unknown operator '{}'", op1.param);
            return false;
        }
    };
    let last = match stack.last() {
        Some(value) => value,
        None => {
            println!("> error: function stack is empty");
            return false;
        }
    };
    let p2 = match get_priority(&last.param) {
        Some(value) => value,
        None => {
            println!("> error: unknown operator '{}'", last.param);
            return false;
        }
    };
    p1 >= 0 && p2 >= 0 && p1 >= p2
}

// convert infix notation to reverse polish
fn in2rpn(variables: &mut HashMap<String, f32>, tokens: &Vec<Token>) -> Vec<Token> {
    let mut result: Vec<Token> = Vec::new();
    let mut funcs: Vec<Token> = Vec::new();
    // skip variable name and operator
    for item in tokens.iter().skip(2) {
        // push numeric value to result vector
        if item.id == TokenType::IsNumeric {
            result.push(item.clone());
        } else if item.id == TokenType::IsVariable {
            // get value from hashmap and push to result
            let token = match variables.get(&item.param) {
                Some(value) => format!("{}", value.clone()),
                None => {
                    println!("> error: can't found {} variable!", item.param);
                    break;
                }
            };
            result.push(Token::new(token.clone(), TokenType::IsNumeric));
        } else {
            if item.param == ")" {
                // push all acumulated functions in brackets
                while funcs.len() > 0 && funcs.last().unwrap().param != "(" {
                    let function = match funcs.pop() {
                        Some(value) => value,
                        None => {
                            println!("> error: function stack is empty");
                            break;
                        }
                    };
                    result.push(function);
                }
                funcs.pop();
            } else {
                // push other functions
                while can_pop(item, &funcs) {
                    let function = match funcs.pop() {
                        Some(value) => value,
                        None => {
                            println!("> error: function stack is empty");
                            break;
                        }
                    };
                    result.push(function);
                }
                funcs.push(item.clone());
            }
        }
    }
    // push rest functions
    if funcs.len() > 0 {
        result.push(funcs.pop().unwrap());
    }
    result
}

// reverse polish notation to value
fn rpn2value(line: &Vec<Token>) -> f32 {
    let mut stack: Vec<f32> = Vec::new();
    for token in line {
        if token.id == TokenType::IsOperation {
            // get first operand
            let a = match stack.pop() {
                Some(value) => value,
                None => {
                    println!("> error: stack is empty!");
                    break;
                }
            };
            // get second operand
            let b = match stack.pop() {
                Some(value) => value,
                None => {
                    println!("> error: stack is empty!");
                    break;
                }
            };
            // calculate statement
            let result: f32 = match token.param.as_ref() {
                "+" => b + a,
                "-" => b - a,
                "*" => b * a,
                "/" => b / a,
                _ => continue,
            };
            stack.push(result);
        } else if token.id == TokenType::IsNumeric {
            // add numeric value to stack
            stack.push(match token.param.parse() {
                Ok(value) => value,
                Err(why) => {
                    println!("> error: {}", why);
                    continue;
                }
            });
        }
    }
    // return first value of stack
    *stack.get(0).unwrap()
}

// check tokens type and calculate it
pub fn execute(variables: &mut HashMap<String, f32>, tokens: &Vec<Token>) -> bool {
    // get first token
    let first = tokens.get(0).unwrap();
    // get second token
    let operator = if tokens.len() > 1 {
        tokens.get(1)
    } else {
        None
    };
    // if first token in function
    if first.id == TokenType::IsFunction {
        match first.param.as_ref() {
            "print" => {
                // iterate by all tokens (except first)
                for item in tokens.iter().skip(1) {
                    match variables.get(&item.param) {
                        Some(var) => println!("{} ", var),
                        None => {
                            println!("> error: variable '{}' is not defined!", item.param);
                            continue;
                        }
                    }
                }
            }
            "exit" => return true,
            _ => println!("> error: function '{}' not defined", first.param),
        }
    } else {
        let operator = match operator {
            Some(value) => value,
            None => {
                println!("> error: can't execute code");
                return false;
            }
        };
        // if second token is operation -- caclucate statement
        if operator.id == TokenType::IsOperation {
            match operator.param.as_ref() {
                "<-" => {
                    // convert infix to reverse polish
                    let rpn_statement = in2rpn(variables, tokens);
                    // calucate reverse polish
                    let value = rpn2value(&rpn_statement);
                    // add value to hashmap
                    variables.insert(first.param.to_owned(), value);
                }
                _ => println!("> error: operator '{}' is not defined!", operator.param),
            }
        }
    }
    false
}
<commit_msg>reorganize structure<commit_after>use tokenizer::{Token, TokenType};
use std::collections::HashMap;

// get operation priority
fn get_priority(operator: &str) -> Option<i8> {
    match operator {
        "(" => Some(-1),
        "^" => Some(0),
        "*" | "/" | "%" => Some(1),
        "+" | "-" => Some(2),
        _ => None,
    }
}

// check for the possibility of pulling out of the stack
fn can_pop(op1: &Token, stack: &Vec<Token>) -> bool {
    if stack.len() == 0 {
        return false;
    }
    let p1 = match get_priority(&op1.param) {
        Some(value) => value,
        None => {
            println!("> error: unknown operator '{}'", op1.param);
            return false;
        }
    };
    let last = match stack.last() {
        Some(value) => value,
        None => {
            println!("> error: function stack is empty");
            return false;
        }
    };
    let p2 = match get_priority(&last.param) {
        Some(value) => value,
        None => {
            println!("> error: unknown operator '{}'", last.param);
            return false;
        }
    };
    p1 >= 0 && p2 >= 0 && p1 >= p2
}

// convert infix notation to reverse polish
fn in2rpn(variables: &mut HashMap<String, f32>, tokens: &Vec<Token>) -> Vec<Token> {
    let mut result: Vec<Token> = Vec::new();
    let mut funcs: Vec<Token> = Vec::new();
    let mut token_counter = 0;
    for item in tokens {
        token_counter += 1;
        match item.id {
            // push numeric value to result vector
            TokenType::IsNumeric => {
                result.push(item.clone());
            }
            // get value from hashmap and push to result
            TokenType::IsVariable => {
                if token_counter == 1 {
                    continue;
                }
                let token = match variables.get(&item.param) {
                    Some(value) => format!("{}", value.clone()),
                    None => {
                        println!("> error: can't found {} variable!", item.param);
                        break;
                    }
                };
                result.push(Token::new(token.clone(), TokenType::IsNumeric));
            }
            TokenType::IsFunction => {
                continue;
            }
            TokenType::IsOperation => {
                if item.param == ")" {
                    // push all acumulated functions in brackets
                    while funcs.len() > 0 && funcs.last().unwrap().param != "(" {
                        let function = match funcs.pop() {
                            Some(value) => value,
                            None => {
                                println!("> error: function stack is empty");
                                break;
                            }
                        };
                        result.push(function);
                    }
                    funcs.pop();
                } else if item.param == "<-" {
                    continue;
                } else {
                    // push other functions
                    while can_pop(item, &funcs) {
                        let function = match funcs.pop() {
                            Some(value) => value,
                            None => {
                                println!("> error: function stack is empty");
                                break;
                            }
                        };
                        result.push(function);
                    }
                    funcs.push(item.clone());
                }
            }
        }
    }
    // push rest functions
    if funcs.len() > 0 {
        result.push(funcs.pop().unwrap());
    }
    result
}

// reverse polish notation to value
fn rpn2value(line: &Vec<Token>) -> f32 {
    let mut stack: Vec<f32> = Vec::new();
    for token in line {
        if token.id == TokenType::IsOperation {
            // get first operand
            let a = match stack.pop() {
                Some(value) => value,
                None => {
                    println!("> error: stack is empty!");
                    break;
                }
            };
            // get second operand
            let b = match stack.pop() {
                Some(value) => value,
                None => {
                    println!("> error: stack is empty!");
                    break;
                }
            };
            // calculate statement
            let result: f32 = match token.param.as_ref() {
                "+" => b + a,
                "-" => b - a,
                "*" => b * a,
                "/" => b / a,
                "%" => b % a,
                "^" => b.powf(a),
                _ => continue,
            };
            stack.push(result);
        } else if token.id == TokenType::IsNumeric {
            // add numeric value to stack
            stack.push(match token.param.parse() {
                Ok(value) => value,
                Err(why) => {
                    println!("> error: {}", why);
                    continue;
                }
            });
        }
    }
    // return first value of stack
    *stack.get(0).unwrap()
}

// check tokens type and calculate it
pub fn execute(variables: &mut HashMap<String, f32>, tokens: &Vec<Token>) -> bool {
    // get first token
    let first = tokens.get(0).unwrap();
    // get second token
    let operator = if tokens.len() > 1 {
        tokens.get(1)
    } else {
        None
    };
    // if first token in function
    if first.id == TokenType::IsFunction {
        match first.param.as_ref() {
            "print" => {
                let mut calculate_it = false;
                for item in tokens.iter().skip(1) {
                    if item.id == TokenType::IsOperation {
                        calculate_it = true;
                        break;
                    }
                }
                if calculate_it {
                    // convert infix to reverse polish
                    let rpn_statement = in2rpn(variables, tokens);
                    // calucate reverse polish
                    let value = rpn2value(&rpn_statement);
                    println!("{} ", value);
                } else {
                    // iterate by all tokens (except first)
                    for item in tokens.iter().skip(1) {
                        match item.id {
                            // find variable in hashmap and print
                            TokenType::IsVariable => {
                                match variables.get(&item.param) {
                                    Some(var) => println!("{} ", var),
                                    None => {
                                        println!("> error: variable '{}' is not defined!",
                                                 item.param);
                                        continue;
                                    }
                                }
                            }
                            // print numeric value
                            TokenType::IsNumeric => println!("{}", item.param),
                            // say no way!
                            TokenType::IsFunction | TokenType::IsOperation => {
                                println!("type '{}' : {:?}", item.param, item.id)
                            }
                        }
                    }
                }
            }
            "exit" => return true,
            _ => println!("> error: function '{}' not defined", first.param),
        }
    } else {
        let operator = match operator {
            Some(value) => value,
            None => {
                println!("> error: can't execute code");
                return false;
            }
        };
        // if second token is operation -- caclucate statement
        if operator.id == TokenType::IsOperation {
            match operator.param.as_ref() {
                "<-" => {
                    // convert infix to reverse polish
                    let rpn_statement = in2rpn(variables, tokens);
                    // calucate reverse polish
                    let value = rpn2value(&rpn_statement);
                    // add value to hashmap
                    variables.insert(first.param.to_owned(), value);
                }
                _ => println!("> error: operator '{}' is not defined!", operator.param),
            }
        }
    }
    false
}
<|endoftext|>


<commit_before>//! Miscellaneous types used by the library.

use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::{fmt, ops};
use parking_lot::RwLock;

pub use maybe_owned::MaybeOwned;
#[cfg(feature="either")]
pub use either::Either;

/// Function that becomes uncallable after it returns false.
///
/// Callbacks use a MaybeOwned<T> argument so we can choose at runtime if we will send a ref or an owned value.
struct FnCell<T>
{
    f: Box<dyn Fn(MaybeOwned<'_, T>) -> bool + Send + Sync>,
    alive: AtomicBool,
}

impl<T> FnCell<T>
{
    /// Creates a new `FnCell` from the supplied closure.
    fn new<F>(f: F) -> Self
        where F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static
    {
        FnCell{ f: Box::new(f), alive: AtomicBool::new(true) }
    }

    /// Calls the stored function and updates it's callable status.
    fn call(&self, arg: MaybeOwned<'_, T>) -> bool
    {
        let is_alive = self.alive.load(Ordering::Acquire) && (self.f)(arg);
        if !is_alive { self.alive.store(false, Ordering::Release); }
        is_alive
    }

    /// Checks if this function can still be called.
    fn is_alive(&self) -> bool
    {
        self.alive.load(Ordering::Relaxed)
    }
}

impl<T> fmt::Debug for FnCell<T>
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        write!(f, "FnCell {{ f: Fn@{:p}, alive: {:?} }}", self.f, self.alive)
    }
}

/// A collection of callbacks.
#[derive(Debug)]
pub(crate) struct Callbacks<T>
{
    fs: RwLock<Vec<FnCell<T>>>,
}

impl<T> Callbacks<T>
{
    /// Creates an empty callback list.
    pub fn new() -> Self
    {
        Callbacks{ fs: Default::default() }
    }

    /// Adds a new closure to the callback list.
    pub fn push<F>(&self, cb: F)
        where F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static
    {
        self.fs.write().push(FnCell::new(cb))
    }

    /// Sends an owned value.
    ///
    /// This sends a ref to the first N-1 callbacks, and the owned value to the last.
    pub fn call(&self, arg: T)
    {
        let fs = self.fs.read();
        let n = fs.len();

        let mut i = 0;
        let mut all_alive = true;
        for _ in 1..n
        {
            all_alive &= fs[i].call(MaybeOwned::Borrowed(&arg));
            i += 1;
        }
        if n > 0 { all_alive &= fs[i].call(MaybeOwned::Owned(arg)) }
        drop(fs);

        if !all_alive { self.cleanup(); }
    }

    /// Sends a value by reference.
    pub fn call_ref(&self, arg: &T)
    {
        let all_alive = self.fs.read().iter()
            .map(|f| f.call(MaybeOwned::Borrowed(arg)))
            .fold(true, |a, alive| a & alive);

        if !all_alive { self.cleanup(); }
    }

    /// Sends a MaybeOwned value.
    ///
    /// We use this to passthrough an unprocessed value.
    pub fn call_dyn(&self, arg: MaybeOwned<'_, T>)
    {
        match arg
        {
            MaybeOwned::Borrowed(r) => self.call_ref(r),
            MaybeOwned::Owned(v) => self.call(v),
        }
    }

    /// Removes the dead callbacks.
    fn cleanup(&self)
    {
        if let Some(mut fs) = self.fs.try_write()
        {
            let mut i = 0;
            while i < fs.len()
            {
                if fs[i].is_alive()
                {
                    i += 1;
                }
                else
                {
                    fs.swap_remove(i);
                }
            }
        }
    }
}

impl<T> Default for Callbacks<T>
{
    fn default() -> Self
    {
        Callbacks::new()
    }
}

/// Generic sum type of two elements.
///
/// It's used to provide generics over the `Option`/`Result`/`Either` types
pub trait SumType2
{
    /// Type of the first variant.
    type Type1;
    /// Type of the second variant.
    type Type2;

    /// Creates a value using the first variant.
    fn from_type1(val: Self::Type1) -> Self;
    /// Creates a value using the second variant.
    fn from_type2(val: Self::Type2) -> Self;

    /// Checks if the value is of the first variant.
    fn is_type1(&self) -> bool;
    /// Checks if the value is of the second variant.
    fn is_type2(&self) -> bool;

    /// Attempts to extract the value contained on the first variant.
    fn into_type1(self) -> Option<Self::Type1>;
    /// Attempts to extract the value contained on the second variant.
    fn into_type2(self) -> Option<Self::Type2>;
}

impl<T> SumType2 for Option<T>
{
    type Type1 = T;
    type Type2 = ();

    fn from_type1(val: Self::Type1) -> Self { Some(val) }
    fn from_type2(_: Self::Type2) -> Self { None }

    fn is_type1(&self) -> bool { self.is_some() }
    fn is_type2(&self) -> bool { self.is_none() }

    fn into_type1(self) -> Option<Self::Type1> { self }
    fn into_type2(self) -> Option<Self::Type2> { self.ok_or(()).err() }
}

impl<T, E> SumType2 for Result<T, E>
{
    type Type1 = T;
    type Type2 = E;

    fn from_type1(val: Self::Type1) -> Self { Ok(val) }
    fn from_type2(val: Self::Type2) -> Self { Err(val) }

    fn is_type1(&self) -> bool { self.is_ok() }
    fn is_type2(&self) -> bool { self.is_err() }

    fn into_type1(self) -> Option<Self::Type1> { self.ok() }
    fn into_type2(self) -> Option<Self::Type2> { self.err() }
}

#[cfg(feature="either")]
impl<L, R> SumType2 for ::either::Either<L, R>
{
    type Type1 = L;
    type Type2 = R;

    fn from_type1(val: Self::Type1) -> Self { Either::Left(val) }
    fn from_type2(val: Self::Type2) -> Self { Either::Right(val) }

    fn is_type1(&self) -> bool { self.is_left() }
    fn is_type2(&self) -> bool { self.is_right() }

    fn into_type1(self) -> Option<Self::Type1> { self.left() }
    fn into_type2(self) -> Option<Self::Type2> { self.right() }
}

/// Storage cell for shared signal values.
pub(crate) struct Storage<T>
{
    val: RwLock<Option<T>>,
    serial: SerialId,
    pub root_ser: Arc<SerialId>,
}

const ERR_EMPTY: &str = "storage empty";

impl<T> Storage<T>
{
    /// Creates a storage with a new root serial.
    pub fn new(val: T) -> Self
    {
        Storage{
            val: RwLock::new(Some(val)),
            serial: SerialId::new(1),
            root_ser: Arc::new(SerialId::new(1)),
        }
    }

    /// Creates a storage with an inherited root serial.
    pub fn inherit<P>(parent: &Storage<P>) -> Self
    {
        Storage{
            val: RwLock::new(None),
            serial: Default::default(),
            root_ser: parent.root_ser.clone(),
        }
    }

    /// Gets the value by cloning.
    pub fn get(&self) -> T
        where T: Clone
    {
        self.val.read().clone().expect(ERR_EMPTY)
    }

    /// Sets value and increments the root serial.
    ///
    /// This is called by source signals.
    pub fn set(&self, val: T)
    {
        let mut st = self.val.write();
        *st = Some(val);
        self.inc_root();
    }

    /// Sets value and increments the local serial.
    ///
    /// This is called by mapped (child) signals.
    pub fn set_local(&self, val: T)
    {
        let mut st = self.val.write();
        *st = Some(val);
        self.inc_local();
    }

    /// Replaces the stored value.
    pub fn replace(&self, val: T) -> T
    {
        let mut st = self.val.write();
        let old = st.take().expect(ERR_EMPTY);
        *st = Some(val);
        self.inc_root();
        old
    }

    /// Passes the stored value through a function.
    pub fn replace_with<F>(&self, f: F)
        where F: FnOnce(T) -> T
    {
        let mut st = self.val.write();
        let old = st.take().expect(ERR_EMPTY);
        *st = Some(f(old));
        self.inc_root();
    }

    /// Checks if a parent storage has changed, so this needs update.
    pub fn must_update(&self) -> bool
    {
        self.root_ser.get() > self.serial.get()
    }

    /// Increments the serial of a source signal, so child must update.
    pub fn inc_root(&self)
    {
        self.root_ser.inc();
    }

    /// Marks this storage as updated.
    pub fn inc_local(&self)
    {
        self.serial.set(self.root_ser.get());
    }
}

impl<T> Default for Storage<T>
{
    fn default() -> Self
    {
        Storage{
            val: RwLock::new(None),
            serial: Default::default(),
            root_ser: Arc::new(SerialId::new(1)),
        }
    }
}

/// A counter on how many times a signal value has been modified.
#[derive(Default)]
pub(crate) struct SerialId(AtomicUsize);

impl SerialId
{
    const fn new(val: usize) -> Self
    {
        SerialId(AtomicUsize::new(val))
    }

    fn get(&self) -> usize
    {
        self.0.load(Ordering::Relaxed)
    }

    fn set(&self, val: usize)
    {
        self.0.store(val, Ordering::Relaxed);
    }

    fn inc(&self)
    {
        self.0.fetch_add(1, Ordering::Relaxed);
    }
}

/// Defines a signal that contains shared storage.
pub(crate) trait SharedSignal<T>
{
    /// Updates the signal.
    fn update(&self);
    /// Checks if the value has changed.
    fn has_changed(&self) -> bool;
    /// Obtains the internal storage.
    fn get_storage(&self) -> &Storage<T>;
    /// Samples the signal.
    fn sample(&self) -> &Storage<T>;
}

/// Common template for shared signal implementations.
pub(crate) struct SharedImpl<T, S, F>
{
    pub storage: Storage<T>,
    pub source: S,
    pub f: F,
}

impl<T, S, F> ops::Deref for SharedImpl<T, S, F>
{
    type Target = Storage<T>;

    fn deref(&self) -> &Self::Target
    {
        &self.storage
    }
}
<commit_msg>removed SerialId wrapper<commit_after>//! Miscellaneous types used by the library.

use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::{fmt, ops};
use parking_lot::RwLock;

pub use maybe_owned::MaybeOwned;
#[cfg(feature="either")]
pub use either::Either;

/// Function that becomes uncallable after it returns false.
///
/// Callbacks use a MaybeOwned<T> argument so we can choose at runtime if we will send a ref or an owned value.
struct FnCell<T>
{
    f: Box<dyn Fn(MaybeOwned<'_, T>) -> bool + Send + Sync>,
    alive: AtomicBool,
}

impl<T> FnCell<T>
{
    /// Creates a new `FnCell` from the supplied closure.
    fn new<F>(f: F) -> Self
        where F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static
    {
        FnCell{ f: Box::new(f), alive: AtomicBool::new(true) }
    }

    /// Calls the stored function and updates it's callable status.
    fn call(&self, arg: MaybeOwned<'_, T>) -> bool
    {
        let is_alive = self.alive.load(Ordering::Acquire) && (self.f)(arg);
        if !is_alive { self.alive.store(false, Ordering::Release); }
        is_alive
    }

    /// Checks if this function can still be called.
    fn is_alive(&self) -> bool
    {
        self.alive.load(Ordering::Relaxed)
    }
}

impl<T> fmt::Debug for FnCell<T>
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        write!(f, "FnCell {{ f: Fn@{:p}, alive: {:?} }}", self.f, self.alive)
    }
}

/// A collection of callbacks.
#[derive(Debug)]
pub(crate) struct Callbacks<T>
{
    fs: RwLock<Vec<FnCell<T>>>,
}

impl<T> Callbacks<T>
{
    /// Creates an empty callback list.
    pub fn new() -> Self
    {
        Callbacks{ fs: Default::default() }
    }

    /// Adds a new closure to the callback list.
    pub fn push<F>(&self, cb: F)
        where F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static
    {
        self.fs.write().push(FnCell::new(cb))
    }

    /// Sends an owned value.
    ///
    /// This sends a ref to the first N-1 callbacks, and the owned value to the last.
    pub fn call(&self, arg: T)
    {
        let fs = self.fs.read();
        let n = fs.len();

        let mut i = 0;
        let mut all_alive = true;
        for _ in 1..n
        {
            all_alive &= fs[i].call(MaybeOwned::Borrowed(&arg));
            i += 1;
        }
        if n > 0 { all_alive &= fs[i].call(MaybeOwned::Owned(arg)) }
        drop(fs);

        if !all_alive { self.cleanup(); }
    }

    /// Sends a value by reference.
    pub fn call_ref(&self, arg: &T)
    {
        let all_alive = self.fs.read().iter()
            .map(|f| f.call(MaybeOwned::Borrowed(arg)))
            .fold(true, |a, alive| a & alive);

        if !all_alive { self.cleanup(); }
    }

    /// Sends a MaybeOwned value.
    ///
    /// We use this to passthrough an unprocessed value.
    pub fn call_dyn(&self, arg: MaybeOwned<'_, T>)
    {
        match arg
        {
            MaybeOwned::Borrowed(r) => self.call_ref(r),
            MaybeOwned::Owned(v) => self.call(v),
        }
    }

    /// Removes the dead callbacks.
    fn cleanup(&self)
    {
        if let Some(mut fs) = self.fs.try_write()
        {
            let mut i = 0;
            while i < fs.len()
            {
                if fs[i].is_alive()
                {
                    i += 1;
                }
                else
                {
                    fs.swap_remove(i);
                }
            }
        }
    }
}

impl<T> Default for Callbacks<T>
{
    fn default() -> Self
    {
        Callbacks::new()
    }
}

/// Generic sum type of two elements.
///
/// It's used to provide generics over the `Option`/`Result`/`Either` types
pub trait SumType2
{
    /// Type of the first variant.
    type Type1;
    /// Type of the second variant.
    type Type2;

    /// Creates a value using the first variant.
    fn from_type1(val: Self::Type1) -> Self;
    /// Creates a value using the second variant.
    fn from_type2(val: Self::Type2) -> Self;

    /// Checks if the value is of the first variant.
    fn is_type1(&self) -> bool;
    /// Checks if the value is of the second variant.
    fn is_type2(&self) -> bool;

    /// Attempts to extract the value contained on the first variant.
    fn into_type1(self) -> Option<Self::Type1>;
    /// Attempts to extract the value contained on the second variant.
    fn into_type2(self) -> Option<Self::Type2>;
}

impl<T> SumType2 for Option<T>
{
    type Type1 = T;
    type Type2 = ();

    fn from_type1(val: Self::Type1) -> Self { Some(val) }
    fn from_type2(_: Self::Type2) -> Self { None }

    fn is_type1(&self) -> bool { self.is_some() }
    fn is_type2(&self) -> bool { self.is_none() }

    fn into_type1(self) -> Option<Self::Type1> { self }
    fn into_type2(self) -> Option<Self::Type2> { self.ok_or(()).err() }
}

impl<T, E> SumType2 for Result<T, E>
{
    type Type1 = T;
    type Type2 = E;

    fn from_type1(val: Self::Type1) -> Self { Ok(val) }
    fn from_type2(val: Self::Type2) -> Self { Err(val) }

    fn is_type1(&self) -> bool { self.is_ok() }
    fn is_type2(&self) -> bool { self.is_err() }

    fn into_type1(self) -> Option<Self::Type1> { self.ok() }
    fn into_type2(self) -> Option<Self::Type2> { self.err() }
}

#[cfg(feature="either")]
impl<L, R> SumType2 for ::either::Either<L, R>
{
    type Type1 = L;
    type Type2 = R;

    fn from_type1(val: Self::Type1) -> Self { Either::Left(val) }
    fn from_type2(val: Self::Type2) -> Self { Either::Right(val) }

    fn is_type1(&self) -> bool { self.is_left() }
    fn is_type2(&self) -> bool { self.is_right() }

    fn into_type1(self) -> Option<Self::Type1> { self.left() }
    fn into_type2(self) -> Option<Self::Type2> { self.right() }
}

/// Storage cell for shared signal values.
pub(crate) struct Storage<T>
{
    val: RwLock<Option<T>>,
    serial: AtomicUsize,
    root_ser: Arc<AtomicUsize>,
}

const ERR_EMPTY: &str = "storage empty";

impl<T> Storage<T>
{
    /// Creates a storage with a new root serial.
    pub fn new(val: T) -> Self
    {
        Storage{
            val: RwLock::new(Some(val)),
            serial: AtomicUsize::new(1),
            root_ser: Arc::new(AtomicUsize::new(1)),
        }
    }

    /// Creates a storage with an inherited root serial.
    pub fn inherit<P>(parent: &Storage<P>) -> Self
    {
        Storage{
            val: RwLock::new(None),
            serial: Default::default(),
            root_ser: parent.root_ser.clone(),
        }
    }

    /// Gets the value by cloning.
    pub fn get(&self) -> T
        where T: Clone
    {
        self.val.read().clone().expect(ERR_EMPTY)
    }

    /// Sets value and increments the root serial.
    ///
    /// This is called by source signals.
    pub fn set(&self, val: T)
    {
        let mut st = self.val.write();
        *st = Some(val);
        self.inc_root();
    }

    /// Sets value and increments the local serial.
    ///
    /// This is called by mapped (child) signals.
    pub fn set_local(&self, val: T)
    {
        let mut st = self.val.write();
        *st = Some(val);
        self.inc_local();
    }

    /// Replaces the stored value.
    pub fn replace(&self, val: T) -> T
    {
        let mut st = self.val.write();
        let old = st.take().expect(ERR_EMPTY);
        *st = Some(val);
        self.inc_root();
        old
    }

    /// Passes the stored value through a function.
    pub fn replace_with<F>(&self, f: F)
        where F: FnOnce(T) -> T
    {
        let mut st = self.val.write();
        let old = st.take().expect(ERR_EMPTY);
        *st = Some(f(old));
        self.inc_root();
    }

    /// Checks if a parent storage has changed, so this needs update.
    pub fn must_update(&self) -> bool
    {
        self.root_ser.load(Ordering::Relaxed) > self.serial.load(Ordering::Relaxed)
    }

    /// Increments the serial of a source signal, so child must update.
    pub fn inc_root(&self)
    {
        self.root_ser.fetch_add(1, Ordering::Relaxed);
    }

    /// Marks this storage as updated.
    pub fn inc_local(&self)
    {
        self.serial.store(self.root_ser.load(Ordering::Relaxed), Ordering::Relaxed);
    }
}

impl<T> Default for Storage<T>
{
    fn default() -> Self
    {
        Storage{
            val: Default::default(),
            serial: Default::default(),
            root_ser: Arc::new(AtomicUsize::new(1)),
        }
    }
}

/// Defines a signal that contains shared storage.
pub(crate) trait SharedSignal<T>
{
    /// Updates the signal.
    fn update(&self);
    /// Checks if the value has changed.
    fn has_changed(&self) -> bool;
    /// Obtains the internal storage.
    fn get_storage(&self) -> &Storage<T>;
    /// Samples the signal.
    fn sample(&self) -> &Storage<T>;
}

/// Common template for shared signal implementations.
pub(crate) struct SharedImpl<T, S, F>
{
    pub storage: Storage<T>,
    pub source: S,
    pub f: F,
}

impl<T, S, F> ops::Deref for SharedImpl<T, S, F>
{
    type Target = Storage<T>;

    fn deref(&self) -> &Self::Target
    {
        &self.storage
    }
}
<|endoftext|>


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

use c;
use low;

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

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

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

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>) -> FfiTypeArray_ {
    let size = elements.len();
    let array = libc::malloc((size+1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;

    for i in 0 .. size {
        *array.offset(i as isize) = elements[i].0;
    }
    *array.offset(size as isize) = ptr::null::<low::ffi_type>() as FfiType_;

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

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

    array
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> FfiType_ {
    println!("ffi_type_array_create({:?})", elements);
    let array    = ffi_type_array_create(elements);
    let ffi_type = libc::malloc(mem::size_of::<low::ffi_type>())
                       as FfiType_;

    (*ffi_type).size      = 0;
    (*ffi_type).alignment = 0;
    (*ffi_type).type_     = c::ffi_type_enum::STRUCT as u16;
    (*ffi_type).elements  = array;

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

    ffi_type
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}
<commit_msg>added stubs for ffi_type_clone and ffi_type_array_clone<commit_after>use std::{mem, ptr};
use libc;

use c;
use low;

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

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

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

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>) -> FfiTypeArray_ {
    let size = elements.len();
    let array = libc::malloc((size+1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;

    for i in 0 .. size {
        *array.offset(i as isize) = elements[i].0;
    }
    *array.offset(size as isize) = ptr::null::<low::ffi_type>() as FfiType_;

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

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

    array
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> FfiType_ {
    println!("ffi_type_array_create({:?})", elements);
    let array    = ffi_type_array_create(elements);
    let ffi_type = libc::malloc(mem::size_of::<low::ffi_type>())
                       as FfiType_;

    (*ffi_type).size      = 0;
    (*ffi_type).alignment = 0;
    (*ffi_type).type_     = c::ffi_type_enum::STRUCT as u16;
    (*ffi_type).elements  = array;

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

    ffi_type
}

unsafe fn ffi_type_array_clone(ffi_types: FfiTypeArray_) -> FfiTypeArray_ {
    unimplemented!();
}

unsafe fn ffn_type_clone(ffi_type: FfiType_) -> FfiType_ {
    unimplemented!();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}
<|endoftext|>


<commit_before>//! Just embed git-hash to `--version`

use std::{env, path::PathBuf, process::Command};

fn main() {
    set_rerun();

    let rev = rev().unwrap_or_else(|| "???????".to_string());
    println!("cargo:rustc-env=REV={}", rev)
}

fn set_rerun() {
    let mut manifest_dir = PathBuf::from(
        env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."),
    );

    while manifest_dir.parent().is_some() {
        if manifest_dir.join(".git/HEAD").exists() {
            let git_dir = manifest_dir.join(".git");

            println!("cargo:rerun-if-changed={}", git_dir.join("HEAD").display());
            // current branch ref
            if let Ok(output) =
                Command::new("git").args(&["rev-parse", "--symbolic-full-name", "HEAD"]).output()
            {
                if let Ok(ref_link) = String::from_utf8(output.stdout) {
                    println!("cargo:rerun-if-changed={}", git_dir.join(ref_link).display());
                }
            }
            return;
        }

        manifest_dir.pop();
    }
    println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!");
}

fn rev() -> Option<String> {
    let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().ok()?;
    let stdout = String::from_utf8(output.stdout).ok()?;
    let short_hash = stdout.get(0..7)?;
    Some(short_hash.to_owned())
}
<commit_msg>Allow overriding rust-analyzer display revision<commit_after>//! Just embed git-hash to `--version`

use std::{env, path::PathBuf, process::Command};

fn main() {
    set_rerun();

    let rev = env::var("RUST_ANALYZER_REV").ok().or_else(rev).unwrap_or_else(|| "???????".to_string());
    println!("cargo:rustc-env=REV={}", rev)
}

fn set_rerun() {
    println!("cargo:rerun-if-env-changed=RUST_ANALYZER_REV");

    let mut manifest_dir = PathBuf::from(
        env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."),
    );

    while manifest_dir.parent().is_some() {
        if manifest_dir.join(".git/HEAD").exists() {
            let git_dir = manifest_dir.join(".git");

            println!("cargo:rerun-if-changed={}", git_dir.join("HEAD").display());
            // current branch ref
            if let Ok(output) =
                Command::new("git").args(&["rev-parse", "--symbolic-full-name", "HEAD"]).output()
            {
                if let Ok(ref_link) = String::from_utf8(output.stdout) {
                    println!("cargo:rerun-if-changed={}", git_dir.join(ref_link).display());
                }
            }
            return;
        }

        manifest_dir.pop();
    }
    println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!");
}

fn rev() -> Option<String> {
    let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().ok()?;
    let stdout = String::from_utf8(output.stdout).ok()?;
    let short_hash = stdout.get(0..7)?;
    Some(short_hash.to_owned())
}
<|endoftext|>


<commit_before>use screen;
use screen::Screen;

use piston_window;

type Screens = Vec<Box<screen::Screen>>;

pub struct Game {
    window: piston_window::PistonWindow,
    screens: Screens,
}

impl Game {
    pub fn new() -> Game {
        let window: piston_window::PistonWindow = piston_window::WindowSettings::new("rrthozopsi", [600, 600])
                                                      .exit_on_esc(true)
                                                      .build()
                                                      .unwrap();
        let screens: Screens = vec![Box::new(screen::MainMenuScreen::new())];
        Game {
            window: window,
            screens: screens,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        let screens = &mut self.screens;

        // TODO: Remove clone?
        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => {
                    last(screens).on_update(&args);
                }
                Some(Event::Render(ref args)) => {
                    last(screens).on_draw(&args, &window);
                }
                Some(Event::Input(ref input)) => {
                    handle_input(screens, &input, &window);
                }
                _ => {}
            }
        }
    }
}

fn last<'a>(vec: &'a mut Screens) -> &'a mut Box<screen::Screen> {
    vec.last_mut().unwrap()
}

fn handle_input(screens: &mut Screens, input: &piston_window::Input, window: &piston_window::PistonWindow) {
    for action in last(screens).on_input(&input, &window) {
        match action {
            screen::InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            screen::InputResult::PopScreen => {
                screens.pop();
            }
        }
    }
}
<commit_msg>TODO: Ui<commit_after>use screen;
use screen::Screen;

use piston_window;

type Screens = Vec<Box<screen::Screen>>;

pub struct Game {
    window: piston_window::PistonWindow,
    screens: Screens,
}

impl Game {
    pub fn new() -> Game {
        let window: piston_window::PistonWindow = piston_window::WindowSettings::new("rrthozopsi", [600, 600])
                                                      .exit_on_esc(true)
                                                      .build()
                                                      .unwrap();
        let screens: Screens = vec![Box::new(screen::MainMenuScreen::new())];
        Game {
            window: window,
            screens: screens,
        }

// TODO: Create Ui.
/*
        let mut ui = {
            let assets = find_folder::Search::KidsThenParents(3, 5)
                .for_folder("assets").unwrap();
            let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
            let theme = Theme::default();
            let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
            Ui::new(glyph_cache.unwrap(), theme)
        };
*/
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        let screens = &mut self.screens;

        // TODO: Remove clone?
        for window in &mut self.window {
            match window.event {
                Some(Event::Update(ref args)) => {
                    last(screens).on_update(&args);
                }
                Some(Event::Render(ref args)) => {
                    last(screens).on_draw(&args, &window);
                }
                Some(Event::Input(ref input)) => {
                    handle_input(screens, &input, &window);
                }
                _ => {}
            }
        }
    }
}

fn last<'a>(vec: &'a mut Screens) -> &'a mut Box<screen::Screen> {
    vec.last_mut().unwrap()
}

fn handle_input(screens: &mut Screens, input: &piston_window::Input, window: &piston_window::PistonWindow) {
    for action in last(screens).on_input(&input, &window) {
        match action {
            screen::InputResult::PushScreen(new_screen) => {
                screens.push(new_screen);
            }
            screen::InputResult::PopScreen => {
                screens.pop();
            }
        }
    }
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

extern crate num_bigint;
extern crate num_traits;

use num_bigint::{BigUint};

pub fn set_panic_hook() {
    // When the `console_error_panic_hook` feature is enabled, we can call the
    // `set_panic_hook` function at least once during initialization, and then
    // we will get better error messages if our code ever panics.
    //
    // For more details see
    // https://github.com/rustwasm/console_error_panic_hook#readme
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

pub fn nth(num: usize) -> String {
    //format a number to say 1st, 2nd, 3rd etc
    format!("{}{}", num, match (num % 10, num % 100) {
        (1, 11) | (2, 12) | (3, 13) => "th",
        (1, _) => "st",
        (2, _) => "nd",
        (3, _) => "rd",
        _ => "th",
    })
}

pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = format!("data:text/plain,{}",&filecontent);
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
}

pub fn generate_file(n:u64, value:BigUint) -> seed::dom_types::Node<Msg> {
    let download_filename:String = format!("P{}.txt",&n.to_string());
    save_as_file(download_filename, value.to_string())
}

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

    #[test]
    fn nth_test() {
        assert_eq!(nth(7), "7th");
        assert_ne!(nth(7), "1st");
        assert_eq!(nth(7000000000000000000), "7000000000000000000th");
        assert_eq!(nth(7000000000000000001), "7000000000000000001st");
        assert_eq!(nth(7000000000000000002), "7000000000000000002nd");
        assert_eq!(nth(7000000000000000003), "7000000000000000003rd");
        assert_eq!(nth(7000000000000000011), "7000000000000000011th");
        assert_eq!(nth(7000000000000000012), "7000000000000000012th");
        assert_eq!(nth(7000000000000000013), "7000000000000000013th");
    }
}
<commit_msg>Added test to check download link text<commit_after>use seed::prelude::*;
use crate::Msg;

extern crate num_bigint;
extern crate num_traits;

use num_bigint::{BigUint};

pub fn set_panic_hook() {
    // When the `console_error_panic_hook` feature is enabled, we can call the
    // `set_panic_hook` function at least once during initialization, and then
    // we will get better error messages if our code ever panics.
    //
    // For more details see
    // https://github.com/rustwasm/console_error_panic_hook#readme
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

pub fn nth(num: usize) -> String {
    //format a number to say 1st, 2nd, 3rd etc
    format!("{}{}", num, match (num % 10, num % 100) {
        (1, 11) | (2, 12) | (3, 13) => "th",
        (1, _) => "st",
        (2, _) => "nd",
        (3, _) => "rd",
        _ => "th",
    })
}

pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = format!("data:text/plain,{}",&filecontent);
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
}

pub fn generate_file(n:u64, value:BigUint) -> seed::dom_types::Node<Msg> {
    let download_filename:String = format!("P{}.txt",&n.to_string());
    save_as_file(download_filename, value.to_string())
}

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

    #[test]
    fn nth_test() {
        assert_eq!(nth(7), "7th");
        assert_ne!(nth(7), "1st");
        assert_eq!(nth(7000000000000000000), "7000000000000000000th");
        assert_eq!(nth(7000000000000000001), "7000000000000000001st");
        assert_eq!(nth(7000000000000000002), "7000000000000000002nd");
        assert_eq!(nth(7000000000000000003), "7000000000000000003rd");
        assert_eq!(nth(7000000000000000011), "7000000000000000011th");
        assert_eq!(nth(7000000000000000012), "7000000000000000012th");
        assert_eq!(nth(7000000000000000013), "7000000000000000013th");
    }

    #[test]
    fn save_as_file_test() {
        let test_file = save_as_file(
            String::from("example name"),
            String::from("some content")
        );

        assert_eq!(test_file.get_text(), "TXT");
        //todo: we are only testing the link text currently
    }
}
<|endoftext|>


<commit_before>//! Utility functions.

use cretonne::ir::entities::AnyEntity;
use cretonne::{ir, verifier};
use cretonne::result::CtonError;
use cretonne::isa::TargetIsa;
use cretonne::settings::{self, FlagsOrIsa};
use cretonne::isa;
use cton_reader::{parse_options, Location};
use std::fmt::Write;
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;

/// Read an entire file into a string.
pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
    let mut file = File::open(path)?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?;
    Ok(buffer)
}

/// Read an entire file into a vector of bytes.
pub fn read_to_end<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
    let mut file = File::open(path)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;
    Ok(buffer)
}

/// Look for a directive in a comment string.
/// The directive is of the form "foo:" and should follow the leading `;` in the comment:
///
/// ; dominates: ebb3 ebb4
///
/// Return the comment text following the directive.
pub fn match_directive<'a>(comment: &'a str, directive: &str) -> Option<&'a str> {
    assert!(
        directive.ends_with(':'),
        "Directive must include trailing colon"
    );
    let text = comment.trim_left_matches(';').trim_left();
    if text.starts_with(directive) {
        Some(text[directive.len()..].trim())
    } else {
        None
    }
}

/// Pretty-print a verifier error.
pub fn pretty_verifier_error(
    func: &ir::Function,
    isa: Option<&TargetIsa>,
    err: verifier::Error,
) -> String {
    let mut msg = err.to_string();
    match err.location {
        AnyEntity::Inst(inst) => {
            write!(msg, "\n{}: {}\n\n", inst, func.dfg.display_inst(inst, isa)).unwrap()
        }
        _ => msg.push('\n'),
    }
    write!(msg, "{}", func.display(isa)).unwrap();
    msg
}

/// Pretty-print a Cretonne error.
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CtonError) -> String {
    if let CtonError::Verifier(e) = err {
        pretty_verifier_error(func, isa, e)
    } else {
        err.to_string()
    }
}

/// Like FlagsOrIsa, but holds ownership.
pub enum OwnedFlagsOrIsa {
    Flags(settings::Flags),
    Isa(Box<TargetIsa>),
}

impl OwnedFlagsOrIsa {
    /// Produce a FlagsOrIsa reference.
    pub fn as_fisa(&self) -> FlagsOrIsa {
        match *self {
            OwnedFlagsOrIsa::Flags(ref flags) => FlagsOrIsa::from(flags),
            OwnedFlagsOrIsa::Isa(ref isa) => FlagsOrIsa::from(&**isa),
        }
    }
}

/// Parse "set" and "isa" commands.
pub fn parse_sets_and_isa(
    flag_set: Vec<String>,
    flag_isa: String,
) -> Result<OwnedFlagsOrIsa, String> {
    let mut flag_builder = settings::builder();
    parse_options(
        flag_set.iter().map(|x| x.as_str()),
        &mut flag_builder,
        &Location { line_number: 0 },
    ).map_err(|err| err.to_string())?;

    let mut words = flag_isa.trim().split_whitespace();
    // Look for `isa foo`.
    if let Some(isa_name) = words.next() {
        let isa_builder = isa::lookup(isa_name).map_err(|err| match err {
            isa::LookupError::Unknown => format!("unknown ISA '{}'", isa_name),
            isa::LookupError::Unsupported => format!("support for ISA '{}' not enabled", isa_name),
        })?;
        Ok(OwnedFlagsOrIsa::Isa(
            isa_builder.finish(settings::Flags::new(&flag_builder)),
        ))
    } else {
        Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(&flag_builder)))
    }
}

#[test]
fn test_match_directive() {
    assert_eq!(match_directive("; foo: bar  ", "foo:"), Some("bar"));
    assert_eq!(match_directive(" foo:bar", "foo:"), Some("bar"));
    assert_eq!(match_directive("foo:bar", "foo:"), Some("bar"));
    assert_eq!(match_directive(";x foo: bar", "foo:"), None);
    assert_eq!(match_directive(";;; foo: bar", "foo:"), Some("bar"));
}
<commit_msg>Support ISA-specific settings in the `--isa` command-line option.<commit_after>//! Utility functions.

use cretonne::ir::entities::AnyEntity;
use cretonne::{ir, verifier};
use cretonne::result::CtonError;
use cretonne::isa::TargetIsa;
use cretonne::settings::{self, FlagsOrIsa};
use cretonne::isa;
use cton_reader::{parse_options, Location};
use std::fmt::Write;
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;

/// Read an entire file into a string.
pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
    let mut file = File::open(path)?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?;
    Ok(buffer)
}

/// Read an entire file into a vector of bytes.
pub fn read_to_end<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
    let mut file = File::open(path)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;
    Ok(buffer)
}

/// Look for a directive in a comment string.
/// The directive is of the form "foo:" and should follow the leading `;` in the comment:
///
/// ; dominates: ebb3 ebb4
///
/// Return the comment text following the directive.
pub fn match_directive<'a>(comment: &'a str, directive: &str) -> Option<&'a str> {
    assert!(
        directive.ends_with(':'),
        "Directive must include trailing colon"
    );
    let text = comment.trim_left_matches(';').trim_left();
    if text.starts_with(directive) {
        Some(text[directive.len()..].trim())
    } else {
        None
    }
}

/// Pretty-print a verifier error.
pub fn pretty_verifier_error(
    func: &ir::Function,
    isa: Option<&TargetIsa>,
    err: verifier::Error,
) -> String {
    let mut msg = err.to_string();
    match err.location {
        AnyEntity::Inst(inst) => {
            write!(msg, "\n{}: {}\n\n", inst, func.dfg.display_inst(inst, isa)).unwrap()
        }
        _ => msg.push('\n'),
    }
    write!(msg, "{}", func.display(isa)).unwrap();
    msg
}

/// Pretty-print a Cretonne error.
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CtonError) -> String {
    if let CtonError::Verifier(e) = err {
        pretty_verifier_error(func, isa, e)
    } else {
        err.to_string()
    }
}

/// Like FlagsOrIsa, but holds ownership.
pub enum OwnedFlagsOrIsa {
    Flags(settings::Flags),
    Isa(Box<TargetIsa>),
}

impl OwnedFlagsOrIsa {
    /// Produce a FlagsOrIsa reference.
    pub fn as_fisa(&self) -> FlagsOrIsa {
        match *self {
            OwnedFlagsOrIsa::Flags(ref flags) => FlagsOrIsa::from(flags),
            OwnedFlagsOrIsa::Isa(ref isa) => FlagsOrIsa::from(&**isa),
        }
    }
}

/// Parse "set" and "isa" commands.
pub fn parse_sets_and_isa(
    flag_set: Vec<String>,
    flag_isa: String,
) -> Result<OwnedFlagsOrIsa, String> {
    let mut flag_builder = settings::builder();
    parse_options(
        flag_set.iter().map(|x| x.as_str()),
        &mut flag_builder,
        &Location { line_number: 0 },
    ).map_err(|err| err.to_string())?;

    let mut words = flag_isa.trim().split_whitespace();
    // Look for `isa foo`.
    if let Some(isa_name) = words.next() {
        let mut isa_builder = isa::lookup(isa_name).map_err(|err| match err {
            isa::LookupError::Unknown => format!("unknown ISA '{}'", isa_name),
            isa::LookupError::Unsupported => format!("support for ISA '{}' not enabled", isa_name),
        })?;
        // Apply the ISA-specific settings to `isa_builder`.
        parse_options(words, &mut isa_builder, &Location { line_number: 0 })
            .map_err(|err| err.to_string())?;

        Ok(OwnedFlagsOrIsa::Isa(
            isa_builder.finish(settings::Flags::new(&flag_builder)),
        ))
    } else {
        Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(&flag_builder)))
    }
}

#[test]
fn test_match_directive() {
    assert_eq!(match_directive("; foo: bar  ", "foo:"), Some("bar"));
    assert_eq!(match_directive(" foo:bar", "foo:"), Some("bar"));
    assert_eq!(match_directive("foo:bar", "foo:"), Some("bar"));
    assert_eq!(match_directive(";x foo: bar", "foo:"), None);
    assert_eq!(match_directive(";;; foo: bar", "foo:"), Some("bar"));
}
<|endoftext|>