<commit_before>use std::{fmt, ops::Bound};

use crate::Lazy;

use super::*;

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Node {
    pub(crate) data: Data,
    pub(crate) next: Option<PageId>,
    pub(crate) lo: IVec,
    pub(crate) hi: IVec,
    pub(crate) merging_child: Option<PageId>,
    pub(crate) merging: bool,
}

impl Debug for Node {
    fn fmt(
        &self,
        f: &mut fmt::Formatter<'_>,
    ) -> std::result::Result<(), fmt::Error> {
        let data = self.data.fmt_keys(&self.lo);

        write!(
            f,
            "Node {{ \
             lo: {:?} \
             hi: {:?} \
             next: {:?} \
             merging_child: {:?} \
             merging: {} \
             data: {:?} }}",
            self.lo, self.hi, self.next, self.merging_child, self.merging, data
        )
    }
}

impl Node {
    pub(crate) fn apply(&mut self, frag: &Frag) {
        use self::Frag::*;

        assert!(
            !self.merging,
            "somehow a frag was applied to a node after it was merged"
        );

        match *frag {
            Set(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.set_leaf(k.clone(), v.clone());
                } else {
                    panic!(
                        "tried to consolidate set at key <= hi.\
                         Set({:?}, {:?}) to node {:?}",
                        k, v, self
                    )
                }
            }
            Del(ref k) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.del_leaf(k);
                } else {
                    panic!("tried to consolidate del at key <= hi")
                }
            }
            Base(_) => panic!("trying to apply a Base to frag {:?}", self),
            ParentMergeIntention(pid) => {
                assert!(
                    self.merging_child.is_none(),
                    "trying to merge {:?} into node {:?} which \
                     is already merging another child",
                    frag,
                    self
                );
                self.merging_child = Some(pid);
            }
            ParentMergeConfirm => {
                assert!(self.merging_child.is_some());
                let merged_child = self.merging_child.take().expect(
                    "we should have a specific \
                     child that was merged if this \
                     frag appears here",
                );
                self.data.parent_merge_confirm(merged_child);
            }
            ChildMergeCap => {
                self.merging = true;
            }
        }
    }

    pub(crate) fn set_leaf(&mut self, key: IVec, val: IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records.binary_search_by(|(k, _)| prefix_cmp(k, &key));
            match search {
                Ok(idx) => records[idx] = (key, val),
                Err(idx) => records.insert(idx, (key, val)),
            }
        } else {
            panic!("tried to Set a value to an index");
        }
    }

    pub(crate) fn parent_split(&mut self, at: &[u8], to: PageId) -> bool {
        if let Data::Index(ref mut ptrs) = self.data {
            let encoded_sep = prefix_encode(&self.lo, at);
            match ptrs.binary_search_by(|a| prefix_cmp(&a.0, &encoded_sep)) {
                Ok(_) => {
                    debug!(
                        "parent_split skipped because \
                         parent already contains child at split point \
                         due to deep race"
                    );
                    return false;
                }
                Err(idx) => ptrs.insert(idx, (encoded_sep, to)),
            }
        } else {
            panic!("tried to attach a ParentSplit to a Leaf chain");
        }

        true
    }

    pub(crate) fn del_leaf(&mut self, key: &IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records
                .binary_search_by(|&(ref k, ref _v)| prefix_cmp(k, &*key));
            if let Ok(idx) = search {
                let _removed = records.remove(idx);
            }
        } else {
            panic!("tried to attach a Del to an Index chain");
        }
    }

    pub(crate) fn split(mut self) -> (Self, Self) {
        let (split, right_data) = self.data.split(&self.lo);
        let rhs = Self {
            data: right_data,
            next: self.next,
            lo: split,
            hi: self.hi.clone(),
            merging_child: None,
            merging: false,
        };

        self.data.drop_gte(&rhs.lo, &self.lo);
        self.hi = rhs.lo.clone();

        // intentionally make this the end to make
        // any issues pop out with setting it
        // correctly after the split.
        self.next = None;

        (self, rhs)
    }

    pub(crate) fn receive_merge(&self, rhs: &Self) -> Self {
        let mut merged = self.clone();
        merged.hi = rhs.hi.clone();
        merged.data.receive_merge(
            rhs.lo.as_ref(),
            merged.lo.as_ref(),
            &rhs.data,
        );
        merged.next = rhs.next;
        merged
    }

    pub(crate) fn contains_upper_bound(&self, bound: &Bound<IVec>) -> bool {
        match bound {
            Bound::Excluded(bound) if self.hi >= *bound => true,
            Bound::Included(bound) if self.hi > *bound => true,
            _ => self.hi.is_empty(),
        }
    }

    pub(crate) fn contains_lower_bound(
        &self,
        bound: &Bound<IVec>,
        is_forward: bool,
    ) -> bool {
        match bound {
            Bound::Excluded(bound)
                if self.lo < *bound || (is_forward && *bound == self.lo) =>
            {
                true
            }
            Bound::Included(bound) if self.lo <= *bound => true,
            Bound::Unbounded if !is_forward => self.hi.is_empty(),
            _ => self.lo.is_empty(),
        }
    }

    pub(crate) fn successor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.data.is_index());

        // This encoding happens this way because
        // keys cannot be lower than the node's lo key.
        let predecessor_key = match bound {
            Bound::Unbounded => prefix_encode(&self.lo, &self.lo),
            Bound::Included(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
            Bound::Excluded(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &predecessor_key));

        let idx = match search {
            Ok(idx) => idx,
            Err(idx) if idx < records.len() => idx,
            _ => return None,
        };

        for (k, v) in &records[idx..] {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }

        None
    }

    pub(crate) fn predecessor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        static MAX_IVEC: Lazy<IVec, fn() -> IVec> = Lazy::new(init_max_ivec);

        fn init_max_ivec() -> IVec {
            let mut base = vec![255; 1024 * 1024];
            base[0] = 0;
            IVec::from(base)
        }

        assert!(!self.data.is_index());

        // This encoding happens this way because
        // the rightmost (unbounded) node has
        // a hi key represented by the empty slice
        let successor_key = match bound {
            Bound::Unbounded => {
                if self.hi.is_empty() {
                    MAX_IVEC.clone()
                } else {
                    prefix_encode(&self.lo, &self.hi)
                }
            }
            Bound::Included(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
            Bound::Excluded(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &successor_key));

        let idx = match search {
            Ok(idx) => idx,
            Err(idx) if idx > 0 => idx - 1,
            _ => return None,
        };

        for (k, v) in records[0..=idx].iter().rev() {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }
        None
    }

    /// leaf_pair_for_key finds an existing value pair for a given key.
    pub(crate) fn leaf_pair_for_key(
        &self,
        key: &[u8],
    ) -> Option<(&IVec, &IVec)> {
        let records = self
            .data
            .leaf_ref()
            .expect("leaf_pair_for_key called on index node");

        let common_prefix = key
            .iter()
            .zip(self.lo.iter())
            .take(u8::max_value() as usize)
            .take_while(|(a, b)| a == b)
            .count() as u8;

        let search = records
            .binary_search_by(|&(ref k, ref _v)| {
                if k[0] > common_prefix {
                    Ordering::Less
                } else if k[0] < common_prefix {
                    Ordering::Greater
                } else {
                    k[1..].cmp(&key[common_prefix as usize..])
                }
            })
            .ok();

        search.map(|idx| (&records[idx].0, &records[idx].1))
    }

    /// node_kv_pair returns either existing (node/key, value) pair or
    /// (node/key, none) where a node/key is node level encoded key.
    pub fn node_kv_pair(&self, key: &[u8]) -> (IVec, Option<IVec>) {
        if let Some((k, v)) = self.leaf_pair_for_key(key.as_ref()) {
            (k.clone(), Some(v.clone()))
        } else {
            let encoded_key = prefix_encode(&self.lo, key.as_ref());
            let encoded_val = None;
            (encoded_key, encoded_val)
        }
    }

    pub(crate) fn should_split(&self) -> bool {
        let threshold = if cfg!(any(test, feature = "lock_free_delays")) {
            2
        } else if self.data.is_index() {
            256
        } else {
            16
        };

        let size_checks = self.data.len() > threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn should_merge(&self) -> bool {
        let threshold = if cfg!(any(test, feature = "lock_free_delays")) {
            1
        } else if self.data.is_index() {
            64
        } else {
            4
        };

        let size_checks = self.data.len() < threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn can_merge_child(&self) -> bool {
        self.merging_child.is_none() && !self.merging
    }

    pub(crate) fn index_next_node(&self, key: &[u8]) -> (usize, PageId) {
        let records = self
            .data
            .index_ref()
            .expect("index_next_node called on leaf");

        let common_prefix = key
            .iter()
            .zip(self.lo.iter())
            .take(u8::max_value() as usize)
            .take_while(|(a, b)| a == b)
            .count() as u8;

        let search = binary_search_lub(records, |&(ref k, ref _v)| {
            if k[0] > common_prefix {
                Ordering::Less
            } else if k[0] < common_prefix {
                Ordering::Greater
            } else {
                k[1..].cmp(&key[common_prefix as usize..])
            }
        });

        let index = search.expect("failed to traverse index");

        (index, records[index].1)
    }
}
<commit_msg>fix compilation<commit_after>use std::{cmp::Ordering, fmt, ops::Bound};

use crate::Lazy;

use super::*;

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Node {
    pub(crate) data: Data,
    pub(crate) next: Option<PageId>,
    pub(crate) lo: IVec,
    pub(crate) hi: IVec,
    pub(crate) merging_child: Option<PageId>,
    pub(crate) merging: bool,
}

impl Debug for Node {
    fn fmt(
        &self,
        f: &mut fmt::Formatter<'_>,
    ) -> std::result::Result<(), fmt::Error> {
        let data = self.data.fmt_keys(&self.lo);

        write!(
            f,
            "Node {{ \
             lo: {:?} \
             hi: {:?} \
             next: {:?} \
             merging_child: {:?} \
             merging: {} \
             data: {:?} }}",
            self.lo, self.hi, self.next, self.merging_child, self.merging, data
        )
    }
}

impl Node {
    pub(crate) fn apply(&mut self, frag: &Frag) {
        use self::Frag::*;

        assert!(
            !self.merging,
            "somehow a frag was applied to a node after it was merged"
        );

        match *frag {
            Set(ref k, ref v) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.set_leaf(k.clone(), v.clone());
                } else {
                    panic!(
                        "tried to consolidate set at key <= hi.\
                         Set({:?}, {:?}) to node {:?}",
                        k, v, self
                    )
                }
            }
            Del(ref k) => {
                // (when hi is empty, it means it's unbounded)
                if self.hi.is_empty()
                    || prefix_cmp_encoded(k, &self.hi, &self.lo)
                        == std::cmp::Ordering::Less
                {
                    self.del_leaf(k);
                } else {
                    panic!("tried to consolidate del at key <= hi")
                }
            }
            Base(_) => panic!("trying to apply a Base to frag {:?}", self),
            ParentMergeIntention(pid) => {
                assert!(
                    self.merging_child.is_none(),
                    "trying to merge {:?} into node {:?} which \
                     is already merging another child",
                    frag,
                    self
                );
                self.merging_child = Some(pid);
            }
            ParentMergeConfirm => {
                assert!(self.merging_child.is_some());
                let merged_child = self.merging_child.take().expect(
                    "we should have a specific \
                     child that was merged if this \
                     frag appears here",
                );
                self.data.parent_merge_confirm(merged_child);
            }
            ChildMergeCap => {
                self.merging = true;
            }
        }
    }

    pub(crate) fn set_leaf(&mut self, key: IVec, val: IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records.binary_search_by(|(k, _)| prefix_cmp(k, &key));
            match search {
                Ok(idx) => records[idx] = (key, val),
                Err(idx) => records.insert(idx, (key, val)),
            }
        } else {
            panic!("tried to Set a value to an index");
        }
    }

    pub(crate) fn parent_split(&mut self, at: &[u8], to: PageId) -> bool {
        if let Data::Index(ref mut ptrs) = self.data {
            let encoded_sep = prefix_encode(&self.lo, at);
            match ptrs.binary_search_by(|a| prefix_cmp(&a.0, &encoded_sep)) {
                Ok(_) => {
                    debug!(
                        "parent_split skipped because \
                         parent already contains child at split point \
                         due to deep race"
                    );
                    return false;
                }
                Err(idx) => ptrs.insert(idx, (encoded_sep, to)),
            }
        } else {
            panic!("tried to attach a ParentSplit to a Leaf chain");
        }

        true
    }

    pub(crate) fn del_leaf(&mut self, key: &IVec) {
        if let Data::Leaf(ref mut records) = self.data {
            let search = records
                .binary_search_by(|&(ref k, ref _v)| prefix_cmp(k, &*key));
            if let Ok(idx) = search {
                let _removed = records.remove(idx);
            }
        } else {
            panic!("tried to attach a Del to an Index chain");
        }
    }

    pub(crate) fn split(mut self) -> (Self, Self) {
        let (split, right_data) = self.data.split(&self.lo);
        let rhs = Self {
            data: right_data,
            next: self.next,
            lo: split,
            hi: self.hi.clone(),
            merging_child: None,
            merging: false,
        };

        self.data.drop_gte(&rhs.lo, &self.lo);
        self.hi = rhs.lo.clone();

        // intentionally make this the end to make
        // any issues pop out with setting it
        // correctly after the split.
        self.next = None;

        (self, rhs)
    }

    pub(crate) fn receive_merge(&self, rhs: &Self) -> Self {
        let mut merged = self.clone();
        merged.hi = rhs.hi.clone();
        merged.data.receive_merge(
            rhs.lo.as_ref(),
            merged.lo.as_ref(),
            &rhs.data,
        );
        merged.next = rhs.next;
        merged
    }

    pub(crate) fn contains_upper_bound(&self, bound: &Bound<IVec>) -> bool {
        match bound {
            Bound::Excluded(bound) if self.hi >= *bound => true,
            Bound::Included(bound) if self.hi > *bound => true,
            _ => self.hi.is_empty(),
        }
    }

    pub(crate) fn contains_lower_bound(
        &self,
        bound: &Bound<IVec>,
        is_forward: bool,
    ) -> bool {
        match bound {
            Bound::Excluded(bound)
                if self.lo < *bound || (is_forward && *bound == self.lo) =>
            {
                true
            }
            Bound::Included(bound) if self.lo <= *bound => true,
            Bound::Unbounded if !is_forward => self.hi.is_empty(),
            _ => self.lo.is_empty(),
        }
    }

    pub(crate) fn successor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        assert!(!self.data.is_index());

        // This encoding happens this way because
        // keys cannot be lower than the node's lo key.
        let predecessor_key = match bound {
            Bound::Unbounded => prefix_encode(&self.lo, &self.lo),
            Bound::Included(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
            Bound::Excluded(b) => {
                let max = std::cmp::max(b, &self.lo);
                prefix_encode(&self.lo, max)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &predecessor_key));

        let idx = match search {
            Ok(idx) => idx,
            Err(idx) if idx < records.len() => idx,
            _ => return None,
        };

        for (k, v) in &records[idx..] {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }

        None
    }

    pub(crate) fn predecessor(
        &self,
        bound: &Bound<IVec>,
    ) -> Option<(IVec, IVec)> {
        static MAX_IVEC: Lazy<IVec, fn() -> IVec> = Lazy::new(init_max_ivec);

        fn init_max_ivec() -> IVec {
            let mut base = vec![255; 1024 * 1024];
            base[0] = 0;
            IVec::from(base)
        }

        assert!(!self.data.is_index());

        // This encoding happens this way because
        // the rightmost (unbounded) node has
        // a hi key represented by the empty slice
        let successor_key = match bound {
            Bound::Unbounded => {
                if self.hi.is_empty() {
                    MAX_IVEC.clone()
                } else {
                    prefix_encode(&self.lo, &self.hi)
                }
            }
            Bound::Included(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
            Bound::Excluded(b) => {
                let min = if self.hi.is_empty() {
                    b
                } else {
                    std::cmp::min(b, &self.hi)
                };
                prefix_encode(&self.lo, min)
            }
        };

        let records = self.data.leaf_ref().unwrap();
        let search =
            records.binary_search_by(|(k, _)| prefix_cmp(k, &successor_key));

        let idx = match search {
            Ok(idx) => idx,
            Err(idx) if idx > 0 => idx - 1,
            _ => return None,
        };

        for (k, v) in records[0..=idx].iter().rev() {
            match bound {
                Bound::Excluded(b)
                    if prefix_cmp_encoded(k, b, &self.lo)
                        == std::cmp::Ordering::Equal =>
                {
                    // keep going because we wanted to exclude
                    // this key.
                    continue;
                }
                _ => {}
            }
            let decoded_key = prefix_decode(&self.lo, &k);
            return Some((IVec::from(decoded_key), v.clone()));
        }
        None
    }

    /// leaf_pair_for_key finds an existing value pair for a given key.
    pub(crate) fn leaf_pair_for_key(
        &self,
        key: &[u8],
    ) -> Option<(&IVec, &IVec)> {
        let records = self
            .data
            .leaf_ref()
            .expect("leaf_pair_for_key called on index node");

        let common_prefix = key
            .iter()
            .zip(self.lo.iter())
            .take(u8::max_value() as usize)
            .take_while(|(a, b)| a == b)
            .count() as u8;

        let search = records
            .binary_search_by(|&(ref k, ref _v)| {
                if k[0] > common_prefix {
                    Ordering::Less
                } else if k[0] < common_prefix {
                    Ordering::Greater
                } else {
                    k[1..].cmp(&key[common_prefix as usize..])
                }
            })
            .ok();

        search.map(|idx| (&records[idx].0, &records[idx].1))
    }

    /// node_kv_pair returns either existing (node/key, value) pair or
    /// (node/key, none) where a node/key is node level encoded key.
    pub fn node_kv_pair(&self, key: &[u8]) -> (IVec, Option<IVec>) {
        if let Some((k, v)) = self.leaf_pair_for_key(key.as_ref()) {
            (k.clone(), Some(v.clone()))
        } else {
            let encoded_key = prefix_encode(&self.lo, key.as_ref());
            let encoded_val = None;
            (encoded_key, encoded_val)
        }
    }

    pub(crate) fn should_split(&self) -> bool {
        let threshold = if cfg!(any(test, feature = "lock_free_delays")) {
            2
        } else if self.data.is_index() {
            256
        } else {
            16
        };

        let size_checks = self.data.len() > threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn should_merge(&self) -> bool {
        let threshold = if cfg!(any(test, feature = "lock_free_delays")) {
            1
        } else if self.data.is_index() {
            64
        } else {
            4
        };

        let size_checks = self.data.len() < threshold;
        let safety_checks = self.merging_child.is_none() && !self.merging;

        size_checks && safety_checks
    }

    pub(crate) fn can_merge_child(&self) -> bool {
        self.merging_child.is_none() && !self.merging
    }

    pub(crate) fn index_next_node(&self, key: &[u8]) -> (usize, PageId) {
        let records = self
            .data
            .index_ref()
            .expect("index_next_node called on leaf");

        let common_prefix = key
            .iter()
            .zip(self.lo.iter())
            .take(u8::max_value() as usize)
            .take_while(|(a, b)| a == b)
            .count() as u8;

        let search = binary_search_lub(records, |&(ref k, ref _v)| {
            if k[0] > common_prefix {
                Ordering::Less
            } else if k[0] < common_prefix {
                Ordering::Greater
            } else {
                k[1..].cmp(&key[common_prefix as usize..])
            }
        });

        let index = search.expect("failed to traverse index");

        (index, records[index].1)
    }
}
<|endoftext|>


<commit_before>use super::NodeId;
use super::MutableNode;

pub struct Node<T> {
    data: T,
    parent: Option<NodeId>,
    children: Vec<NodeId>
}

impl<T> Node<T> {
    pub fn new(data: T) -> Node<T> {
        Node::new_with_child_capacity(data, 0)
    }

    //todo: make a NodeBuilder for this kind of thing
    pub fn new_with_child_capacity(data: T, capacity: usize) -> Node<T> {
        Node {
            data: data,
            parent: None,
            children: Vec::with_capacity(capacity)
        }
    }

    pub fn data(&self) -> &T {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut T {
        &mut self.data
    }

    pub fn parent(&self) -> Option<NodeId> {
        self.parent
    }

    pub fn children(&self) -> &Vec<NodeId> {
        &self.children
    }
}

impl<T> MutableNode for Node<T> {
    fn set_parent(&mut self, parent: Option<NodeId>) {
        self.parent = parent;
    }

    fn add_child(&mut self, child: NodeId) {
        self.children.push(child);
    }

    fn children_mut(&mut self) -> &mut Vec<NodeId> {
        &mut self.children
    }
}

#[cfg(test)]
mod node_tests {
    use super::Node;
    use super::super::NodeId;
    use super::super::snowflake::ProcessUniqueId;
    use super::super::MutableNode;

    #[test]
    fn test_new() {
        let node = Node::new(5);
        assert_eq!(node.children.capacity(), 0);
    }

    #[test]
    fn test_new_with_capacity() {
        let node = Node::new_with_child_capacity(5, 10);
        assert_eq!(node.children.capacity(), 10);
    }

    #[test]
    fn test_data() {
        let five = 5;
        let node = Node::new(five);
        assert_eq!(node.data(), &five);
    }

    #[test]
    fn test_data_mut() {
        let mut five = 5;
        let mut node = Node::new(five);
        assert_eq!(node.data_mut(), &mut five);
    }

    #[test]
    fn test_parent() {
        let node = Node::new(5);
        assert!(node.parent().is_none());

        let parent_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0
        };
        let mut node = Node::new(5);
        node.set_parent(Some(parent_id));

        assert_eq!(node.parent(), Some(parent_id))
    }

    #[test]
    fn test_children() {
        let node = Node::new(5);
        assert_eq!(node.children().len(), 0);

        let tree_id = ProcessUniqueId::new();

        let mut node = Node::new(5);
        let child_id: NodeId = NodeId {
            tree_id: tree_id,
            index: 2
        };
        node.add_child(child_id);
        let children = node.children();

        assert_eq!(children.len(), 1);
        assert_eq!(children.get(0).unwrap(), &child_id);

        let mut node = Node::new(5);
        let child_id: NodeId = NodeId {
            tree_id: tree_id,
            index: 2
        };
        node.children_mut().push(child_id);
        let children = node.children();

        assert_eq!(children.len(), 1);
        assert_eq!(children.get(0).unwrap(), &child_id);
    }
}
<commit_msg>clean up the node module a bit.<commit_after>use super::NodeId;
use super::MutableNode;

pub struct Node<T> {
    data: T,
    parent: Option<NodeId>,
    children: Vec<NodeId>,
}

impl<T> Node<T> {
    pub fn new(data: T) -> Node<T> {
        Node::new_with_child_capacity(data, 0)
    }

    //todo: make a NodeBuilder for this kind of thing
    pub fn new_with_child_capacity(data: T, capacity: usize) -> Node<T> {
        Node {
            data: data,
            parent: None,
            children: Vec::with_capacity(capacity),
        }
    }

    pub fn data(&self) -> &T {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut T {
        &mut self.data
    }

    pub fn parent(&self) -> Option<NodeId> {
        self.parent
    }

    pub fn children(&self) -> &Vec<NodeId> {
        &self.children
    }
}

impl<T> MutableNode for Node<T> {
    fn set_parent(&mut self, parent: Option<NodeId>) {
        self.parent = parent;
    }

    fn add_child(&mut self, child: NodeId) {
        self.children.push(child);
    }

    fn children_mut(&mut self) -> &mut Vec<NodeId> {
        &mut self.children
    }
}

#[cfg(test)]
mod node_tests {
    use super::Node;
    use super::super::NodeId;
    use super::super::snowflake::ProcessUniqueId;
    use super::super::MutableNode;

    #[test]
    fn test_new() {
        let node = Node::new(5);
        assert_eq!(node.children.capacity(), 0);
    }

    #[test]
    fn test_new_with_capacity() {
        let node = Node::new_with_child_capacity(5, 10);
        assert_eq!(node.children.capacity(), 10);
    }

    #[test]
    fn test_data() {
        let five = 5;
        let node = Node::new(five);
        assert_eq!(node.data(), &five);
    }

    #[test]
    fn test_data_mut() {
        let mut five = 5;
        let mut node = Node::new(five);
        assert_eq!(node.data_mut(), &mut five);
    }

    #[test]
    fn test_parent() {
        let mut node = Node::new(5);
        assert!(node.parent().is_none());

        let parent_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };

        node.set_parent(Some(parent_id));
        assert_eq!(node.parent(), Some(parent_id));
    }

    #[test]
    fn test_children() {
        let mut node = Node::new(5);
        assert_eq!(node.children().len(), 0);

        let child_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };
        node.add_child(child_id);

        assert_eq!(node.children().len(), 1);
        assert_eq!(node.children().get(0).unwrap(), &child_id);

        let mut node = Node::new(5);
        assert_eq!(node.children().len(), 0);

        let child_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };
        node.children_mut().push(child_id);

        assert_eq!(node.children().len(), 1);
        assert_eq!(node.children().get(0).unwrap(), &child_id);
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![allow(ctypes)]

extern crate core;

use core::iter::Iterator;
use core::str::StrExt;
use core::option::Option;

use core::kinds::Copy;

impl Copy for Color {}

enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

struct IntRange {
    cur: int,
    max: int
}

impl IntRange {
    fn next(&mut self) -> Option<int> {
        if self.cur < self.max {
            self.cur += 1;
            Option::Some(self.cur - 1)
        } else {
            Option::None
        }
    }
}

fn range(lo: int, hi: int) -> IntRange {
    IntRange { cur: lo, max: hi }
}

fn clear_screen(background: Color) {
    let mut r = range(0, 80 * 25);
    loop {
        match r.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + x * 2) as *mut u16) = (background as u16) << 12;
                }
            },
            Option::None =>{break}
        }
    }
}

