use std::{fmt, rc::Rc};

use crate::vm::{Value, value::BytecodeFunction};

#[derive(Debug, Clone, PartialEq)]
pub enum UpvalueValue {
    Open(usize),
    Closed(Box<Value>),
}

#[derive(Clone, PartialEq)]
pub struct ClosureValue {
    pub function: Rc<BytecodeFunction>,
    pub upvalues: Vec<usize>,
}

impl ClosureValue {
    pub fn instruction_byte(&self, address: usize) -> Option<u8> {
        self.function.instructions.get(address).copied()
    }
}

impl fmt::Debug for ClosureValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ClosureValue")
            .field("function", &self.function)
            .finish_non_exhaustive()
    }
}

impl fmt::Display for ClosureValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "<closure {}@{:p}>", self.function.name(), self.function)
    }
}
