<commit_before>use prolog::ast::*;
use prolog::machine::machine_errors::*;
use prolog::machine::machine_state::*;
use prolog::num::{ToPrimitive, Zero};
use prolog::num::bigint::BigInt;

use std::rc::Rc;

struct BrentAlgState {
    hare: usize,
    tortoise: usize,
    power: usize,
    steps: usize
}

impl BrentAlgState {
    fn new(hare: usize) -> Self {
        BrentAlgState { hare, tortoise: hare, power: 2, steps: 1 }
    }
}

impl MachineState {
    // a step in Brent's algorithm.
    fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
    {
        match self.heap[brent_st.hare].clone() {
            HeapCellValue::Addr(Addr::Lis(l)) => {
                brent_st.hare = l + 1;
                brent_st.steps += 1;

                if brent_st.tortoise == brent_st.hare {
                    return Some(CycleSearchResult::NotList);
                } else if brent_st.steps == brent_st.power {
                    brent_st.tortoise = brent_st.hare;
                    brent_st.power <<= 1;
                }

                None
            },
            HeapCellValue::NamedStr(..) =>
                Some(CycleSearchResult::NotList),
            HeapCellValue::Addr(addr) =>
                match self.store(self.deref(addr)) {
                    Addr::Con(Constant::EmptyList) =>
                        Some(CycleSearchResult::ProperList(brent_st.steps)),
                    Addr::HeapCell(_) | Addr::StackCell(..) =>
                        Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)),
                    _ =>
                        Some(CycleSearchResult::NotList)
                }
        }
    }

    pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult
    {
        let addr = self.store(self.deref(addr));
        let hare = match addr {
            Addr::Lis(offset) if max_steps > 0 => offset + 1,
            Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
            Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
            _ => return CycleSearchResult::NotList
        };

        let mut brent_st = BrentAlgState::new(hare);

        loop {
            if brent_st.steps == max_steps {
                return CycleSearchResult::PartialList(brent_st.steps, brent_st.hare);
            }

            if let Some(result) = self.brents_alg_step(&mut brent_st) {
                return result;
            }
        }
    }

    pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult
    {
        let addr = self.store(self.deref(addr));
        let hare = match addr {
            Addr::Lis(offset) => offset + 1,
            Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
            _ => return CycleSearchResult::NotList
        };

        let mut brent_st = BrentAlgState::new(hare);

        loop {
            if let Some(result) = self.brents_alg_step(&mut brent_st) {
                return result;
            }
        }
    }

    fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) {
        let target_n = self[temp_v!(1)].clone();
        self.unify(Addr::Con(integer!(n)), target_n);

        if !self.fail {
            let xs = self[temp_v!(4)].clone();
            self.unify(addr, xs);
        }
    }

    pub(super) fn skip_max_list(&mut self) -> Result<(), MachineError> {
        let max_steps = self.store(self.deref(self[temp_v!(2)].clone()));

        match max_steps {
            Addr::Con(Constant::Number(Number::Integer(ref max_steps)))
                if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) => {
                    let n = self.store(self.deref(self[temp_v!(1)].clone()));

                    match n {
                        Addr::Con(Constant::Number(Number::Integer(ref n))) if n.is_zero() => {
                            let xs0 = self[temp_v!(3)].clone();
                            let xs  = self[temp_v!(4)].clone();

                            self.unify(xs0, xs);
                        },
                        _ => {
                            let search_result = if let Some(max_steps) = max_steps.to_isize() {
                                if max_steps == -1 {
                                    self.detect_cycles(self[temp_v!(3)].clone())
                                } else {
                                    self.detect_cycles_with_max(max_steps as usize,
                                                                self[temp_v!(3)].clone())
                                }
                            } else {
                                self.detect_cycles(self[temp_v!(3)].clone())
                            };

                            match search_result {
                                CycleSearchResult::UntouchedList(l) =>
                                    self.finalize_skip_max_list(0, Addr::Lis(l)),
                                CycleSearchResult::EmptyList =>
                                    self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)),
                                CycleSearchResult::PartialList(n, hc) =>
                                    self.finalize_skip_max_list(n, Addr::HeapCell(hc)),
                                CycleSearchResult::ProperList(n) =>
                                    self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)),
                                CycleSearchResult::NotList => {
                                    let xs0 = self[temp_v!(3)].clone();
                                    self.finalize_skip_max_list(0, xs0);
                                }
                            }
                        }
                    }
                },
            _ => self.fail = true
        };

        Ok(())
    }

    fn install_new_block(&mut self, r: RegType) -> usize {
        self.block = self.b;

        let c = Constant::Usize(self.block);
        let addr = self[r].clone();

        self.write_constant_to_var(addr, c);
        self.block
    }

    pub(super) fn system_call(&mut self, ct: &SystemClauseType,
                              call_policy: &mut Box<CallPolicy>,
                              cut_policy:  &mut Box<CutPolicy>,)
                              -> CallResult
    {
        match ct {
            &SystemClauseType::CheckCutPoint => {
                let addr = self.store(self.deref(self[temp_v!(1)].clone()));

                match addr {
                    Addr::Con(Constant::Usize(old_b)) if self.b <= old_b + 2 => {},
                    _ => self.fail = true
                };
            },
            &SystemClauseType::GetSCCCleaner => {
                let dest = self[temp_v!(1)].clone();

                match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
                    Some(sgc_policy) =>
                        if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() {
                            if self.b <= b_cutoff + 1 {
                                self.block = prev_b;

                                if let Some(r) = dest.as_var() {
                                    self.bind(r, addr.clone());
                                    return Ok(());
                                }
                            } else {
                                sgc_policy.push_cont_pt(addr, b_cutoff, prev_b);
                            }
                        },
                    None => panic!("expected SCCCutPolicy trait object.")
                };

                self.fail = true;
            },
            &SystemClauseType::InstallSCCCleaner => {
                let addr = self[temp_v!(1)].clone();
                let b = self.b;
                let prev_block = self.block;

                if cut_policy.downcast_ref::<SCCCutPolicy>().is_err() {
                    *cut_policy = Box::new(SCCCutPolicy::new());
                }

                match cut_policy.downcast_mut::<SCCCutPolicy>().ok()
                {
                    Some(cut_policy) => {
                        self.install_new_block(temp_v!(2));
                        cut_policy.push_cont_pt(addr, b, prev_block);
                    },
                    None => panic!("install_cleaner: should have installed \\
                                    SCCCutPolicy.")
                };
            },
            &SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L
                let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
                let a2 = self.store(self.deref(self[temp_v!(2)].clone()));

                if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
                    CallWithInferenceLimitCallPolicy::new_in_place(call_policy);
                }

                match (a1, a2.clone()) {
                    (Addr::Con(Constant::Usize(bp)),
                     Addr::Con(Constant::Number(Number::Integer(n)))) =>
                        match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
                            Some(call_policy) => {
                                let count = call_policy.add_limit(n, bp);
                                self[temp_v!(3)] = Addr::Con(Constant::Number(Number::Integer(count)));
                            },
                            None => panic!("install_inference_counter: should have installed \\
                                            CallWithInferenceLimitCallPolicy.")
                        },
                    _ => {
                        let stub = self.functor_stub(clause_name!("call_with_inference_limit"), 3);
                        let type_error = self.error_form(self.type_error(ValidType::Integer, a2),
                                                         stub);
                        self.throw_exception(type_error)
                    }
                };
            },
            &SystemClauseType::RemoveCallPolicyCheck => {
                let restore_default =
                    match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
                        Some(call_policy) => {
                            let a1 = self.store(self.deref(self[temp_v!(1)].clone()));

                            if let Addr::Con(Constant::Usize(bp)) = a1 {
                                if call_policy.is_empty() && bp == self.b {
                                    Some(call_policy.into_inner())
                                } else {
                                    None
                                }
                            } else {
                                panic!("remove_call_policy_check: expected Usize in A1.");
                            }
                        },
                        None => panic!("remove_call_policy_check: requires \\
                                        CallWithInferenceLimitCallPolicy.")
                    };

                if let Some(new_policy) = restore_default {
                    *call_policy = new_policy;
                }
            },
            &SystemClauseType::RemoveInferenceCounter => {
                match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
                    Some(call_policy) => {
                        let a1 = self.store(self.deref(self[temp_v!(1)].clone()));

                        if let Addr::Con(Constant::Usize(bp)) = a1 {
                            let count = call_policy.remove_limit(bp);
                            self[temp_v!(2)] = Addr::Con(Constant::Number(Number::Integer(count)));
                        } else {
                            panic!("remove_inference_counter: expected Usize in A1.");
                        }
                    },
                    None => panic!("remove_inference_counters: requires \\
                                    CallWithInferenceLimitCallPolicy.")
                };
            },
            &SystemClauseType::RestoreCutPolicy => {
                let restore_default =
                    if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
                        cut_policy.out_of_cont_pts()
                    } else {
                        false
                    };

                if restore_default {
                    *cut_policy = Box::new(DefaultCutPolicy {});
                }
            },
            &SystemClauseType::SetCutPoint(r) =>
                cut_policy.cut(self, r),
            &SystemClauseType::InferenceLevel => {
                let a1 = self[temp_v!(1)].clone();
                let a2 = self.store(self.deref(self[temp_v!(2)].clone()));

                match a2 {
                    Addr::Con(Constant::Usize(bp)) =>
                        if self.b <= bp + 1 {
                            let a2 = Addr::Con(atom!("!"));
                            self.unify(a1, a2);
                        } else {
                            let a2 = Addr::Con(atom!("true"));
                            self.unify(a1, a2);
                        },
                    _ => self.fail = true
                };
            },
            &SystemClauseType::CleanUpBlock => {
                let nb = self.store(self.deref(self[temp_v!(1)].clone()));

                match nb {
                    Addr::Con(Constant::Usize(nb)) => {
                        let b = self.b - 1;

                        if nb > 0 && self.or_stack[b].b == nb {
                            self.b = self.or_stack[nb - 1].b;
                            self.or_stack.truncate(self.b);
                        }
                    },
                    _ => self.fail = true
                };
            },
            &SystemClauseType::EraseBall => self.ball.reset(),
            &SystemClauseType::Fail => self.fail = true,
            &SystemClauseType::GetBall => {
                let addr = self.store(self.deref(self[temp_v!(1)].clone()));
                let h = self.heap.h;

                if self.ball.stub.len() > 0 {
                    self.copy_and_align_ball_to_heap();
                } else {
                    self.fail = true;
                    return Ok(());
                }

                let ball = self.heap[h].as_addr(h);

                match addr.as_var() {
                    Some(r) => self.bind(r, ball),
                    _ => self.fail = true
                };
            },
            &SystemClauseType::GetCurrentBlock => {
                let c = Constant::Usize(self.block);
                let addr = self[temp_v!(1)].clone();

                self.write_constant_to_var(addr, c);
            },
            &SystemClauseType::GetCutPoint => {
                let a1 = self[temp_v!(1)].clone();
                let a2 = Addr::Con(Constant::Usize(self.b));

                self.unify(a1, a2);
            },
            &SystemClauseType::InstallNewBlock => {
                self.install_new_block(temp_v!(1));
            },
            &SystemClauseType::ResetBlock => {
                let addr = self.deref(self[temp_v!(1)].clone());
                self.reset_block(addr);
            },
            &SystemClauseType::SetBall => self.set_ball(),
            &SystemClauseType::SkipMaxList => return self.skip_max_list(),
            &SystemClauseType::Succeed => {},
            &SystemClauseType::UnwindStack => self.unwind_stack()
        };

        Ok(())
    }
}
<commit_msg>add instantiation error to skip_max_list<commit_after>use prolog::ast::*;
use prolog::machine::machine_errors::*;
use prolog::machine::machine_state::*;
use prolog::num::{ToPrimitive, Zero};
use prolog::num::bigint::BigInt;