fn print_string(string: &str) {
    let mut bytes = string.bytes();
    let mut count = 0;
    loop {
        match bytes.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + count) as *mut u8) = x;
                    *((0xb8000 + count + 1) as *mut u8) = 0x0f;
                }
                count = count + 2;
            },
            Option::None =>{break}
        }
    }
}

#[no_mangle]
#[no_split_stack]
pub fn main() {
    clear_screen(Color::LightRed);
    print_string("Hello world");
}
<commit_msg>Move cursor using inline assembly<commit_after>#![no_std]
#![allow(ctypes)]
#![feature(asm)]

extern crate core;

use core::iter::Iterator;
use core::str::StrExt;
use core::option::Option;

use core::marker::Copy;

impl Copy for Color {}

enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

struct IntRange {
    cur: int,
    max: int
}

impl IntRange {
    fn next(&mut self) -> Option<int> {
        if self.cur < self.max {
            self.cur += 1;
            Option::Some(self.cur - 1)
        } else {
            Option::None
        }
    }
}

fn range(lo: int, hi: int) -> IntRange {
    IntRange { cur: lo, max: hi }
}

fn clear_screen(background: Color) {
    let mut r = range(0, 80 * 25);
    loop {
        match r.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + x * 2) as *mut u16) = (background as u16) << 12;
                }
            },
            Option::None =>{break}
        }
    }
}

