p2sh 0.4.3

The p2sh Programming language interpreter
use std::cell::RefCell;
use std::fmt;
use std::fmt::Write;
use std::hash::{Hash, Hasher};
use std::rc::Rc;

use super::Object;

#[derive(Debug)]
pub struct Array {
    pub elements: RefCell<Vec<Rc<Object>>>,
}

impl Array {
    pub fn new(elements: Vec<Rc<Object>>) -> Self {
        Self {
            elements: RefCell::new(elements),
        }
    }
    pub fn len(&self) -> usize {
        self.elements.borrow().len()
    }
    pub fn is_empty(&self) -> bool {
        self.elements.borrow().is_empty()
    }
    pub fn get(&self, idx: usize) -> Rc<Object> {
        match self.elements.borrow().get(idx) {
            Some(value) => value.clone(),
            None => Rc::new(Object::Null),
        }
    }
    pub fn last(&self) -> Rc<Object> {
        match self.elements.borrow().last() {
            Some(value) => value.clone(),
            None => Rc::new(Object::Null),
        }
    }
    pub fn push(&self, obj: Rc<Object>) {
        self.elements.borrow_mut().push(obj);
    }
    pub fn set(&self, idx: usize, obj: Rc<Object>) {
        self.elements.borrow_mut()[idx] = obj;
    }
}

impl fmt::Display for Array {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let elements_str = self
            .elements
            .borrow()
            .iter()
            .fold(String::new(), |mut acc, p| {
                let _ = write!(&mut acc, "{}, ", p);
                acc
            });
        let elements_str = elements_str.trim_end_matches(|c| c == ' ' || c == ',');
        write!(f, "[{}]", elements_str)
    }
}

impl From<&Array> for Vec<u8> {
    fn from(obj: &Array) -> Self {
        let mut bytes = Vec::new();
        for element in obj.elements.borrow().iter() {
            let b: Vec<u8> = element.as_ref().into();
            bytes.extend_from_slice(&b);
        }
        bytes
    }
}

impl PartialEq for Array {
    fn eq(&self, other: &Self) -> bool {
        let self_elements = self.elements.borrow();
        let other_elements = other.elements.borrow();

        if self_elements.len() != other_elements.len() {
            return false;
        }

        for (a, b) in self_elements.iter().zip(other_elements.iter()) {
            if *a != *b {
                return false;
            }
        }
        true
    }
}

impl Eq for Array {}

impl Hash for Array {
    fn hash<H: Hasher>(&self, state: &mut H) {
        for element in self.elements.borrow().iter() {
            element.hash(state);
        }
    }
}