use std::rc::Rc;

struct BrentAlgState {
    hare: usize,
    tortoise: usize,
    power: usize,
    steps: usize
}

impl BrentAlgState {
    fn new(hare: usize) -> Self {
        BrentAlgState { hare, tortoise: hare, power: 2, steps: 1 }
    }
}

impl MachineState {
    // a step in Brent's algorithm.
    fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
    {
        match self.heap[brent_st.hare].clone() {
            HeapCellValue::Addr(Addr::Lis(l)) => {
                brent_st.hare = l + 1;
                brent_st.steps += 1;

                if brent_st.tortoise == brent_st.hare {
                    return Some(CycleSearchResult::NotList);
                } else if brent_st.steps == brent_st.power {
                    brent_st.tortoise = brent_st.hare;
                    brent_st.power <<= 1;
                }

                None
            },
            HeapCellValue::NamedStr(..) =>
                Some(CycleSearchResult::NotList),
            HeapCellValue::Addr(addr) =>
                match self.store(self.deref(addr)) {
                    Addr::Con(Constant::EmptyList) =>
                        Some(CycleSearchResult::ProperList(brent_st.steps)),
                    Addr::HeapCell(_) | Addr::StackCell(..) =>
                        Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)),
                    _ =>
                        Some(CycleSearchResult::NotList)
                }
        }
    }

    pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult
    {
        let addr = self.store(self.deref(addr));
        let hare = match addr {
            Addr::Lis(offset) if max_steps > 0 => offset + 1,
            Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
            Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
            _ => return CycleSearchResult::NotList
        };

        let mut brent_st = BrentAlgState::new(hare);

        loop {
            if brent_st.steps == max_steps {
                return CycleSearchResult::PartialList(brent_st.steps, brent_st.hare);
            }

            if let Some(result) = self.brents_alg_step(&mut brent_st) {
                return result;
            }
        }
    }

    pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult
    {
        let addr = self.store(self.deref(addr));
        let hare = match addr {
            Addr::Lis(offset) => offset + 1,
            Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
            _ => return CycleSearchResult::NotList
        };

        let mut brent_st = BrentAlgState::new(hare);

        loop {
            if let Some(result) = self.brents_alg_step(&mut brent_st) {
                return result;
            }
        }
    }

    fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) {
        let target_n = self[temp_v!(1)].clone();
        self.unify(Addr::Con(integer!(n)), target_n);

        if !self.fail {
            let xs = self[temp_v!(4)].clone();
            self.unify(addr, xs);
        }
    }

    pub(super) fn skip_max_list(&mut self) -> Result<(), MachineError> {
        let max_steps = self.store(self.deref(self[temp_v!(2)].clone()));

        match max_steps {
            Addr::Con(Constant::Number(Number::Integer(ref max_steps))) =>
                if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) {
                    let n = self.store(self.deref(self[temp_v!(1)].clone()));

                    match n {
                        Addr::Con(Constant::Number(Number::Integer(ref n))) if n.is_zero() => {
                            let xs0 = self[temp_v!(3)].clone();
                            let xs  = self[temp_v!(4)].clone();

                            self.unify(xs0, xs);
                        },
                        _ => {
                            let search_result = if let Some(max_steps) = max_steps.to_isize() {
                                if max_steps == -1 {
                                    self.detect_cycles(self[temp_v!(3)].clone())
                                } else {
                                    self.detect_cycles_with_max(max_steps as usize,
                                                                self[temp_v!(3)].clone())
                                }
                            } else {
                                self.detect_cycles(self[temp_v!(3)].clone())
                            };

                            match search_result {
                                CycleSearchResult::UntouchedList(l) =>
                                    self.finalize_skip_max_list(0, Addr::Lis(l)),
                                CycleSearchResult::EmptyList =>
                                    self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)),
                                CycleSearchResult::PartialList(n, hc) =>
                                    self.finalize_skip_max_list(n, Addr::HeapCell(hc)),
                                CycleSearchResult::ProperList(n) =>
                                    self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)),
                                CycleSearchResult::NotList => {
                                    let xs0 = self[temp_v!(3)].clone();
                                    self.finalize_skip_max_list(0, xs0);
                                }
                            }
                        }
                    }
                } else {
                    self.fail = true;
                },
            _ => {
                let stub = self.functor_stub(clause_name!("$skip_max_list"), 4);
                return Err(self.error_form(self.instantiation_error(), stub));
            }
        };

        Ok(())
    }

    fn install_new_block(&mut self, r: RegType) -> usize {
        self.block = self.b;

        let c = Constant::Usize(self.block);
        let addr = self[r].clone();

        self.write_constant_to_var(addr, c);
        self.block
    }

    pub(super) fn system_call(&mut self, ct: &SystemClauseType,
                              call_policy: &mut Box<CallPolicy>,
                              cut_policy:  &mut Box<CutPolicy>,)
                              -> CallResult
    {
        match ct {
            &SystemClauseType::CheckCutPoint => {
                let addr = self.store(self.deref(self[temp_v!(1)].clone()));

                match addr {
                    Addr::Con(Constant::Usize(old_b)) if self.b <= old_b + 2 => {},
                    _ => self.fail = true
                };
            },
            &SystemClauseType::GetSCCCleaner => {
                let dest = self[temp_v!(1)].clone();

                match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
                    Some(sgc_policy) =>
                        if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() {
                            if self.b <= b_cutoff + 1 {
                                self.block = prev_b;

                                if let Some(r) = dest.as_var() {
                                    self.bind(r, addr.clone());
                                    return Ok(());
                                }
                            } else {
                                sgc_policy.push_cont_pt(addr, b_cutoff, prev_b);
                            }
                        },
                    None => panic!("expected SCCCutPolicy trait object.")
                };

                self.fail = true;
            },
            &SystemClauseType::InstallSCCCleaner => {
                let addr = self[temp_v!(1)].clone();
                let b = self.b;
                let prev_block = self.block;

                if cut_policy.downcast_ref::<SCCCutPolicy>().is_err() {
                    *cut_policy = Box::new(SCCCutPolicy::new());
                }

                match cut_policy.downcast_mut::<SCCCutPolicy>().ok()
                {
                    Some(cut_policy) => {
                        self.install_new_block(temp_v!(2));
                        cut_policy.push_cont_pt(addr, b, prev_block);
                    },
                    None => panic!("install_cleaner: should have installed \\
                                    SCCCutPolicy.")
                };
            },
            &SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L
                let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
                let a2 = self.store(self.deref(self[temp_v!(2)].clone()));

                if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
                    CallWithInferenceLimitCallPolicy::new_in_place(call_policy);
                }

                match (a1, a2.clone()) {
                    (Addr::Con(Constant::Usize(bp)),
                     Addr::Con(Constant::Number(Number::Integer(n)))) =>
                        match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
                            Some(call_policy) => {
                                let count = call_policy.add_limit(n, bp);
                                self[temp_v!(3)] = Addr::Con(Constant::Number(Number::Integer(count)));
                            },
                            None => panic!("install_inference_counter: should have installed \\
                                            CallWithInferenceLimitCallPolicy.")
                        },
                    _ => {
                        let stub = self.functor_stub(clause_name!("call_with_inference_limit"), 3);
                        let type_error = self.error_form(self.type_error(ValidType::Integer, a2),
                                                         stub);
                        self.throw_exception(type_error)
                    }
                };
            },
            &SystemClauseType::RemoveCallPolicyCheck => {
                let restore_default =
                    match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
                        Some(call_policy) => {
                            let a1 = self.store(self.deref(self[temp_v!(1)].clone()));

                            if let Addr::Con(Constant::Usize(bp)) = a1 {
                                if call_policy.is_empty() && bp == self.b {
                                    Some(call_policy.into_inner())
                                } else {
                                    None
                                }
                            } else {
                                panic!("remove_call_policy_check: expected Usize in A1.");
                            }
                        },
                        None => panic!("remove_call_policy_check: requires \\
                                        CallWithInferenceLimitCallPolicy.")
                    };

                if let Some(new_policy) = restore_default {
                    *call_policy = new_policy;
                }
            },
            &SystemClauseType::RemoveInferenceCounter => {
                match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
                    Some(call_policy) => {
                        let a1 = self.store(self.deref(self[temp_v!(1)].clone()));

                        if let Addr::Con(Constant::Usize(bp)) = a1 {
                            let count = call_policy.remove_limit(bp);
                            self[temp_v!(2)] = Addr::Con(Constant::Number(Number::Integer(count)));
                        } else {
                            panic!("remove_inference_counter: expected Usize in A1.");
                        }
                    },
                    None => panic!("remove_inference_counters: requires \\
                                    CallWithInferenceLimitCallPolicy.")
                };
            },
            &SystemClauseType::RestoreCutPolicy => {
                let restore_default =
                    if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
                        cut_policy.out_of_cont_pts()
                    } else {
                        false
                    };

                if restore_default {
                    *cut_policy = Box::new(DefaultCutPolicy {});
                }
            },
            &SystemClauseType::SetCutPoint(r) =>
                cut_policy.cut(self, r),
            &SystemClauseType::InferenceLevel => {
                let a1 = self[temp_v!(1)].clone();
                let a2 = self.store(self.deref(self[temp_v!(2)].clone()));

                match a2 {
                    Addr::Con(Constant::Usize(bp)) =>
                        if self.b <= bp + 1 {
                            let a2 = Addr::Con(atom!("!"));
                            self.unify(a1, a2);
                        } else {
                            let a2 = Addr::Con(atom!("true"));
                            self.unify(a1, a2);
                        },
                    _ => self.fail = true
                };
            },
            &SystemClauseType::CleanUpBlock => {
                let nb = self.store(self.deref(self[temp_v!(1)].clone()));

                match nb {
                    Addr::Con(Constant::Usize(nb)) => {
                        let b = self.b - 1;

                        if nb > 0 && self.or_stack[b].b == nb {
                            self.b = self.or_stack[nb - 1].b;
                            self.or_stack.truncate(self.b);
                        }
                    },
                    _ => self.fail = true
                };
            },
            &SystemClauseType::EraseBall => self.ball.reset(),
            &SystemClauseType::Fail => self.fail = true,
            &SystemClauseType::GetBall => {
                let addr = self.store(self.deref(self[temp_v!(1)].clone()));
                let h = self.heap.h;

                if self.ball.stub.len() > 0 {
                    self.copy_and_align_ball_to_heap();
                } else {
                    self.fail = true;
                    return Ok(());
                }

                let ball = self.heap[h].as_addr(h);

                match addr.as_var() {
                    Some(r) => self.bind(r, ball),
                    _ => self.fail = true
                };
            },
            &SystemClauseType::GetCurrentBlock => {
                let c = Constant::Usize(self.block);
                let addr = self[temp_v!(1)].clone();

                self.write_constant_to_var(addr, c);
            },
            &SystemClauseType::GetCutPoint => {
                let a1 = self[temp_v!(1)].clone();
                let a2 = Addr::Con(Constant::Usize(self.b));

                self.unify(a1, a2);
            },
            &SystemClauseType::InstallNewBlock => {
                self.install_new_block(temp_v!(1));
            },
            &SystemClauseType::ResetBlock => {
                let addr = self.deref(self[temp_v!(1)].clone());
                self.reset_block(addr);
            },
            &SystemClauseType::SetBall => self.set_ball(),
            &SystemClauseType::SkipMaxList => return self.skip_max_list(),
            &SystemClauseType::Succeed => {},
            &SystemClauseType::UnwindStack => self.unwind_stack()
        };

        Ok(())
    }
}
<|endoftext|>