fn print_string(string: &str) {
    let mut bytes = string.bytes();
    let mut count = 0;
    loop {
        match bytes.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + count) as *mut u8) = x;
                    *((0xb8000 + count + 1) as *mut u8) = 0x0f;
                }
                count = count + 2;
            },
            Option::None =>{break}
        }
    }
}

fn move_cursor(row: u8, col: u8) {
    let pos = row*80 + col;
    outb(0x3D4,15);
    outb(0x3D5,pos);
    outb(0x3D4,14);
    outb(0x3D5,pos);
}

fn outb(port:u16, value:u8) {
    unsafe {
        asm!(
        "out $0,$1"
        :
        : "{ax}"(value), "{dx}"(port)
        :
        :
        )
    }
}

#[no_mangle]
#[no_split_stack]
pub fn main() {
    clear_screen(Color::LightRed);
    move_cursor(0,0);
    print_string("Hello world");
}
<|endoftext|>


<commit_before>#[crate_id = "vm#0.0"];
#[crate_type = "bin"];
#[feature(managed_boxes, macro_rules, globs)];
extern mod extra;
use std::hashmap::HashMap;
use std::rc::Rc;
use std::path::Path;
use std::io::File;
use std::str::{from_utf8};
use typecheck::TypeEnvironment;
use compiler::{Compiler, Assembly,
    Instruction, Add, Sub, Multiply, Divide, Remainder, Push, PushGlobal, PushInt, Mkap, Eval, Unwind, Update, Pop, Slide,
    SuperCombinator};
