use std::default::Default;

#[derive(Default)]
pub struct MemoryMap {
    pub global:   Vec<Symbol>,
    pub sections: Vec<Section>
}

impl MemoryMap {
    pub fn is_empty(&self) -> bool {
        self.global.is_empty() && self.sections.is_empty()
    }
}

#[derive(Default)]
pub struct Section {
    pub name:    String,
    pub adr:     u64,
    pub size:    usize,
    pub symbols: Vec<Symbol>
}

impl Section {
    pub fn new(name: String, adr: u64, size: usize) -> Section {
        Section{name, adr, size, symbols: Vec::new()}
    }

    pub fn contains_adr(&self, adr: u64) -> bool {
        adr >= self.adr && adr < (self.adr + self.size as u64)
    }
}

impl NamedMemoryArea for Section {
    fn get_name(&self) -> &str {
        self.name.as_str()
    }

    fn get_adr(&self) -> u64 {
        self.adr
    }

    fn get_size(&self) -> usize {
        self.size
    }
}

#[derive(Default)]
pub struct Symbol {
    pub name: String,
    pub adr:  u64,
    pub size: usize
}

impl Symbol {
    pub fn new(name: String, adr: u64, size: usize) -> Symbol {
        Symbol{name, adr, size}
    }
}

impl NamedMemoryArea for Symbol {
    fn get_name(&self) -> &str {
        self.name.as_str()
    }

    fn get_adr(&self) -> u64 {
        self.adr
    }

    fn get_size(&self) -> usize {
        self.size
    }
}

pub trait NamedMemoryArea {
    fn get_name(&self) -> &str;
    fn get_adr(&self)  -> u64;
    fn get_size(&self) -> usize;

    fn get_end_adr(&self) -> u64 {
        self.get_adr() + self.get_size() as u64
    }
}