<commit_before>use num::Bounded;
use std::mem;

#[cfg(feature = "dim3")]
use na::Point2;
use na::{self, Real};

use bounding_volume::AABB;
use shape::{FeatureId, Segment};
use math::{Isometry, Vector, Point};
use query::{Ray, RayCast, RayIntersection};

impl<N: Real> RayCast<N> for AABB<N> {
    fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, solid: bool) -> Option<N> {
        let ls_ray = ray.inverse_transform_by(m);

        let mut tmin: N = na::zero();
        let mut tmax: N = Bounded::max_value();

        for i in 0usize..na::dimension::<Vector<N>>() {
            if ls_ray.dir[i].is_zero() {
                if ls_ray.origin[i] < self.mins()[i] || ls_ray.origin[i] > self.maxs()[i] {
                    return None;
                }
            } else {
                let _1: N = na::one();
                let denom = _1 / ls_ray.dir[i];
                let mut inter_with_near_plane = (self.mins()[i] - ls_ray.origin[i]) * denom;
                let mut inter_with_far_plane = (self.maxs()[i] - ls_ray.origin[i]) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }

                tmin = tmin.max(inter_with_near_plane);
                tmax = tmax.min(inter_with_far_plane);

                if tmin > tmax {
                    return None;
                }
            }
        }

        if tmin.is_zero() && !solid {
            Some(tmax)
        } else {
            Some(tmin)
        }
    }

    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(self, &ls_ray, solid).map(|(t, n, i)| {
            let feature = if i < 0 {
                FeatureId::Face(i as usize - 1 + 3)
            } else {
                FeatureId::Face(i as usize - 1)
            };

            RayIntersection::new(t, m * n, feature)
        })
    }

    #[cfg(feature = "dim3")]
    fn toi_and_normal_and_uv_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        do_toi_and_normal_and_uv_with_ray(m, self, ray, solid)
    }
}

impl<N: Real> AABB<N> {
    #[inline]
    pub fn clip_line_parameters(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<(N, N)> {
        clip_line(self, orig, dir).map(|clip| ((clip.0).0, (clip.1).0))
    }

    #[inline]
    pub fn clip_line(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<Segment<N>> {
        clip_line(self, orig, dir).map(|clip| {
            Segment::new(orig + dir * (clip.0).0, orig + dir * (clip.1).0)
        })
    }

    #[inline]
    pub fn clip_ray_parameters(&self, ray: &Ray<N>) -> Option<(N, N)> {
        match self.clip_line_parameters(&ray.origin, &ray.dir) {
            Some(clip) => {
                let t0 = clip.0;
                let t1 = clip.1;

                if t1 < N::zero() {
                    None
                } else {
                    Some((na::sup(&t0, &N::zero()), t1))
                }
            }
            None => None
        }
    }

    #[inline]
    pub fn clip_ray(&self, ray: &Ray<N>) -> Option<Segment<N>> {
        self.clip_ray_parameters(ray).map(|clip| {
            Segment::new(ray.point_at(clip.0), ray.point_at(clip.1))
        })
    }
}

#[cfg(feature = "dim3")]
fn do_toi_and_normal_and_uv_with_ray<N: Real>(
    m: &Isometry<N>,
    aabb: &AABB<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
{
    if na::dimension::<Vector<N>>() != 3 {
        aabb.toi_and_normal_with_ray(m, ray, solid)
    } else {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(aabb, &ls_ray, solid).map(|(t, n, s)| {
            let pt = ls_ray.origin + ls_ray.dir * t;
            let dpt = pt - *aabb.mins();
            let scale = *aabb.maxs() - *aabb.mins();
            let id = na::abs(&s);
            let gs_n = m * n;
            let feature = if s < 0 {
                FeatureId::Face(id as usize - 1 + 3)
            } else {
                FeatureId::Face(id as usize - 1)
            };

            if id == 1 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[1] / scale[1], dpt[2] / scale[2])),
                )
            } else if id == 2 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[2] / scale[2], dpt[0] / scale[0])),
                )
            } else {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[0] / scale[0], dpt[1] / scale[1])),
                )
            }
        })
    }
}