use parser::Parser;

mod compiler;
mod typecheck;
mod lexer;
mod parser;
mod module;
mod graph;

struct Scope<'a, T> {
    variables: HashMap<~str, T>,
    parent: Option<&'a Scope<'a, T>>
}

impl <'a, T> Scope<'a, T> {

    fn new() -> Scope<T> {
        Scope { variables : HashMap::new(), parent : None }
    }

    fn insert(&mut self, identifier : ~str, value : T) {
        self.variables.insert(identifier, value);
    }

    fn find(&'a self, identifier : &str) -> Option<&'a T> {
       match self.variables.find_equiv(&identifier) {
            Some(var) => Some(var),
            None => match self.parent {
                Some(parent) => parent.find(identifier),
                None => None
            }
       }
    }

    fn child(&'a self) -> Scope<'a, T> {
        Scope { variables : HashMap::new(), parent : Some(self) }
    }
}

#[deriving(Clone)]
enum Node<'a> {
    Application(Rc<Node<'a>>, Rc<Node<'a>>),
    Int(int),
    Combinator(&'a SuperCombinator),
    Indirection(Rc<Node<'a>>)
}

struct VM<'a> {
    assembly : Assembly,
    heap : ~[Node<'a>]
}

impl <'a> VM<'a> {
    fn new() -> VM {
        VM { assembly : Assembly { superCombinators : ~[] }, heap : ~[] }
    }

    fn evaluate(&'a self, code: &[Instruction]) -> Node<'a> {
        let mut stack = ~[];
        self.execute(&mut stack, code);
        static evalCode : &'static [Instruction] = &[Eval];
        self.execute(&mut stack, evalCode);
        assert_eq!(stack.len(), 1);
        stack[0].borrow().clone()
    }

    fn execute(&'a self, stack : &mut ~[Rc<Node<'a>>], code : &[Instruction]) {
        debug!("----------------------------");
        debug!("Entering frame with stack");
        for x in stack.iter() {
            debug!("{:?}", x.borrow());
        }
        let mut i = 0;
        while i < code.len() {
            debug!("Executing instruction : {:?}", code[i]);
            match &code[i] {
                &Add => primitive(stack, |l, r| { l + r }),
                &Sub => primitive(stack, |l, r| { l - r }),
                &Multiply => primitive(stack, |l, r| { l * r }),
                &Divide => primitive(stack, |l, r| { l / r }),
                &Remainder => primitive(stack, |l, r| { l % r }),
                &PushInt(value) => { stack.push(Rc::new(Int(value))); }
                &Push(index) => {
                    let x = stack[index].clone();
                    stack.push(x);
                }
                &PushGlobal(index) => {
                    match &self.assembly.superCombinators[index] {
                        &(_, ref sc) => stack.push(Rc::new(Combinator(sc)))
                    }
                }
                &Mkap => {
                    let func = stack.pop();
                    let arg = stack.pop();
                    debug!("Mkap {:?} {:?}", func.borrow(), arg.borrow());
                    stack.push(Rc::new(Application(func, arg)));
                }
                &Eval => {
                    static unwindCode : &'static [Instruction] = &[Unwind];
                    let mut newStack = ~[stack.pop()];
                    self.execute(&mut newStack, unwindCode);
                    assert_eq!(newStack.len(), 1);
                    stack.push(newStack.pop());
                }
                &Pop(num) => {
                    for _ in range(0, num) {
                        stack.pop();
                    }
                }
                &Update(index) => {
                    stack[index] = Rc::new(Indirection(stack[stack.len() - 1].clone()));
                }
                &Unwind => {
                    match (*stack[stack.len() - 1].borrow()).clone() {
                        Application(func, _) => {
                            stack.push(func);
                            i -= 1;//Redo the unwind instruction
                        }
                        Combinator(comb_ptr) => {
                            let comb = comb_ptr;
                            for j in range(stack.len() - (comb.arity as uint) - 1, stack.len() - 1) {
                                stack[j] = match stack[j].borrow() {
                                    &Application(_, ref arg) => arg.clone(),
                                    _ => fail!("Expected Application")
                                };
                            }
                            let mut newStack = ~[];
                            for i in range(0, comb.arity as uint) {
                                let index = stack.len() - comb.arity as uint + i - 1;
                                newStack.push(stack[index].clone());
                            }
                            self.execute(&mut newStack, comb.instructions);
                            assert_eq!(newStack.len(), 1);
                            for _ in range(0, comb.arity + 1) {
                                stack.pop();
                            }
                            stack.push(newStack.pop());
                        }
                        Indirection(node) => stack[stack.len() - 1] = node,
                        Int(_) => ()
                    }
                }
                &Slide(size) => {
                    for _ in range(0, size) {
                        stack.pop();
                    }
                }
                undefined => fail!("Use of undefined instruction {:?}", undefined)
            }
            i += 1;
        }
        debug!("End frame");
        debug!("--------------------------");
    }
}

fn primitive(stack: &mut ~[Rc<Node>], f: |int, int| -> int) {
    let l = stack.pop();
    let r = stack.pop();
    match (l.borrow(), r.borrow()) {
        (&Int(lhs), &Int(rhs)) => stack.push(Rc::new(Int(f(lhs, rhs)))),
        (lhs, rhs) => fail!("Expected fully evaluted numbers in primitive instruction\n LHS: {:?}\nRHS: {:?} ", lhs, rhs)
    }
}

fn main() {
    let arguments = std::os::args();
    match arguments {
        [_, expr_str] => {
            let mut parser = Parser::new(expr_str.chars());
            let mut expr = parser.expression_();

            let mut type_env = TypeEnvironment::new();
            type_env.typecheck(&mut expr);

            let mut compiler = Compiler::new();
            let instr = compiler.compileExpression(&expr);

            let vm = VM::new();
            let mut stack = ~[];
            vm.execute(&mut stack, instr);
            println!("{:?}", stack[0].borrow());
        }
        [_, ~"-l", filename] => {
            let path = &Path::new(filename);
            let s  = File::open(path).read_to_end();
            let contents : &str = from_utf8(s);

            let mut parser = Parser::new(contents.chars());
            let module = parser.module();

            let mut compiler = Compiler::new();
            let mut vm = VM::new();
            vm.assembly = compiler.compileModule(&module);
            let x = vm.assembly.superCombinators.iter().find(|& &(ref name, _)| *name == ~"main");
            match x {
                Some(&(_, ref sc)) => {
                    assert!(sc.arity == 0);
                    let result = vm.evaluate(sc.instructions);
                    println!("{:?}", result);
                }
                None => ()
            }
        }
        _ => return println!("Expected one argument which is the expression or 2 arguments where the first is -l and the second the file to run (needs a main function)")
    }
}

#[test]
fn test()
{
    format!("{:?}", main);
}
<commit_msg>Implemented the new instructions needed for case expressions<commit_after>#[crate_id = "vm#0.0"];
#[crate_type = "bin"];
#[feature(managed_boxes, macro_rules, globs)];
extern mod extra;
use std::hashmap::HashMap;
use std::rc::Rc;
use std::path::Path;
use std::vec;
use std::io::File;
use std::str::{from_utf8};
use typecheck::TypeEnvironment;
use compiler::{Compiler, Assembly,
    Instruction, Add, Sub, Multiply, Divide, Remainder, Push, PushGlobal, PushInt, Mkap, Eval, Unwind, Update, Pop, Slide, Split, Pack, CaseJump, Jump,
    SuperCombinator};
use parser::Parser;

mod compiler;
mod typecheck;
mod lexer;
mod parser;
mod module;
mod graph;

struct Scope<'a, T> {
    variables: HashMap<~str, T>,
    parent: Option<&'a Scope<'a, T>>
}

impl <'a, T> Scope<'a, T> {

    fn new() -> Scope<T> {
        Scope { variables : HashMap::new(), parent : None }
    }

    fn insert(&mut self, identifier : ~str, value : T) {
        self.variables.insert(identifier, value);
    }

    fn find(&'a self, identifier : &str) -> Option<&'a T> {
       match self.variables.find_equiv(&identifier) {
            Some(var) => Some(var),
            None => match self.parent {
                Some(parent) => parent.find(identifier),
                None => None
            }
       }
    }

    fn child(&'a self) -> Scope<'a, T> {
        Scope { variables : HashMap::new(), parent : Some(self) }
    }
}

#[deriving(Clone)]
enum Node<'a> {
    Application(Rc<Node<'a>>, Rc<Node<'a>>),
    Int(int),
    Combinator(&'a SuperCombinator),
    Indirection(Rc<Node<'a>>),
    Constructor(u16, ~[Rc<Node<'a>>])
}

struct VM<'a> {
    assembly : Assembly,
    heap : ~[Node<'a>]
}

impl <'a> VM<'a> {
    fn new() -> VM {
        VM { assembly : Assembly { superCombinators : ~[] }, heap : ~[] }
    }

    fn evaluate(&'a self, code: &[Instruction]) -> Node<'a> {
        let mut stack = ~[];
        self.execute(&mut stack, code);
        static evalCode : &'static [Instruction] = &[Eval];
        self.execute(&mut stack, evalCode);
        assert_eq!(stack.len(), 1);
        stack[0].borrow().clone()
    }

    fn execute(&'a self, stack : &mut ~[Rc<Node<'a>>], code : &[Instruction]) {
        debug!("----------------------------");
        debug!("Entering frame with stack");
        for x in stack.iter() {
            debug!("{:?}", x.borrow());
        }
        let mut i = 0;
        while i < code.len() {
            debug!("Executing instruction : {:?}", code[i]);
            match &code[i] {
                &Add => primitive(stack, |l, r| { l + r }),
                &Sub => primitive(stack, |l, r| { l - r }),
                &Multiply => primitive(stack, |l, r| { l * r }),
                &Divide => primitive(stack, |l, r| { l / r }),
                &Remainder => primitive(stack, |l, r| { l % r }),
                &PushInt(value) => { stack.push(Rc::new(Int(value))); }
                &Push(index) => {
                    let x = stack[index].clone();
                    debug!("Pushed {:?}", x.borrow());
                    debug!("Stack {:?} {:?}", stack[0].borrow(), stack[1].borrow());
                    stack.push(x);
                }
                &PushGlobal(index) => {
                    match &self.assembly.superCombinators[index] {
                        &(_, ref sc) => stack.push(Rc::new(Combinator(sc)))
                    }
                }
                &Mkap => {
                    let func = stack.pop();
                    let arg = stack.pop();
                    debug!("Mkap {:?} {:?}", func.borrow(), arg.borrow());
                    stack.push(Rc::new(Application(func, arg)));
                }
                &Eval => {
                    static unwindCode : &'static [Instruction] = &[Unwind];
                    let mut newStack = ~[stack.pop()];
                    self.execute(&mut newStack, unwindCode);
                    assert_eq!(newStack.len(), 1);
                    stack.push(newStack.pop());
                }
                &Pop(num) => {
                    for _ in range(0, num) {
                        stack.pop();
                    }
                }
                &Update(index) => {
                    stack[index] = Rc::new(Indirection(stack[stack.len() - 1].clone()));
                }
                &Unwind => {
                    match (*stack[stack.len() - 1].borrow()).clone() {
                        Application(func, _) => {
                            stack.push(func);
                            i -= 1;//Redo the unwind instruction
                        }
                        Combinator(comb_ptr) => {
                            let comb = comb_ptr;
                            for j in range(stack.len() - (comb.arity as uint) - 1, stack.len() - 1) {
                                stack[j] = match stack[j].borrow() {
                                    &Application(_, ref arg) => arg.clone(),
                                    _ => fail!("Expected Application")
                                };
                            }
                            let mut newStack = ~[];
                            for i in range(0, comb.arity as uint) {
                                let index = stack.len() - comb.arity as uint + i - 1;
                                newStack.push(stack[index].clone());
                            }
                            self.execute(&mut newStack, comb.instructions);
                            assert_eq!(newStack.len(), 1);
                            for _ in range(0, comb.arity + 1) {
                                stack.pop();
                            }
                            stack.push(newStack.pop());
                        }
                        Indirection(node) => stack[stack.len() - 1] = node,
                        _ => ()
                    }
                }
                &Slide(size) => {
                    let top = stack.pop();
                    for _ in range(0, size) {
                        stack.pop();
                    }
                    stack.push(top);
                }
                &Split(size) => {
                    let x = stack.pop();
                    match x.borrow() {
                        &Constructor(_, ref fields) => {
                            for field in fields.iter() {
                                stack.push(field.clone());
                            }
                        }
                        _ => fail!("Expected constructor in Split instruction")
                    }
                }
                &Pack(tag, arity) => {
                    let args = std::vec::from_fn(arity as uint, |_| stack.pop());
                    stack.push(Rc::new(Constructor(tag, args)));
                }
                &CaseJump(jump_tag) => {
                    match stack[stack.len() - 1].borrow() {
                        &Constructor(tag, _) => {
                            if jump_tag != tag as uint {
                                i += 1;//Skip the jump instruction
                            }
                        }
                        _ => fail!("Expected constructor when executing CaseJump")
                    }
                }
                &Jump(to) => {
                    i = to - 1;
                }
                //undefined => fail!("Use of undefined instruction {:?}", undefined)
            }
            i += 1;
        }
        debug!("End frame");
        debug!("--------------------------");
    }
}

fn primitive(stack: &mut ~[Rc<Node>], f: |int, int| -> int) {
    let l = stack.pop();
    let r = stack.pop();
    match (l.borrow(), r.borrow()) {
        (&Int(lhs), &Int(rhs)) => stack.push(Rc::new(Int(f(lhs, rhs)))),
        (lhs, rhs) => fail!("Expected fully evaluted numbers in primitive instruction\n LHS: {:?}\nRHS: {:?} ", lhs, rhs)
    }
}

fn main() {
    let arguments = std::os::args();
    match arguments {
        [_, expr_str] => {
            let mut parser = Parser::new(expr_str.chars());
            let mut expr = parser.expression_();

            let mut type_env = TypeEnvironment::new();
            type_env.typecheck(&mut expr);

            let mut compiler = Compiler::new();
            let instr = compiler.compileExpression(&expr);

            let vm = VM::new();
            let mut stack = ~[];
            vm.execute(&mut stack, instr);
            println!("{:?}", stack[0].borrow());
        }
        [_, ~"-l", filename] => {
            let path = &Path::new(filename);
            let s  = File::open(path).read_to_end();
            let contents : &str = from_utf8(s);

            let mut parser = Parser::new(contents.chars());
            let module = parser.module();

            let mut compiler = Compiler::new();
            let mut vm = VM::new();
            vm.assembly = compiler.compileModule(&module);
            let x = vm.assembly.superCombinators.iter().find(|& &(ref name, _)| *name == ~"main");
            match x {
                Some(&(_, ref sc)) => {
                    assert!(sc.arity == 0);
                    let result = vm.evaluate(sc.instructions);
                    println!("{:?}", result);
                }
                None => ()
            }
        }
        _ => return println!("Expected one argument which is the expression or 2 arguments where the first is -l and the second the file to run (needs a main function)")
    }
}

#[test]
fn test()
{
    format!("{:?}", main);
}
<|endoftext|>


<commit_before>#[crate_id = "vm#0.0"];
#[crate_type = "bin"];
#[feature(managed_boxes, macro_rules, globs)];
extern mod extra;
use std::rc::Rc;
use std::path::Path;
use std::io::File;
use std::str::{from_utf8};
use compiler::{Compiler,
    Instruction, Add, Sub, Multiply, Divide, Remainder, Push, PushGlobal, PushInt, Mkap, Eval, Unwind, Update, Pop, Slide,
    SuperCombinator};
use parser::Parser;

mod compiler;
mod typecheck;
mod lexer;
mod parser;

#[deriving(Clone)]
enum Node {
    Application(Rc<Node>, Rc<Node>),
    Int(int),
    Combinator(Rc<SuperCombinator>),
    Indirection(Rc<Node>)
}

struct VM {
    globals : ~[Rc<SuperCombinator>],
    heap : ~[Node]
}

impl VM {
    fn new() -> VM {
        VM { globals : ~[], heap : ~[] }
    }
    fn execute(&self, stack : &mut ~[Rc<Node>], code : &[Instruction]) {
        debug!("Entering frame");
        let mut i = 0;
        while i < code.len() {
            println!("Executing instruction : {:?}", code[i]);
            match &code[i] {
                &Add => primitive(stack, |l, r| { l + r }),
                &Sub => primitive(stack, |l, r| { l - r }),
                &Multiply => primitive(stack, |l, r| { l * r }),
                &Divide => primitive(stack, |l, r| { l / r }),
                &Remainder => primitive(stack, |l, r| { l % r }),
                &PushInt(value) => { stack.push(Rc::new(Int(value))); }
                &Push(index) => {
                    let x = stack[index].clone();
                    stack.push(x);
                }
                &PushGlobal(index) => {
                    stack.push(Rc::new(Combinator(self.globals[index].clone())));
                }
                &Mkap => {
                    let func = stack.pop();
                    let arg = stack.pop();
                    stack.push(Rc::new(Application(func, arg)));
                }
                &Eval => {
                    static unwindCode : &'static [Instruction] = &[Unwind];
                    let mut newStack = ~[stack.pop()];
                    self.execute(&mut newStack, unwindCode);
                    assert!(newStack.len() == 1);
                    stack.push(newStack.pop());
                }
                &Pop(num) => {
                    for _ in range(0, num) {
                        stack.pop();
                    }
                }
                &Update(index) => {
                    stack[index] = Rc::new(Indirection(stack[stack.len() - 1].clone()));
                }
                &Unwind => {
                    match (*stack[stack.len() - 1].borrow()).clone() {
                        Application(func, _) => {
                            stack.push(func);
                            i -= 1;//Redo the unwind instruction
                        }
                        Combinator(comb_ptr) => {
                            let comb = comb_ptr.borrow();
                            for j in range(stack.len() - (comb.arity as uint) - 1, stack.len()) {
                                stack[j] = match stack[j].borrow() {
                                    &Application(_, ref arg) => arg.clone(),
                                    _ => fail!("Expected Application")
                                };
                            }
                            let mut newStack = ~[stack[stack.len() - 1].clone()];
                            self.execute(&mut newStack, comb.instructions);
                            assert!(newStack.len() == 0);
                            for _ in range(0, comb.arity) {
                                stack.pop();
                            }
                            stack.push(newStack.pop());
                        }
                        Indirection(node) => stack[stack.len() - 1] = node,
                        Int(_) => ()
                    }
                }
                &Slide(size) => {
                    for _ in range(0, size) {
                        stack.pop();
                    }
                }
            }
            i += 1;
        }
    }
}

fn primitive(stack: &mut ~[Rc<Node>], f: |int, int| -> int) {
    let l = stack.pop();
    let r = stack.pop();
    match (l.borrow(), r.borrow()) {
        (&Int(lhs), &Int(rhs)) => stack.push(Rc::new(Int(f(lhs, rhs)))),
        _ => fail!("Expected fully evaluted numbers in Add instruction")
    }
}

fn main() {
    let arguments = std::os::args();
    if arguments.len() == 2 {
        let mut parser = Parser::new(arguments[1].chars());
        let expr = parser.expression_();

        let mut compiler = Compiler::new();
        let instr = compiler.compileExpression(&expr);

        let vm = VM::new();
        let mut stack = ~[];
        vm.execute(&mut stack, instr);
        println!("{:?}", stack[0].borrow());
    }
    else if arguments.len() == 3 {
        let arg = arguments[2];
        let path = &Path::new(arg);
        let s  = File::open(path).read_to_end();
        let contents : &str = from_utf8(s);

        let mut parser = Parser::new(contents.chars());
        let module = parser.module();

        let mut compiler = Compiler::new();
        compiler.compileModule(&module);
    }
    else {
        return println!("Expected one argument which is the expression or 2 arguments where the first is -l and the second the file to run (needs a main function)");
    }
}

#[test]
fn test()
{
    format!("{:?}", main);
}
<commit_msg>Use pattern matching when parsing command line arguments<commit_after>#[crate_id = "vm#0.0"];
#[crate_type = "bin"];
#[feature(managed_boxes, macro_rules, globs)];
extern mod extra;
use std::rc::Rc;
use std::path::Path;
use std::io::File;
use std::str::{from_utf8};
use compiler::{Compiler,
    Instruction, Add, Sub, Multiply, Divide, Remainder, Push, PushGlobal, PushInt, Mkap, Eval, Unwind, Update, Pop, Slide,
    SuperCombinator};
use parser::Parser;

mod compiler;
mod typecheck;
mod lexer;
mod parser;

#[deriving(Clone)]
enum Node {
    Application(Rc<Node>, Rc<Node>),
    Int(int),
    Combinator(Rc<SuperCombinator>),
    Indirection(Rc<Node>)
}

struct VM {
    globals : ~[Rc<SuperCombinator>],
    heap : ~[Node]
}

impl VM {
    fn new() -> VM {
        VM { globals : ~[], heap : ~[] }
    }
    fn execute(&self, stack : &mut ~[Rc<Node>], code : &[Instruction]) {
        debug!("Entering frame");
        let mut i = 0;
        while i < code.len() {
            println!("Executing instruction : {:?}", code[i]);
            match &code[i] {
                &Add => primitive(stack, |l, r| { l + r }),
                &Sub => primitive(stack, |l, r| { l - r }),
                &Multiply => primitive(stack, |l, r| { l * r }),
                &Divide => primitive(stack, |l, r| { l / r }),
                &Remainder => primitive(stack, |l, r| { l % r }),
                &PushInt(value) => { stack.push(Rc::new(Int(value))); }
                &Push(index) => {
                    let x = stack[index].clone();
                    stack.push(x);
                }
                &PushGlobal(index) => {
                    stack.push(Rc::new(Combinator(self.globals[index].clone())));
                }
                &Mkap => {
                    let func = stack.pop();
                    let arg = stack.pop();
                    stack.push(Rc::new(Application(func, arg)));
                }
                &Eval => {
                    static unwindCode : &'static [Instruction] = &[Unwind];
                    let mut newStack = ~[stack.pop()];
                    self.execute(&mut newStack, unwindCode);
                    assert!(newStack.len() == 1);
                    stack.push(newStack.pop());
                }
                &Pop(num) => {
                    for _ in range(0, num) {
                        stack.pop();
                    }
                }
                &Update(index) => {
                    stack[index] = Rc::new(Indirection(stack[stack.len() - 1].clone()));
                }
                &Unwind => {
                    match (*stack[stack.len() - 1].borrow()).clone() {
                        Application(func, _) => {
                            stack.push(func);
                            i -= 1;//Redo the unwind instruction
                        }
                        Combinator(comb_ptr) => {
                            let comb = comb_ptr.borrow();
                            for j in range(stack.len() - (comb.arity as uint) - 1, stack.len()) {
                                stack[j] = match stack[j].borrow() {
                                    &Application(_, ref arg) => arg.clone(),
                                    _ => fail!("Expected Application")
                                };
                            }
                            let mut newStack = ~[stack[stack.len() - 1].clone()];
                            self.execute(&mut newStack, comb.instructions);
                            assert!(newStack.len() == 0);
                            for _ in range(0, comb.arity) {
                                stack.pop();
                            }
                            stack.push(newStack.pop());
                        }
                        Indirection(node) => stack[stack.len() - 1] = node,
                        Int(_) => ()
                    }
                }
                &Slide(size) => {
                    for _ in range(0, size) {
                        stack.pop();
                    }
                }
            }
            i += 1;
        }
    }
}

fn primitive(stack: &mut ~[Rc<Node>], f: |int, int| -> int) {
    let l = stack.pop();
    let r = stack.pop();
    match (l.borrow(), r.borrow()) {
        (&Int(lhs), &Int(rhs)) => stack.push(Rc::new(Int(f(lhs, rhs)))),
        _ => fail!("Expected fully evaluted numbers in Add instruction")
    }
}

fn main() {
    let arguments = std::os::args();
    match arguments {
        [_, expr_str] => {
            let mut parser = Parser::new(expr_str.chars());
            let expr = parser.expression_();

            let mut compiler = Compiler::new();
            let instr = compiler.compileExpression(&expr);

            let vm = VM::new();
            let mut stack = ~[];
            vm.execute(&mut stack, instr);
            println!("{:?}", stack[0].borrow());
        }
        [_, ~"-l", filename] => {
            let path = &Path::new(filename);
            let s  = File::open(path).read_to_end();
            let contents : &str = from_utf8(s);

            let mut parser = Parser::new(contents.chars());
            let module = parser.module();

            let mut compiler = Compiler::new();
            compiler.compileModule(&module);
        }
        _ => return println!("Expected one argument which is the expression or 2 arguments where the first is -l and the second the file to run (needs a main function)")
    }
}

#[test]
fn test()
{
    format!("{:?}", main);
}
<|endoftext|>


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

//! Communication with the compositor task.

use compositor;
use euclid::{Point2D, Size2D};
use headless;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use layers::layers::{BufferRequest, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerProperties};
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState};
use profile_traits::mem;
use profile_traits::time;
use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender, channel};
use style_traits::viewport::ViewportConstraints;
use url::Url;
use util::cursor::Cursor;
use windowing::{WindowEvent, WindowMethods};
pub use constellation::SendableFrameTree;
pub use windowing;

/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
/// process, and so forth.
pub trait CompositorProxy : 'static + Send {
    /// Sends a message to the compositor.
    fn send(&self, msg: Msg);
    /// Clones the compositor proxy.
    fn clone_compositor_proxy(&self) -> Box<CompositorProxy + 'static + Send>;
}

/// The port that the compositor receives messages on. As above, this is a trait supplied by the
/// Servo port.
pub trait CompositorReceiver : 'static {
    /// Receives the next message inbound for the compositor. This must not block.
    fn try_recv_compositor_msg(&mut self) -> Option<Msg>;
    /// Synchronously waits for, and returns, the next message inbound for the compositor.
    fn recv_compositor_msg(&mut self) -> Msg;
}

/// A convenience implementation of `CompositorReceiver` for a plain old Rust `Receiver`.
impl CompositorReceiver for Receiver<Msg> {
    fn try_recv_compositor_msg(&mut self) -> Option<Msg> {
        match self.try_recv() {
            Ok(msg) => Some(msg),
            Err(_) => None,
        }
    }
    fn recv_compositor_msg(&mut self) -> Msg {
        self.recv().unwrap()
    }
}

pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'static + Send>,
                                  receiver: IpcReceiver<ScriptToCompositorMsg>) {
    while let Ok(msg) = receiver.recv() {
        match msg {
            ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
                compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
                                                               layer_id,
                                                               point,
                                                               _smooth));
            }

            ScriptToCompositorMsg::GetClientWindow(send) => {
                compositor_proxy.send(Msg::GetClientWindow(send));
            }

            ScriptToCompositorMsg::MoveTo(point) => {
                compositor_proxy.send(Msg::MoveTo(point));
            }

            ScriptToCompositorMsg::ResizeTo(size) => {
                compositor_proxy.send(Msg::ResizeTo(size));
            }

            ScriptToCompositorMsg::Exit => {
                let (chan, port) = channel();
                compositor_proxy.send(Msg::Exit(chan));
                port.recv().unwrap();
            }

            ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
                compositor_proxy.send(Msg::ChangePageTitle(pipeline_id, title))
            }

            ScriptToCompositorMsg::SendKeyEvent(key, key_state, key_modifiers) => {
                compositor_proxy.send(Msg::KeyEvent(key, key_state, key_modifiers))
            }

            ScriptToCompositorMsg::TouchEventProcessed(result) => {
                compositor_proxy.send(Msg::TouchEventProcessed(result))
            }
        }
    }
}

/// Implementation of the abstract `PaintListener` interface.
impl PaintListener for Box<CompositorProxy + 'static + Send> {
    fn native_display(&mut self) -> Option<NativeDisplay> {
        let (chan, port) = channel();
        self.send(Msg::GetNativeDisplay(chan));
        // If the compositor is shutting down when a paint task
        // is being created, the compositor won't respond to
        // this message, resulting in an eventual panic. Instead,
        // just return None in this case, since the paint task
        // will exit shortly and never actually be requested
        // to paint buffers by the compositor.
        port.recv().unwrap_or(None)
    }

    fn assign_painted_buffers(&mut self,
                              pipeline_id: PipelineId,
                              epoch: Epoch,
                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
                              frame_tree_id: FrameTreeId) {
        self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
    }

    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
        let mut native_surfaces = Vec::new();
        for request in buffer_requests.into_iter() {
            if let Some(native_surface) = request.native_surface {
                native_surfaces.push(native_surface);
            }
        }
        if !native_surfaces.is_empty() {
            self.send(Msg::ReturnUnusedNativeSurfaces(native_surfaces));
        }
    }

    fn initialize_layers_for_pipeline(&mut self,
                                      pipeline_id: PipelineId,
                                      properties: Vec<LayerProperties>,
                                      epoch: Epoch) {
        // FIXME(#2004, pcwalton): This assumes that the first layer determines the page size, and
        // that all other layers are immediate children of it. This is sufficient to handle
        // `position: fixed` but will not be sufficient to handle `overflow: scroll` or transforms.
        self.send(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties));
    }

    fn notify_paint_task_exiting(&mut self, pipeline_id: PipelineId) {
        self.send(Msg::PaintTaskExited(pipeline_id))
    }
}