fn clip_line<N: Real>(aabb: &AABB<N>, origin: &Point<N>, dir: &Vector<N>) -> Option<((N, Vector<N>, isize), (N, Vector<N>, isize))> {
    let mut tmax: N = Bounded::max_value();
    let mut tmin: N = -tmax;
    let mut near_side = 0;
    let mut far_side = 0;
    let mut near_diag = false;
    let mut far_diag = false;

    for i in 0usize..na::dimension::<Vector<N>>() {
        if dir[i].is_zero() {
            if origin[i] < aabb.mins()[i] || origin[i] > aabb.maxs()[i] {
                return None;
            }
        } else {
            let _1: N = na::one();
            let denom = _1 / dir[i];
            let flip_sides;
            let mut inter_with_near_plane = (aabb.mins()[i] - origin[i]) * denom;
            let mut inter_with_far_plane = (aabb.maxs()[i] - origin[i]) * denom;

            if inter_with_near_plane > inter_with_far_plane {
                flip_sides = true;
                mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
            } else {
                flip_sides = false;
            }

            if inter_with_near_plane > tmin {
                tmin = inter_with_near_plane;
                near_side = if flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                near_diag = false;
            } else if inter_with_near_plane == tmin {
                near_diag = true;
            }

            if inter_with_far_plane < tmax {
                tmax = inter_with_far_plane;
                far_side = if !flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                far_diag = false;
            } else if inter_with_far_plane == tmax {
                far_diag = true;
            }

            if tmin > tmax {
                return None;
            }
        }
    }

    let near = if near_diag {
        (tmin, -dir.normalize(), near_side)
    } else {
        let mut normal = Vector::zeros();

        if near_side < 0 {
            normal[(-near_side - 1) as usize] = N::one();
        } else {
            normal[(near_side - 1) as usize] = -N::one();
        }

        (tmin, normal, near_side)
    };

    let far = if far_diag {
        (tmax, -dir.normalize(), far_side)
    } else {
        let mut normal = Vector::zeros();

        if far_side < 0 {
            normal[(-far_side - 1) as usize] = -N::one();
        } else {
            normal[(far_side - 1) as usize] = N::one();
        }

        (tmax, normal, far_side)
    };

    Some((near, far))
}

fn ray_aabb<N: Real>(aabb: &AABB<N>, ray: &Ray<N>, solid: bool) -> Option<(N, Vector<N>, isize)> {
    if let Some((near, far)) = clip_line(aabb, &ray.origin, &ray.dir) {
        if near.0 < N::zero() {
            if solid {
                Some((na::zero(), na::zero(), far.2))
            } else {
                Some(far)
            }
        } else {
            Some(near)
        }
    } else {
        None
    }
}<commit_msg>Fix AABB ray-cast feature ID.<commit_after>use num::Bounded;
use std::mem;

#[cfg(feature = "dim3")]
use na::Point2;
use na::{self, Real};

use bounding_volume::AABB;
use shape::{FeatureId, Segment};
use math::{Isometry, Vector, Point};
use query::{Ray, RayCast, RayIntersection};

impl<N: Real> RayCast<N> for AABB<N> {
    fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, solid: bool) -> Option<N> {
        let ls_ray = ray.inverse_transform_by(m);

        let mut tmin: N = na::zero();
        let mut tmax: N = Bounded::max_value();

        for i in 0usize..na::dimension::<Vector<N>>() {
            if ls_ray.dir[i].is_zero() {
                if ls_ray.origin[i] < self.mins()[i] || ls_ray.origin[i] > self.maxs()[i] {
                    return None;
                }
            } else {
                let _1: N = na::one();
                let denom = _1 / ls_ray.dir[i];
                let mut inter_with_near_plane = (self.mins()[i] - ls_ray.origin[i]) * denom;
                let mut inter_with_far_plane = (self.maxs()[i] - ls_ray.origin[i]) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }

                tmin = tmin.max(inter_with_near_plane);
                tmax = tmax.min(inter_with_far_plane);

                if tmin > tmax {
                    return None;
                }
            }
        }

        if tmin.is_zero() && !solid {
            Some(tmax)
        } else {
            Some(tmin)
        }
    }

    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(self, &ls_ray, solid).map(|(t, n, i)| {
            let feature = if i < 0 {
                FeatureId::Face(-i as usize - 1 + 3)
            } else {
                FeatureId::Face(i as usize - 1)
            };

            RayIntersection::new(t, m * n, feature)
        })
    }

    #[cfg(feature = "dim3")]
    fn toi_and_normal_and_uv_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        do_toi_and_normal_and_uv_with_ray(m, self, ray, solid)
    }
}

impl<N: Real> AABB<N> {
    #[inline]
    pub fn clip_line_parameters(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<(N, N)> {
        clip_line(self, orig, dir).map(|clip| ((clip.0).0, (clip.1).0))
    }

    #[inline]
    pub fn clip_line(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<Segment<N>> {
        clip_line(self, orig, dir).map(|clip| {
            Segment::new(orig + dir * (clip.0).0, orig + dir * (clip.1).0)
        })
    }

    #[inline]
    pub fn clip_ray_parameters(&self, ray: &Ray<N>) -> Option<(N, N)> {
        match self.clip_line_parameters(&ray.origin, &ray.dir) {
            Some(clip) => {
                let t0 = clip.0;
                let t1 = clip.1;

                if t1 < N::zero() {
                    None
                } else {
                    Some((na::sup(&t0, &N::zero()), t1))
                }
            }
            None => None
        }
    }

    #[inline]
    pub fn clip_ray(&self, ray: &Ray<N>) -> Option<Segment<N>> {
        self.clip_ray_parameters(ray).map(|clip| {
            Segment::new(ray.point_at(clip.0), ray.point_at(clip.1))
        })
    }
}

#[cfg(feature = "dim3")]
fn do_toi_and_normal_and_uv_with_ray<N: Real>(
    m: &Isometry<N>,
    aabb: &AABB<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
{
    if na::dimension::<Vector<N>>() != 3 {
        aabb.toi_and_normal_with_ray(m, ray, solid)
    } else {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(aabb, &ls_ray, solid).map(|(t, n, s)| {
            let pt = ls_ray.origin + ls_ray.dir * t;
            let dpt = pt - *aabb.mins();
            let scale = *aabb.maxs() - *aabb.mins();
            let id = na::abs(&s);
            let gs_n = m * n;
            let feature = if s < 0 {
                FeatureId::Face(id as usize - 1 + 3)
            } else {
                FeatureId::Face(id as usize - 1)
            };

            if id == 1 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[1] / scale[1], dpt[2] / scale[2])),
                )
            } else if id == 2 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[2] / scale[2], dpt[0] / scale[0])),
                )
            } else {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[0] / scale[0], dpt[1] / scale[1])),
                )
            }
        })
    }
}

fn clip_line<N: Real>(aabb: &AABB<N>, origin: &Point<N>, dir: &Vector<N>) -> Option<((N, Vector<N>, isize), (N, Vector<N>, isize))> {
    let mut tmax: N = Bounded::max_value();
    let mut tmin: N = -tmax;
    let mut near_side = 0;
    let mut far_side = 0;
    let mut near_diag = false;
    let mut far_diag = false;

    for i in 0usize..na::dimension::<Vector<N>>() {
        if dir[i].is_zero() {
            if origin[i] < aabb.mins()[i] || origin[i] > aabb.maxs()[i] {
                return None;
            }
        } else {
            let _1: N = na::one();
            let denom = _1 / dir[i];
            let flip_sides;
            let mut inter_with_near_plane = (aabb.mins()[i] - origin[i]) * denom;
            let mut inter_with_far_plane = (aabb.maxs()[i] - origin[i]) * denom;

            if inter_with_near_plane > inter_with_far_plane {
                flip_sides = true;
                mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
            } else {
                flip_sides = false;
            }

            if inter_with_near_plane > tmin {
                tmin = inter_with_near_plane;
                near_side = if flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                near_diag = false;
            } else if inter_with_near_plane == tmin {
                near_diag = true;
            }

            if inter_with_far_plane < tmax {
                tmax = inter_with_far_plane;
                far_side = if !flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                far_diag = false;
            } else if inter_with_far_plane == tmax {
                far_diag = true;
            }

            if tmin > tmax {
                return None;
            }
        }
    }

    let near = if near_diag {
        (tmin, -dir.normalize(), near_side)
    } else {
        let mut normal = Vector::zeros();

        if near_side < 0 {
            normal[(-near_side - 1) as usize] = N::one();
        } else {
            normal[(near_side - 1) as usize] = -N::one();
        }

        (tmin, normal, near_side)
    };

    let far = if far_diag {
        (tmax, -dir.normalize(), far_side)
    } else {
        let mut normal = Vector::zeros();

        if far_side < 0 {
            normal[(-far_side - 1) as usize] = -N::one();
        } else {
            normal[(far_side - 1) as usize] = N::one();
        }

        (tmax, normal, far_side)
    };

    Some((near, far))
}

fn ray_aabb<N: Real>(aabb: &AABB<N>, ray: &Ray<N>, solid: bool) -> Option<(N, Vector<N>, isize)> {
    if let Some((near, far)) = clip_line(aabb, &ray.origin, &ray.dir) {
        if near.0 < N::zero() {
            if solid {
                Some((na::zero(), na::zero(), far.2))
            } else {
                Some(far)
            }
        } else {
            Some(near)
        }
    } else {
        None
    }
}<|endoftext|>


<commit_before>
use {
    AddRoundBorder,
    BackEnd,
    Borrowed,
    Clear,
    Color,
    Field,
    Line,
    Matrix2d,
    RoundBorderLineColorContext,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanColor,
    CanTransform,
    HasColor,
    HasTransform,
};

/// A line context.
pub struct LineColorContext<'a> {
    /// Base/original transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current line.
    pub line: Field<'a, Line>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, LineColorContext<'a>, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for LineColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, LineColorContext<'a>, Color> for LineColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Value(value),
        }
    }
}

impl<'a> View<'a> for LineColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> AddRoundBorder<'a, RoundBorderLineColorContext<'a>> for LineColorContext<'a> {
    #[inline(always)]
    fn round_border_radius(&'a self, radius: f64) -> RoundBorderLineColorContext<'a> {
        RoundBorderLineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            round_border_radius: Value(radius),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> Clear for LineColorContext<'a> {
    fn clear<B: BackEnd>(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        }
    }
}