/// Messages from the painting task and the constellation task to the compositor task.
pub enum Msg {
    /// Requests that the compositor shut down.
    Exit(Sender<()>),

    /// Informs the compositor that the constellation has completed shutdown.
    /// Required because the constellation can have pending calls to make
    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
    ShutdownComplete,

    /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs
    /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
    /// is the pixel format.
    ///
    /// The headless compositor returns `None`.
    GetNativeDisplay(Sender<Option<NativeDisplay>>),

    /// Tells the compositor to create or update the layers for a pipeline if necessary
    /// (i.e. if no layer with that ID exists).
    InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
    /// Scroll a page in a window
    ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
    /// Requests that the compositor assign the painted buffers to the given layers.
    AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
    /// Alerts the compositor that the current page has changed its title.
    ChangePageTitle(PipelineId, Option<String>),
    /// Alerts the compositor that the current page has changed its URL.
    ChangePageUrl(PipelineId, Url),
    /// Alerts the compositor that the given pipeline has changed whether it is running animations.
    ChangeRunningAnimationsState(PipelineId, AnimationState),
    /// Replaces the current frame tree, typically called during main frame navigation.
    SetFrameTree(SendableFrameTree, Sender<()>, ConstellationChan),
    /// The load of a page has begun: (can go back, can go forward).
    LoadStart(bool, bool),
    /// The load of a page has completed: (can go back, can go forward).
    LoadComplete(bool, bool),
    /// Indicates that the scrolling timeout with the given starting timestamp has happened and a
    /// composite should happen. (See the `scrolling` module.)
    ScrollTimeout(u64),
    RecompositeAfterScroll,
    /// Sends an unconsumed key event back to the compositor.
    KeyEvent(Key, KeyState, KeyModifiers),
    /// Script has handled a touch event, and either prevented or allowed default actions.
    TouchEventProcessed(EventResult),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// Composite to a PNG file and return the Image over a passed channel.
    CreatePng(IpcSender<Option<Image>>),
    /// Informs the compositor that the paint task for the given pipeline has exited.
    PaintTaskExited(PipelineId),
    /// Alerts the compositor that the viewport has been constrained in some manner
    ViewportConstrained(PipelineId, ViewportConstraints),
    /// A reply to the compositor asking if the output image is stable.
    IsReadyToSaveImageReply(bool),
    /// A favicon was detected
    NewFavicon(Url),
    /// <head> tag finished parsing
    HeadParsed,
    /// Signal that the paint task ignored the paint requests that carried
    /// these native surfaces, so that they can be re-added to the surface cache.
    ReturnUnusedNativeSurfaces(Vec<NativeSurface>),
    /// Collect memory reports and send them back to the given mem::ReportsChan.
    CollectMemoryReports(mem::ReportsChan),
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Get Window Informations size and position
    GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
    /// Move the window to a point
    MoveTo(Point2D<i32>),
    /// Resize the window to size
    ResizeTo(Size2D<u32>),
    /// A pipeline was shut down.
    PipelineExited(PipelineId),
}