<commit_msg>Implemented `AddBevelBorder` for `LineColorContext`<commit_after>
use {
    AddBevelBorder,
    AddRoundBorder,
    BackEnd,
    BevelBorderLineColorContext,
    Borrowed,
    Clear,
    Color,
    Field,
    Line,
    Matrix2d,
    RoundBorderLineColorContext,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanColor,
    CanTransform,
    HasColor,
    HasTransform,
};

/// A line context.
pub struct LineColorContext<'a> {
    /// Base/original transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current line.
    pub line: Field<'a, Line>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> HasTransform<'a, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, LineColorContext<'a>, Matrix2d> for LineColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for LineColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, LineColorContext<'a>, Color> for LineColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Value(value),
        }
    }
}

impl<'a> View<'a> for LineColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> AddRoundBorder<'a, RoundBorderLineColorContext<'a>> for LineColorContext<'a> {
    #[inline(always)]
    fn round_border_radius(&'a self, radius: f64) -> RoundBorderLineColorContext<'a> {
        RoundBorderLineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            round_border_radius: Value(radius),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> AddBevelBorder<'a, BevelBorderLineColorContext<'a>> for LineColorContext<'a> {
    #[inline(always)]
    fn bevel_border_radius(&'a self, radius: f64) -> BevelBorderLineColorContext<'a> {
        BevelBorderLineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            bevel_border_radius: Value(radius),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> Clear for LineColorContext<'a> {
    fn clear<B: BackEnd>(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        }
    }
}

<|endoftext|>


<commit_before>use std::num::{Zero, Orderable};
use std::uint;
use std::vec;
use nalgebra::traits::division_ring::DivisionRing;

pub fn projected_gauss_seidel_solve<N: DivisionRing + Orderable + Copy>
       (J:              &mut [N],
        MJ:             &mut [N],
        b:              &mut [N],
        lambda:         &mut [N],
        bounds:         &mut [N],
        idx:            &mut [int],
        sparcity:       uint,
        num_equations:  uint,
        num_bodies:     uint,
        num_iterations: uint) -> ~[N]
{
  // JMJ matrix’s diagonal.
  let mut d        = vec::from_elem(num_equations, Zero::zero::<N>());
  // MJLambda = MJ * lambda
  let mut MJLambda = vec::from_elem(sparcity * num_bodies, Zero::zero::<N>());

  /*
   * compute MJLambda = MJ * lambda
   */
  // warm start
  for uint::iterate(0u, num_equations) |i|
  {
    let b1 = unsafe { idx.unsafe_get(i * 2)     };
    let b2 = unsafe { idx.unsafe_get(i * 2 + 1) };

    if (b1 >= 0)
    {
      for uint::iterate(0u, sparcity) |j|
      {
        unsafe {
          *MJLambda.unsafe_mut_ref(b1 as uint * sparcity + j) +=
            MJ.unsafe_get(i * sparcity * 2 + j) * lambda.unsafe_get(i);
        }
      }
    }

    if (b2 >= 0)
    {
      for uint::iterate(0u, sparcity) |j|
      {
        unsafe {
          *MJLambda.unsafe_mut_ref(b2 as uint * sparcity + j) +=
            MJ.unsafe_get(i * sparcity * 2 + sparcity + j) *
            lambda.unsafe_get(i);
        }
      }
    }
  }

  /*
   * init JB's diagonal
   */
  for uint::iterate(0u, num_equations) |i|
  {
    /*
     * J and MJ^t have the same sparcity
     */
    unsafe {
      d.unsafe_set(i, Zero::zero());
    }

    for uint::iterate(0u, sparcity) |j|
    {
      unsafe {
        *d.unsafe_mut_ref(i) +=
          J.unsafe_get(i * sparcity * 2 + j) *
          MJ.unsafe_get(i * sparcity * 2 + j)
          + J.unsafe_get(i * sparcity * 2 + j + sparcity) *
            MJ.unsafe_get(sparcity + i * sparcity * 2 + j);
      }
    }
  }

  /*
   * solve the system
   */
  for num_iterations.times
  {
    for uint::iterate(0u, num_equations) |i|
    {
      let b1 = unsafe { idx.unsafe_get(i * 2 + 0) } * (sparcity as int);
      let b2 = unsafe { idx.unsafe_get(i * 2 + 1) } * (sparcity as int);

      let mut d_lambda_i = unsafe { b.unsafe_get(i) };

      if (b1 >= 0)
      {
        for uint::iterate(0u, sparcity) |j|
        {
          unsafe {
            d_lambda_i -= J.unsafe_get(2 * sparcity * i + j) *
                          MJLambda.unsafe_get(b1 as uint + j)
          }
        }
      }

      if (b2 >= 0)
      {
        for uint::iterate(0u, sparcity) |j|
        {
          unsafe {
            d_lambda_i -= J.unsafe_get(2 * sparcity * i + sparcity + j) *
                          MJLambda.unsafe_get(b2 as uint + j)
          }
        }
      }

      d_lambda_i /= unsafe { d.unsafe_get(i) };

      /*
       * clamp the value such that: lambda- <= lambda <= lambda+
       * (this is the ``projected'' flavour of Gauss-Seidel
       */
      let lambda_i_0 = unsafe { lambda.unsafe_get(i) };

      // FIXME: clamp takes pointers as arguments… would it be faster if it did
      // not?
      unsafe {
        lambda.unsafe_set(
          i,
          (lambda_i_0 + d_lambda_i).clamp(&bounds.unsafe_get(i * 2),
                                          &bounds.unsafe_get(i * 2 + 1))
        );
      }

      d_lambda_i = unsafe { lambda.unsafe_get(i) } - lambda_i_0;

      if (b1 >= 0)
      {
        for uint::iterate(0u, sparcity) |j|
        {
          unsafe {
            *MJLambda.unsafe_mut_ref(b1 as uint + j) +=
              d_lambda_i * MJ.unsafe_get(i * sparcity * 2 + j)
          }
        }
      }

      if (b2 >= 0)
      {
        for uint::iterate(0u, sparcity) |j|
        {
          unsafe {
            *MJLambda.unsafe_mut_ref(b2 as uint + j) +=
              d_lambda_i * MJ.unsafe_get(i * sparcity * 2 + sparcity + j)
          }
        }
      }
    }
  }

  MJLambda
}
<commit_msg>Replaced for loops by while loops on constraint solver inner loop.<commit_after>use std::num::{Zero, Orderable};
use std::vec;
use nalgebra::traits::division_ring::DivisionRing;

pub fn projected_gauss_seidel_solve<N: DivisionRing + Orderable + Copy>
       (J:              &mut [N],
        MJ:             &mut [N],
        b:              &mut [N],
        lambda:         &mut [N],
        bounds:         &mut [N],
        idx:            &mut [int],
        sparcity:       uint,
        num_equations:  uint,
        num_bodies:     uint,
        num_iterations: uint) -> ~[N]
{
  // JMJ matrix’s diagonal.
  let mut d        = vec::from_elem(num_equations, Zero::zero::<N>());
  // MJLambda = MJ * lambda
  let mut MJLambda = vec::from_elem(sparcity * num_bodies, Zero::zero::<N>());

  /*
   * compute MJLambda = MJ * lambda
   */
  // warm start
  let mut i = 0;
  while(i != num_equations)
  {
    let b1 = unsafe { idx.unsafe_get(i * 2)     };
    let b2 = unsafe { idx.unsafe_get(i * 2 + 1) };

    if (b1 >= 0)
    {
      let mut j = 0;
      while(j != sparcity)
      {
        unsafe {
          *MJLambda.unsafe_mut_ref(b1 as uint * sparcity + j) +=
            MJ.unsafe_get(i * sparcity * 2 + j) * lambda.unsafe_get(i);
        }

        j += 1;
      }
    }

    if (b2 >= 0)
    {
      let mut j = 0;
      while(j != sparcity)
      {
        unsafe {
          *MJLambda.unsafe_mut_ref(b2 as uint * sparcity + j) +=
            MJ.unsafe_get(i * sparcity * 2 + sparcity + j) *
            lambda.unsafe_get(i);
        }

        j += 1;
      }
    }

    i += 1;
  }

  /*
   * init JB's diagonal
   */
  let mut i = 0;
  while (i != num_equations)
  {
    /*
     * J and MJ^t have the same sparcity
     */
    unsafe {
      d.unsafe_set(i, Zero::zero());
    }

    let mut j = 0;
    while(j != sparcity)
    {
      unsafe {
        *d.unsafe_mut_ref(i) +=
          J.unsafe_get(i * sparcity * 2 + j) *
          MJ.unsafe_get(i * sparcity * 2 + j)
          + J.unsafe_get(i * sparcity * 2 + j + sparcity) *
            MJ.unsafe_get(sparcity + i * sparcity * 2 + j);
      }

      j += 1;
    }

    i += 1;
  }

  /*
   * solve the system
   */

  let mut time = 0;
  while(time != num_iterations)
  {
    let mut i = 0;
    while(i != num_equations)
    {
      let b1 = unsafe { idx.unsafe_get(i * 2 + 0) } * (sparcity as int);
      let b2 = unsafe { idx.unsafe_get(i * 2 + 1) } * (sparcity as int);

      let mut d_lambda_i = unsafe { b.unsafe_get(i) };

      if (b1 >= 0)
      {
        let mut j = 0;
        while(j != sparcity)
        {
          unsafe {
            d_lambda_i -= J.unsafe_get(2 * sparcity * i + j) *
                          MJLambda.unsafe_get(b1 as uint + j)
          }

          j += 1;
        }
      }

      if (b2 >= 0)
      {
        let mut j = 0;
        while(j != sparcity)
        {
          unsafe {
            d_lambda_i -= J.unsafe_get(2 * sparcity * i + sparcity + j) *
                          MJLambda.unsafe_get(b2 as uint + j)
          }

          j += 1;
        }
      }

      d_lambda_i /= unsafe { d.unsafe_get(i) };

      /*
       * clamp the value such that: lambda- <= lambda <= lambda+
       * (this is the ``projected'' flavour of Gauss-Seidel
       */
      let lambda_i_0 = unsafe { lambda.unsafe_get(i) };

      // FIXME: clamp takes pointers as arguments… would it be faster if it did
      // not?
      unsafe {
        lambda.unsafe_set(
          i,
          (lambda_i_0 + d_lambda_i).clamp(&bounds.unsafe_get(i * 2),
                                          &bounds.unsafe_get(i * 2 + 1))
        );
      }

      d_lambda_i = unsafe { lambda.unsafe_get(i) } - lambda_i_0;

      if (b1 >= 0)
      {
        let mut j = 0;
        while(j != sparcity)
        {
          unsafe {
            *MJLambda.unsafe_mut_ref(b1 as uint + j) +=
              d_lambda_i * MJ.unsafe_get(i * sparcity * 2 + j)
          }

          j += 1;
        }
      }

      if (b2 >= 0)
      {
        let mut j = 0;
        while(j != sparcity)
        {
          unsafe {
            *MJLambda.unsafe_mut_ref(b2 as uint + j) +=
              d_lambda_i * MJ.unsafe_get(i * sparcity * 2 + sparcity + j)
          }

          j += 1;
        }
      }

      i += 1;
    }

    time += 1;
  }

  MJLambda
}
<|endoftext|>


<commit_before>use std;
use std::{ mem, slice, string };
use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use raw::{ SVt_PVAV, SVt_PVHV, SVt_PVCV, SVt_PVGV };
use array::{ AV };
use hash::{ HV };
use convert::{ IntoSV, FromSV, TryFromSV };

/// Perl scalar object.
pub struct SV(Owned<raw::SV>);

impl SV {
    method! {
        /// Return true if SV is a real scalar value.
        simple fn is_scalar() -> bool = sv_type() < SVt_PVAV
    }
    method! {
        /// Return true if SV contains array.
        simple fn is_array() -> bool = sv_type() == SVt_PVAV
    }
    method! {
        /// Return true if SV contains hash.
        simple fn is_hash() -> bool = sv_type() == SVt_PVHV
    }
    method! {
        /// Return true if SV contains subroutine.
        simple fn is_code() -> bool = sv_type() == SVt_PVCV
    }
    method! {
        /// Return true if SV contains glob.
        simple fn is_glob() -> bool = sv_type() == SVt_PVGV
    }
    method! {
        /// Return true if SV is defined.
        ///
        /// [`SvOK`](http://perldoc.perl.org/perlapi.html#SvOK).
        simple fn ok() -> bool = sv_ok() != 0
    }
    method! {
        /// Return true if SV contains a signed integer.
        ///
        /// Perl macro:[`SvIOK`](http://perldoc.perl.org/perlapi.html#SvIOK).
        simple fn iv_ok() -> bool = sv_iok() != 0
    }
    method! {
        /// Coerce the given SV to an integer and return it.
        ///
        /// Perl macro: [`SvIV`](http://perldoc.perl.org/perlapi.html#SvIV).
        simple fn iv() -> IV = sv_iv()
    }
    method! {
        /// Return true if SV contains a unsigned integer.
        ///
        /// Perl macro:[`SvUOK`](http://perldoc.perl.org/perlapi.html#SvUOK).
        simple fn uv_ok() -> bool = sv_uok() != 0
    }
    method! {
        /// Coerce the given SV to an unsigned integer and return it.
        ///
        /// Perl macro: [`SvUV`](http://perldoc.perl.org/perlapi.html#SvUV).
        simple fn uv() -> UV = sv_uv()
    }
    method! {
        /// Return true if SV contains a floating point value.
        ///
        /// Perl macro:[`SvNOK`](http://perldoc.perl.org/perlapi.html#SvNOK).
        simple fn nv_ok() -> bool = sv_nok() != 0
    }
    method! {
        /// Coerce the given SV to a floating point value and return it.
        ///
        /// Perl macro: [`SvNV`](http://perldoc.perl.org/perlapi.html#SvNV).
        simple fn nv() -> NV = sv_nv()
    }
    method! {
        /// Return true if SV contains a string.
        ///
        /// Perl macro:[`SvPOK`](http://perldoc.perl.org/perlapi.html#SvPOK).
        simple fn pv_ok() -> bool = sv_pok() != 0
    }
    method! {
        /// Return UTF8 flag on the SV.
        ///
        /// You should use this after a call to `to_vec` or `to_string`, in case any call to string
        /// overloading updates the internal flag.
        ///
        /// Perl macro: [`SvUTF8`](http://perldoc.perl.org/perlapi.html#SvUTF8).
        simple fn utf8() -> bool = sv_utf8() != 0
    }

    /// Get a slice of the internal string buffer of the SV.
    ///
    /// This method is unsafe, because the buffer may be changed, moved or freed by the interpreter
    /// whenever this SV is accessed or modified. To be safe, code that uses this method should not
    /// access interpreter context, this or any other perl value while the slice is in scope.
    ///
    /// For example, this use is okay:
    ///
    /// ```ignore
    /// let chars = unsafe { sv.as_slice().chars().count() };
    /// ```
    ///
    /// And this code may potentially access freed memory:
    ///
    /// ```ignore
    /// let msg = unsafe { sv1.as_slice() };
    /// let pos = sv2.iv();
    /// println!("{}", &msg[pos..]);
    /// ```
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub unsafe fn as_slice(&self) -> &[u8] {
        let mut len = 0;
        let ptr = self.pthx().sv_pv(self.as_ptr(), &mut len);
        slice::from_raw_parts(ptr as *const u8, len as usize)
    }

    /// Return a copy of string in the SV as a vector of bytes.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_vec(&self) -> Vec<u8> {
        unsafe {
            self.as_slice().to_owned()
        }
    }

    /// Return a copy of string in the SV.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_string(&self) -> Result<String, string::FromUtf8Error> {
        String::from_utf8(self.to_vec())
    }

    method! {
        /// Return true if SV contains a Perl reference.
        ///
        /// Perl macro:[`SvROK`](http://perldoc.perl.org/perlapi.html#SvROK).
        simple fn rv_ok() -> bool = sv_rok() != 0
    }

    #[inline]
    unsafe fn deref_raw(&self) -> *mut raw::SV {
        self.pthx().sv_rv(self.as_ptr())
    }

    /// Dereference RV.
    ///
    /// Return `None` if `self` is not a valid Perl reference.
    #[inline]
    pub fn deref(&self) -> Option<SV> {
        if self.rv_ok() {
            Some(unsafe { SV::from_raw_borrowed(self.pthx(), self.deref_raw()) })
        } else {
            None
        }
    }

    /// Dereference RV into AV.
    ///
    /// Return `None` if `self` is not an array reference.
    #[inline]
    pub fn deref_av(&self) -> Option<AV> {
        self.deref().and_then(|sv| sv.into_av())
    }

    /// Dereference RV into HV.
    ///
    /// Return `None` if `self` is not a hash reference.
    #[inline]
    pub fn deref_hv(&self) -> Option<HV> {
        self.deref().and_then(|sv| sv.into_hv())
    }

    /// Cast SV into AV.
    #[inline]
    pub fn into_av(self) -> Option<AV> {
        if self.is_array() {
            Some(unsafe { AV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Cast SV into HV.
    #[inline]
    pub fn into_hv(self) -> Option<HV> {
        if self.is_hash() {
            Some(unsafe { HV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Consume SV and convert into raw pointer.
    ///
    /// Does not decrement reference count. Returned pointer must be correctly disposed of to avoid
    /// memory leaks.
    #[inline]
    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    /// Construct new instance from a raw SV pointer without incrementing reference counter.
    ///
    /// Owned SV pointers are returned by assorted
    /// [`newSV`](http://perldoc.perl.org/perlapi.html#newSV) functions.
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new instance from a raw SV pointer and increment reference counter.
    ///
    /// Borrowed SV pointers exist on stack and are returned by functions like
    /// [`av_fetch`](http://perldoc.perl.org/perlapi.html#av_fetch) or
    /// [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl FromSV for IV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for UV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> UV {
        pthx.sv_uv(raw)
    }
}

impl FromSV for NV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> NV {
        pthx.sv_nv(raw)
    }
}

impl FromSV for SV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl TryFromSV for String {
    type Error = std::str::Utf8Error;

    #[inline]
    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<Self, Self::Error> {
        let mut len = 0;
        let ptr = pthx.sv_pv(raw, &mut len);
        let bytes = slice::from_raw_parts(ptr as *const u8, len as usize);
        Ok(try!(std::str::from_utf8(bytes)).to_owned())
    }
}

impl IntoSV for IV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl IntoSV for bool {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let raw = if self { pthx.sv_yes() } else { pthx.sv_no() };
            SV::from_raw_owned(pthx, raw)
        }
    }
}

impl IntoSV for String {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        (&self[..]).into_sv(pthx)
    }
}

impl<'a> IntoSV for &'a str {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let svp = pthx.new_sv_pvn(self.as_ptr() as *const i8,
                                      self.len() as raw::STRLEN,
                                      raw::SVf_UTF8 as raw::U32);
            SV::from_raw_owned(pthx, svp)
        }
    }
}

impl IntoSV for SV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        assert!(self.pthx() == pthx);
        self
    }
}
<commit_msg>Implement clone for SV.<commit_after>use std;
use std::{ mem, slice, string };
use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use raw::{ SVt_PVAV, SVt_PVHV, SVt_PVCV, SVt_PVGV };
use array::{ AV };
use hash::{ HV };
use convert::{ IntoSV, FromSV, TryFromSV };