impl Debug for Msg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Msg::Exit(..) => write!(f, "Exit"),
            Msg::ShutdownComplete(..) => write!(f, "ShutdownComplete"),
            Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
            Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
            Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
            Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
            Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
            Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"),
            Msg::SetFrameTree(..) => write!(f, "SetFrameTree"),
            Msg::LoadComplete(..) => write!(f, "LoadComplete"),
            Msg::LoadStart(..) => write!(f, "LoadStart"),
            Msg::ScrollTimeout(..) => write!(f, "ScrollTimeout"),
            Msg::RecompositeAfterScroll => write!(f, "RecompositeAfterScroll"),
            Msg::KeyEvent(..) => write!(f, "KeyEvent"),
            Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
            Msg::SetCursor(..) => write!(f, "SetCursor"),
            Msg::CreatePng(..) => write!(f, "CreatePng"),
            Msg::PaintTaskExited(..) => write!(f, "PaintTaskExited"),
            Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"),
            Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
            Msg::NewFavicon(..) => write!(f, "NewFavicon"),
            Msg::HeadParsed => write!(f, "HeadParsed"),
            Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
            Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
            Msg::Status(..) => write!(f, "Status"),
            Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
            Msg::MoveTo(..) => write!(f, "MoveTo"),
            Msg::ResizeTo(..) => write!(f, "ResizeTo"),
            Msg::PipelineExited(..) => write!(f, "PipelineExited"),
        }
    }
}

pub struct CompositorTask;

impl CompositorTask {
    pub fn create<Window>(window: Option<Rc<Window>>,
                          state: InitialCompositorState)
                          -> Box<CompositorEventListener + 'static>
                          where Window: WindowMethods + 'static {
        match window {
            Some(window) => {
                box compositor::IOCompositor::create(window, state)
                    as Box<CompositorEventListener>
            }
            None => {
                box headless::NullCompositor::create(state)
                    as Box<CompositorEventListener>
            }
        }
    }
}

pub trait CompositorEventListener {
    fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool;
    fn repaint_synchronously(&mut self);
    fn pinch_zoom_level(&self) -> f32;
    /// Requests that the compositor send the title for the main frame as soon as possible.
    fn title_for_main_frame(&self);
}

/// Data used to construct a compositor.
pub struct InitialCompositorState {
    /// A channel to the compositor.
    pub sender: Box<CompositorProxy + Send>,
    /// A port on which messages inbound to the compositor can be received.
    pub receiver: Box<CompositorReceiver>,
    /// A channel to the constellation.
    pub constellation_chan: ConstellationChan,
    /// A channel to the time profiler thread.
    pub time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler thread.
    pub mem_profiler_chan: mem::ProfilerChan,
}
<commit_msg>Use Result::ok in CompositorReceiver<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Communication with the compositor task.

use compositor;
use euclid::{Point2D, Size2D};
use headless;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use layers::layers::{BufferRequest, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerProperties};
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState};
use profile_traits::mem;
use profile_traits::time;
use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender, channel};
use style_traits::viewport::ViewportConstraints;
use url::Url;
use util::cursor::Cursor;
use windowing::{WindowEvent, WindowMethods};
pub use constellation::SendableFrameTree;
pub use windowing;

/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
/// process, and so forth.
pub trait CompositorProxy : 'static + Send {
    /// Sends a message to the compositor.
    fn send(&self, msg: Msg);
    /// Clones the compositor proxy.
    fn clone_compositor_proxy(&self) -> Box<CompositorProxy + 'static + Send>;
}

/// The port that the compositor receives messages on. As above, this is a trait supplied by the
/// Servo port.
pub trait CompositorReceiver : 'static {
    /// Receives the next message inbound for the compositor. This must not block.
    fn try_recv_compositor_msg(&mut self) -> Option<Msg>;
    /// Synchronously waits for, and returns, the next message inbound for the compositor.
    fn recv_compositor_msg(&mut self) -> Msg;
}

/// A convenience implementation of `CompositorReceiver` for a plain old Rust `Receiver`.
impl CompositorReceiver for Receiver<Msg> {
    fn try_recv_compositor_msg(&mut self) -> Option<Msg> {
        self.try_recv().ok()
    }
    fn recv_compositor_msg(&mut self) -> Msg {
        self.recv().unwrap()
    }
}

pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'static + Send>,
                                  receiver: IpcReceiver<ScriptToCompositorMsg>) {
    while let Ok(msg) = receiver.recv() {
        match msg {
            ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
                compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
                                                               layer_id,
                                                               point,
                                                               _smooth));
            }

            ScriptToCompositorMsg::GetClientWindow(send) => {
                compositor_proxy.send(Msg::GetClientWindow(send));
            }

            ScriptToCompositorMsg::MoveTo(point) => {
                compositor_proxy.send(Msg::MoveTo(point));
            }

            ScriptToCompositorMsg::ResizeTo(size) => {
                compositor_proxy.send(Msg::ResizeTo(size));
            }

            ScriptToCompositorMsg::Exit => {
                let (chan, port) = channel();
                compositor_proxy.send(Msg::Exit(chan));
                port.recv().unwrap();
            }

            ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
                compositor_proxy.send(Msg::ChangePageTitle(pipeline_id, title))
            }

            ScriptToCompositorMsg::SendKeyEvent(key, key_state, key_modifiers) => {
                compositor_proxy.send(Msg::KeyEvent(key, key_state, key_modifiers))
            }

            ScriptToCompositorMsg::TouchEventProcessed(result) => {
                compositor_proxy.send(Msg::TouchEventProcessed(result))
            }
        }
    }
}

/// Implementation of the abstract `PaintListener` interface.
impl PaintListener for Box<CompositorProxy + 'static + Send> {
    fn native_display(&mut self) -> Option<NativeDisplay> {
        let (chan, port) = channel();
        self.send(Msg::GetNativeDisplay(chan));
        // If the compositor is shutting down when a paint task
        // is being created, the compositor won't respond to
        // this message, resulting in an eventual panic. Instead,
        // just return None in this case, since the paint task
        // will exit shortly and never actually be requested
        // to paint buffers by the compositor.
        port.recv().unwrap_or(None)
    }

    fn assign_painted_buffers(&mut self,
                              pipeline_id: PipelineId,
                              epoch: Epoch,
                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
                              frame_tree_id: FrameTreeId) {
        self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
    }

    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
        let mut native_surfaces = Vec::new();
        for request in buffer_requests.into_iter() {
            if let Some(native_surface) = request.native_surface {
                native_surfaces.push(native_surface);
            }
        }
        if !native_surfaces.is_empty() {
            self.send(Msg::ReturnUnusedNativeSurfaces(native_surfaces));
        }
    }

    fn initialize_layers_for_pipeline(&mut self,
                                      pipeline_id: PipelineId,
                                      properties: Vec<LayerProperties>,
                                      epoch: Epoch) {
        // FIXME(#2004, pcwalton): This assumes that the first layer determines the page size, and
        // that all other layers are immediate children of it. This is sufficient to handle
        // `position: fixed` but will not be sufficient to handle `overflow: scroll` or transforms.
        self.send(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties));
    }

    fn notify_paint_task_exiting(&mut self, pipeline_id: PipelineId) {
        self.send(Msg::PaintTaskExited(pipeline_id))
    }
}

/// Messages from the painting task and the constellation task to the compositor task.
pub enum Msg {
    /// Requests that the compositor shut down.
    Exit(Sender<()>),

    /// Informs the compositor that the constellation has completed shutdown.
    /// Required because the constellation can have pending calls to make
    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
    ShutdownComplete,

    /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs
    /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
    /// is the pixel format.
    ///
    /// The headless compositor returns `None`.
    GetNativeDisplay(Sender<Option<NativeDisplay>>),

    /// Tells the compositor to create or update the layers for a pipeline if necessary
    /// (i.e. if no layer with that ID exists).
    InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
    /// Scroll a page in a window
    ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
    /// Requests that the compositor assign the painted buffers to the given layers.
    AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
    /// Alerts the compositor that the current page has changed its title.
    ChangePageTitle(PipelineId, Option<String>),
    /// Alerts the compositor that the current page has changed its URL.
    ChangePageUrl(PipelineId, Url),
    /// Alerts the compositor that the given pipeline has changed whether it is running animations.
    ChangeRunningAnimationsState(PipelineId, AnimationState),
    /// Replaces the current frame tree, typically called during main frame navigation.
    SetFrameTree(SendableFrameTree, Sender<()>, ConstellationChan),
    /// The load of a page has begun: (can go back, can go forward).
    LoadStart(bool, bool),
    /// The load of a page has completed: (can go back, can go forward).
    LoadComplete(bool, bool),
    /// Indicates that the scrolling timeout with the given starting timestamp has happened and a
    /// composite should happen. (See the `scrolling` module.)
    ScrollTimeout(u64),
    RecompositeAfterScroll,
    /// Sends an unconsumed key event back to the compositor.
    KeyEvent(Key, KeyState, KeyModifiers),
    /// Script has handled a touch event, and either prevented or allowed default actions.
    TouchEventProcessed(EventResult),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// Composite to a PNG file and return the Image over a passed channel.
    CreatePng(IpcSender<Option<Image>>),
    /// Informs the compositor that the paint task for the given pipeline has exited.
    PaintTaskExited(PipelineId),
    /// Alerts the compositor that the viewport has been constrained in some manner
    ViewportConstrained(PipelineId, ViewportConstraints),
    /// A reply to the compositor asking if the output image is stable.
    IsReadyToSaveImageReply(bool),
    /// A favicon was detected
    NewFavicon(Url),
    /// <head> tag finished parsing
    HeadParsed,
    /// Signal that the paint task ignored the paint requests that carried
    /// these native surfaces, so that they can be re-added to the surface cache.
    ReturnUnusedNativeSurfaces(Vec<NativeSurface>),
    /// Collect memory reports and send them back to the given mem::ReportsChan.
    CollectMemoryReports(mem::ReportsChan),
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Get Window Informations size and position
    GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
    /// Move the window to a point
    MoveTo(Point2D<i32>),
    /// Resize the window to size
    ResizeTo(Size2D<u32>),
    /// A pipeline was shut down.
    PipelineExited(PipelineId),
}

impl Debug for Msg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Msg::Exit(..) => write!(f, "Exit"),
            Msg::ShutdownComplete(..) => write!(f, "ShutdownComplete"),
            Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
            Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
            Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
            Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
            Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
            Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"),
            Msg::SetFrameTree(..) => write!(f, "SetFrameTree"),
            Msg::LoadComplete(..) => write!(f, "LoadComplete"),
            Msg::LoadStart(..) => write!(f, "LoadStart"),
            Msg::ScrollTimeout(..) => write!(f, "ScrollTimeout"),
            Msg::RecompositeAfterScroll => write!(f, "RecompositeAfterScroll"),
            Msg::KeyEvent(..) => write!(f, "KeyEvent"),
            Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
            Msg::SetCursor(..) => write!(f, "SetCursor"),
            Msg::CreatePng(..) => write!(f, "CreatePng"),
            Msg::PaintTaskExited(..) => write!(f, "PaintTaskExited"),
            Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"),
            Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
            Msg::NewFavicon(..) => write!(f, "NewFavicon"),
            Msg::HeadParsed => write!(f, "HeadParsed"),
            Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
            Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
            Msg::Status(..) => write!(f, "Status"),
            Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
            Msg::MoveTo(..) => write!(f, "MoveTo"),
            Msg::ResizeTo(..) => write!(f, "ResizeTo"),
            Msg::PipelineExited(..) => write!(f, "PipelineExited"),
        }
    }
}

pub struct CompositorTask;

impl CompositorTask {
    pub fn create<Window>(window: Option<Rc<Window>>,
                          state: InitialCompositorState)
                          -> Box<CompositorEventListener + 'static>
                          where Window: WindowMethods + 'static {
        match window {
            Some(window) => {
                box compositor::IOCompositor::create(window, state)
                    as Box<CompositorEventListener>
            }
            None => {
                box headless::NullCompositor::create(state)
                    as Box<CompositorEventListener>
            }
        }
    }
}

pub trait CompositorEventListener {
    fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool;
    fn repaint_synchronously(&mut self);
    fn pinch_zoom_level(&self) -> f32;
    /// Requests that the compositor send the title for the main frame as soon as possible.
    fn title_for_main_frame(&self);
}

/// Data used to construct a compositor.
pub struct InitialCompositorState {
    /// A channel to the compositor.
    pub sender: Box<CompositorProxy + Send>,
    /// A port on which messages inbound to the compositor can be received.
    pub receiver: Box<CompositorReceiver>,
    /// A channel to the constellation.
    pub constellation_chan: ConstellationChan,
    /// A channel to the time profiler thread.
    pub time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler thread.
    pub mem_profiler_chan: mem::ProfilerChan,
}
<|endoftext|>