/// Perl scalar object.
pub struct SV(Owned<raw::SV>);

impl SV {
    method! {
        /// Return true if SV is a real scalar value.
        simple fn is_scalar() -> bool = sv_type() < SVt_PVAV
    }
    method! {
        /// Return true if SV contains array.
        simple fn is_array() -> bool = sv_type() == SVt_PVAV
    }
    method! {
        /// Return true if SV contains hash.
        simple fn is_hash() -> bool = sv_type() == SVt_PVHV
    }
    method! {
        /// Return true if SV contains subroutine.
        simple fn is_code() -> bool = sv_type() == SVt_PVCV
    }
    method! {
        /// Return true if SV contains glob.
        simple fn is_glob() -> bool = sv_type() == SVt_PVGV
    }
    method! {
        /// Return true if SV is defined.
        ///
        /// [`SvOK`](http://perldoc.perl.org/perlapi.html#SvOK).
        simple fn ok() -> bool = sv_ok() != 0
    }
    method! {
        /// Return true if SV contains a signed integer.
        ///
        /// Perl macro:[`SvIOK`](http://perldoc.perl.org/perlapi.html#SvIOK).
        simple fn iv_ok() -> bool = sv_iok() != 0
    }
    method! {
        /// Coerce the given SV to an integer and return it.
        ///
        /// Perl macro: [`SvIV`](http://perldoc.perl.org/perlapi.html#SvIV).
        simple fn iv() -> IV = sv_iv()
    }
    method! {
        /// Return true if SV contains a unsigned integer.
        ///
        /// Perl macro:[`SvUOK`](http://perldoc.perl.org/perlapi.html#SvUOK).
        simple fn uv_ok() -> bool = sv_uok() != 0
    }
    method! {
        /// Coerce the given SV to an unsigned integer and return it.
        ///
        /// Perl macro: [`SvUV`](http://perldoc.perl.org/perlapi.html#SvUV).
        simple fn uv() -> UV = sv_uv()
    }
    method! {
        /// Return true if SV contains a floating point value.
        ///
        /// Perl macro:[`SvNOK`](http://perldoc.perl.org/perlapi.html#SvNOK).
        simple fn nv_ok() -> bool = sv_nok() != 0
    }
    method! {
        /// Coerce the given SV to a floating point value and return it.
        ///
        /// Perl macro: [`SvNV`](http://perldoc.perl.org/perlapi.html#SvNV).
        simple fn nv() -> NV = sv_nv()
    }
    method! {
        /// Return true if SV contains a string.
        ///
        /// Perl macro:[`SvPOK`](http://perldoc.perl.org/perlapi.html#SvPOK).
        simple fn pv_ok() -> bool = sv_pok() != 0
    }
    method! {
        /// Return UTF8 flag on the SV.
        ///
        /// You should use this after a call to `to_vec` or `to_string`, in case any call to string
        /// overloading updates the internal flag.
        ///
        /// Perl macro: [`SvUTF8`](http://perldoc.perl.org/perlapi.html#SvUTF8).
        simple fn utf8() -> bool = sv_utf8() != 0
    }

    /// Get a slice of the internal string buffer of the SV.
    ///
    /// This method is unsafe, because the buffer may be changed, moved or freed by the interpreter
    /// whenever this SV is accessed or modified. To be safe, code that uses this method should not
    /// access interpreter context, this or any other perl value while the slice is in scope.
    ///
    /// For example, this use is okay:
    ///
    /// ```ignore
    /// let chars = unsafe { sv.as_slice().chars().count() };
    /// ```
    ///
    /// And this code may potentially access freed memory:
    ///
    /// ```ignore
    /// let msg = unsafe { sv1.as_slice() };
    /// let pos = sv2.iv();
    /// println!("{}", &msg[pos..]);
    /// ```
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub unsafe fn as_slice(&self) -> &[u8] {
        let mut len = 0;
        let ptr = self.pthx().sv_pv(self.as_ptr(), &mut len);
        slice::from_raw_parts(ptr as *const u8, len as usize)
    }

    /// Return a copy of string in the SV as a vector of bytes.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_vec(&self) -> Vec<u8> {
        unsafe {
            self.as_slice().to_owned()
        }
    }

    /// Return a copy of string in the SV.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_string(&self) -> Result<String, string::FromUtf8Error> {
        String::from_utf8(self.to_vec())
    }

    method! {
        /// Return true if SV contains a Perl reference.
        ///
        /// Perl macro:[`SvROK`](http://perldoc.perl.org/perlapi.html#SvROK).
        simple fn rv_ok() -> bool = sv_rok() != 0
    }

    #[inline]
    unsafe fn deref_raw(&self) -> *mut raw::SV {
        self.pthx().sv_rv(self.as_ptr())
    }

    /// Dereference RV.
    ///
    /// Return `None` if `self` is not a valid Perl reference.
    #[inline]
    pub fn deref(&self) -> Option<SV> {
        if self.rv_ok() {
            Some(unsafe { SV::from_raw_borrowed(self.pthx(), self.deref_raw()) })
        } else {
            None
        }
    }

    /// Dereference RV into AV.
    ///
    /// Return `None` if `self` is not an array reference.
    #[inline]
    pub fn deref_av(&self) -> Option<AV> {
        self.deref().and_then(|sv| sv.into_av())
    }

    /// Dereference RV into HV.
    ///
    /// Return `None` if `self` is not a hash reference.
    #[inline]
    pub fn deref_hv(&self) -> Option<HV> {
        self.deref().and_then(|sv| sv.into_hv())
    }

    /// Cast SV into AV.
    #[inline]
    pub fn into_av(self) -> Option<AV> {
        if self.is_array() {
            Some(unsafe { AV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Cast SV into HV.
    #[inline]
    pub fn into_hv(self) -> Option<HV> {
        if self.is_hash() {
            Some(unsafe { HV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Consume SV and convert into raw pointer.
    ///
    /// Does not decrement reference count. Returned pointer must be correctly disposed of to avoid
    /// memory leaks.
    #[inline]
    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    /// Construct new instance from a raw SV pointer without incrementing reference counter.
    ///
    /// Owned SV pointers are returned by assorted
    /// [`newSV`](http://perldoc.perl.org/perlapi.html#newSV) functions.
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new instance from a raw SV pointer and increment reference counter.
    ///
    /// Borrowed SV pointers exist on stack and are returned by functions like
    /// [`av_fetch`](http://perldoc.perl.org/perlapi.html#av_fetch) or
    /// [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl Clone for SV {
    fn clone(&self) -> SV {
        unsafe {
            SV::from_raw_borrowed(self.pthx(), self.as_ptr())
        }
    }
}

impl FromSV for IV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for UV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> UV {
        pthx.sv_uv(raw)
    }
}

impl FromSV for NV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> NV {
        pthx.sv_nv(raw)
    }
}

impl FromSV for SV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl TryFromSV for String {
    type Error = std::str::Utf8Error;

    #[inline]
    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<Self, Self::Error> {
        let mut len = 0;
        let ptr = pthx.sv_pv(raw, &mut len);
        let bytes = slice::from_raw_parts(ptr as *const u8, len as usize);
        Ok(try!(std::str::from_utf8(bytes)).to_owned())
    }
}

impl IntoSV for IV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl IntoSV for bool {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let raw = if self { pthx.sv_yes() } else { pthx.sv_no() };
            SV::from_raw_owned(pthx, raw)
        }
    }
}

impl IntoSV for String {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        (&self[..]).into_sv(pthx)
    }
}

impl<'a> IntoSV for &'a str {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let svp = pthx.new_sv_pvn(self.as_ptr() as *const i8,
                                      self.len() as raw::STRLEN,
                                      raw::SVf_UTF8 as raw::U32);
            SV::from_raw_owned(pthx, svp)
        }
    }
}

impl IntoSV for SV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        assert!(self.pthx() == pthx);
        self
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;

use std::error::Error;
use self::rustbox::{Color, RustBox};
use self::rustbox::Key;
use super::rusoto::{ProvideAwsCredentials, DispatchSignedRequest};
use kinesis::KinesisHelper;

pub struct Screen {
    rustbox: RustBox
}

impl Screen {

    pub fn new() -> Screen {
        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        Screen { rustbox: rustbox }
    }

    pub fn draw_first(&self) {
        self.rustbox.print(0, 0, rustbox::RB_BOLD, Color::White, Color::Black, "> Hello, world!");
        self.rustbox.print(0, 1, rustbox::RB_BOLD, Color::White, Color::Black, "> Press 'q' to quit.");
        self.rustbox.print(0, 2, rustbox::RB_BOLD, Color::White, Color::Black, "> Press 'l' to show kinesis streams.");
        self.rustbox.present();
    }

    pub fn draw_strem_names(&self, streamNames: Vec<String>) {

        for (num, streamName) in streamNames.iter().enumerate() {
            self.rustbox.print(0, num, rustbox::RB_BOLD, Color::Green, Color::Black, &streamName);
        }
    }

    pub fn draw<P, D>(&self, kinesis_helper: &KinesisHelper<P, D>) where P: ProvideAwsCredentials, D: DispatchSignedRequest {

        loop {

            self.rustbox.clear();

            match self.rustbox.poll_event(false) {
                Ok(rustbox::Event::KeyEvent(key)) => {
                    match key {
                        Key::Char('q') => {
                            break;
                        },
                        Key::Char('l') => {
                            let streams = kinesis_helper.list_streams();
                            self.draw_strem_names(streams)
                        },
                        _ => { }
                    }
                },
                Err(e) => panic!("{}", e.description()),
                _ => { }
            }
            self.rustbox.present();
        }
    }
}
<commit_msg>Fix view control<commit_after>extern crate rustbox;

use std::error::Error;
use self::rustbox::{Color, RustBox};
use self::rustbox::Key;
use super::rusoto::{ProvideAwsCredentials, DispatchSignedRequest};
use kinesis::KinesisHelper;

pub struct Screen {
    rustbox: RustBox
}

impl Screen {

    pub fn new() -> Screen {
        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        Screen { rustbox: rustbox }
    }

    pub fn draw_first(&self) {
        self.draw_help();
        self.rustbox.present();
    }

    pub fn draw_help(&self) {
        self.rustbox.print(0, 0, rustbox::RB_BOLD, Color::White, Color::Black, "> Hello!");
        self.rustbox.print(0, 1, rustbox::RB_BOLD, Color::White, Color::Black, "> Press 'q' to quit.");
        self.rustbox.print(0, 2, rustbox::RB_BOLD, Color::White, Color::Black, "> Press 'l' to show kinesis streams.");
    }

    pub fn draw_strem_names(&self, streamNames: Vec<String>) {

        self.rustbox.print(0, 0, rustbox::RB_BOLD, Color::Green, Color::Black, "Kinesis Stream List");

        for (num, streamName) in streamNames.iter().enumerate() {
            self.rustbox.print(0, num + 1, rustbox::RB_BOLD, Color::White, Color::Black, &format!("[{0}]: {1}", num, &streamName));
        }
    }

    pub fn draw<P, D>(&self, kinesis_helper: &KinesisHelper<P, D>) where P: ProvideAwsCredentials, D: DispatchSignedRequest {

        loop {

            self.rustbox.clear();

            match self.rustbox.poll_event(false) {
                Ok(rustbox::Event::KeyEvent(key)) => {
                    match key {
                        Key::Char('q') => {
                            break;
                        },
                        Key::Char('l') => {
                            let streams = kinesis_helper.list_streams();
                            self.draw_strem_names(streams)
                        },
                        _ => { self.draw_help() }
                    }
                },
                Err(e) => panic!("{}", e.description()),
                _ => { self.draw_help() }
            }
            self.rustbox.present();
        }
    }
}
<|endoftext|>


<commit_before>// Refer:
// https://www.ietf.org/rfc/rfc2388.txt:  Returning Values from Forms:  multipart/form-data
// https://www.ietf.org/rfc/rfc2183.txt:  The Content-Disposition Header Field

use std::fmt;
use std::ascii::AsciiExt;

use hyper::header::{Header, HeaderFormat, parsing};

/// We define a Content-Disposition form-data only header, which is found within
/// the mime multipart sections.  NOT FOR GENERAL USE
#[derive(Debug,Clone,PartialEq)]
pub struct ContentDispositionFormData {
    pub name: Option<String>,
    pub filename: Option<String>,
}

impl Header for ContentDispositionFormData {
    fn header_name() -> &'static str {
        "Content-Disposition"
    }

    fn parse_header(raw: &[Vec<u8>]) -> Option<ContentDispositionFormData> {
        parsing::from_one_raw_str(raw).and_then(|s: String| {
            let mut sections = s.split(';');
            match sections.next() {
                None => return None,
                Some(s) => {
                    if &s.trim().to_ascii_lowercase() != "form-data" {
                        return None
                    }
                }
            };
            let mut cd = ContentDispositionFormData { name: None, filename: None };
            for section in sections {
                let mut parts = section.split('=');
                if parts.clone().count() != 2 { continue; }
                let key = parts.next().unwrap().trim().to_ascii_lowercase();
                let mut val = parts.next().unwrap().trim();
                if val.chars().next()==Some('"') && val.chars().rev().next()==Some('"') {
                    val = &val[1..val.len()-1]; // unwrap quotes
                }
                match &*key {
                    "name" => cd.name = Some(val.to_string()),
                    "filename" => cd.filename = Some(val.to_string()),
                    _ => {}
                }
            }
            Some(cd)
        })
    }
}

impl HeaderFormat for ContentDispositionFormData {
    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("form-data")
    }
}

#[cfg(test)]
mod tests {
    use super::ContentDispositionFormData;
    use hyper::header::Header;

    #[test]
    fn parse_header() {
        let a: ContentDispositionFormData =
            ContentDispositionFormData::parse_header(
                [b"form-data; dummy=3; name=upload;\r\n filename=\"sample.png\"".to_vec()].as_ref() )
            .unwrap();
        let b = ContentDispositionFormData {
            name: Some("upload".to_string()),
            filename: Some("sample.png".to_string()),
        };
        assert_eq!(a, b);

        let e: Option<ContentDispositionFormData> = Header::parse_header([b"".to_vec()].as_ref());
        assert_eq!(e, None);
    }

    // RFC 2231 (obsoletes 2184) is NOT supported presently
    // See closed issue #3
    //
    //#[test]
    //fn parse_header_test_rfc_2231() {
    //    let a: ContentDispositionFormData =
    //        ContentDispositionFormData::parse_header(
    //            [b"form-data; dummy=3;\r\n filename*0=\"sample%20music\"; filename*1=\".png\"".to_vec()].as_ref() )
    //        .unwrap();
    //    let b = ContentDispositionFormData {
    //        name: None,
    //        filename: Some("sample music.png".to_string()),
    //    };
    //    assert_eq!(a, b);
    //}
}
<commit_msg>upstream hyper: Update parse_header return value<commit_after>// Refer:
// https://www.ietf.org/rfc/rfc2388.txt:  Returning Values from Forms:  multipart/form-data
// https://www.ietf.org/rfc/rfc2183.txt:  The Content-Disposition Header Field

use std::fmt;
use std::ascii::AsciiExt;

use hyper::header::{Header, HeaderFormat, parsing};
use hyper::error::Error as HyperError;

/// We define a Content-Disposition form-data only header, which is found within
/// the mime multipart sections.  NOT FOR GENERAL USE
#[derive(Debug,Clone,PartialEq)]
pub struct ContentDispositionFormData {
    pub name: Option<String>,
    pub filename: Option<String>,
}

impl Header for ContentDispositionFormData {
    fn header_name() -> &'static str {
        "Content-Disposition"
    }

    fn parse_header(raw: &[Vec<u8>]) -> Result<ContentDispositionFormData,HyperError> {
        parsing::from_one_raw_str(raw).and_then(|s: String| {
            let mut sections = s.split(';');
            match sections.next() {
                None => return Err(HyperError::Header),
                Some(s) => {
                    if &s.trim().to_ascii_lowercase() != "form-data" {
                        return Err(HyperError::Header)
                    }
                }
            };
            let mut cd = ContentDispositionFormData { name: None, filename: None };
            for section in sections {
                let mut parts = section.split('=');
                if parts.clone().count() != 2 { continue; }
                let key = parts.next().unwrap().trim().to_ascii_lowercase();
                let mut val = parts.next().unwrap().trim();
                if val.chars().next()==Some('"') && val.chars().rev().next()==Some('"') {
                    val = &val[1..val.len()-1]; // unwrap quotes
                }
                match &*key {
                    "name" => cd.name = Some(val.to_string()),
                    "filename" => cd.filename = Some(val.to_string()),
                    _ => {}
                }
            }
            Ok(cd)
        })
    }
}

impl HeaderFormat for ContentDispositionFormData {
    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("form-data")
    }
}

#[cfg(test)]
mod tests {
    use super::ContentDispositionFormData;
    use hyper::header::Header;
    use hyper::error::Error as HyperError;

    #[test]
    fn parse_header() {
        let a: ContentDispositionFormData =
            ContentDispositionFormData::parse_header(
                [b"form-data; dummy=3; name=upload;\r\n filename=\"sample.png\"".to_vec()].as_ref() )
            .unwrap();
        let b = ContentDispositionFormData {
            name: Some("upload".to_string()),
            filename: Some("sample.png".to_string()),
        };
        assert_eq!(a, b);

        match ContentDispositionFormData::parse_header([b"".to_vec()].as_ref()) {
            Ok(_) => assert!(false, "Empty header was parsed as ok!"),
            Err(HyperError::Header) => assert!(true),
            Err(_) => assert!(false, "Empty header parsed with wrong error"),
        }
    }

    // RFC 2231 (obsoletes 2184) is NOT supported presently
    // See closed issue #3
    //
    //#[test]
    //fn parse_header_test_rfc_2231() {
    //    let a: ContentDispositionFormData =
    //        ContentDispositionFormData::parse_header(
    //            [b"form-data; dummy=3;\r\n filename*0=\"sample%20music\"; filename*1=\".png\"".to_vec()].as_ref() )
    //        .unwrap();
    //    let b = ContentDispositionFormData {
    //        name: None,
    //        filename: Some("sample music.png".to_string()),
    //    };
    //    assert_eq!(a, b);
    //}
}
<|endoftext|>