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

//! Volume Groups

use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::str::FromStr;
use std::borrow::Cow;

use time::now;
use nix::sys::utsname::uname;

use lv::{LV, Segment};
use pv::{PV, Device};
use pvlabel::{PvHeader, SECTOR_SIZE};
use parser::{LvmTextMap, Entry};
use lvmetad;
use dm;
use dm::DM;
use util::{align_to, make_uuid};

/// A Volume Group.
#[derive(Debug, PartialEq, Clone)]
pub struct VG {
    /// Name.
    pub name: String,
    /// Uuid.
    pub id: String,
    /// The generation of metadata this VG represents.
    pub seqno: u64,
    /// Always "LVM2".
    pub format: String,
    /// Status.
    pub status: Vec<String>,
    /// Flags.
    pub flags: Vec<String>,
    /// Size of each extent, in 512-byte sectors.
    pub extent_size: u64,
    /// Maximum number of LVs, 0 means no limit.
    pub max_lv: u64,
    /// Maximum number of PVs, 0 means no limit.
    pub max_pv: u64,
    /// How many metadata copies (?)
    pub metadata_copies: u64,
    /// Physical Volumes within this volume group.
    pub pvs: BTreeMap<String, PV>,
    /// Logical Volumes within this volume group.
    pub lvs: BTreeMap<String, LV>,
}

impl VG {
    /// The total number of extents in use in the volume group.
    pub fn extents_in_use(&self) -> u64 {
        self.lvs
            .values()
            .map(|x| x.used_extents())
            .sum()
    }

    /// The total number of free extents in the volume group.
    pub fn extents_free(&self) -> u64 {
        self.extents() - self.extents_in_use()
    }

    /// The total number of extents in the volume group.
    pub fn extents(&self) -> u64 {
        self.pvs
            .values()
            .map(|x| x.pe_count)
            .sum()
    }

    // Recursively walk DM deps to see if device is present
    fn depends_on(dev: Device, dm_majors: &BTreeSet<u32>, dm: &DM) -> bool {
        if !dm_majors.contains(&dev.major) {
            return false;
        }

        if let Ok(dep_list) = dm.list_deps(dev) {
            for d in dep_list {
                if d == dev {
                    return true;
                } else if Self::depends_on(d, dm_majors, dm) {
                    return true;
                }
            }
        }

        false
    }

    /// Add a non-affiliated PV to this VG.
    pub fn add_pv(&mut self, pvh: &PvHeader) -> Result<()> {
        // Check pv is not on an LV from the vg:
        // 1) is pv's major a devicemapper major?
        // 2) Walk dm deps (equiv. of LVM2 dev_manager_device_uses_vg)
        let dm_majors = dm::dev_majors();
        let dev = try!(Device::from_str(&pvh.dev_path.to_string_lossy()));
        {
            let dm = try!(DM::new(&self));
            if Self::depends_on(dev, &dm_majors, &dm) {
                return Err(Error::new(Other, "Dependency loops prohibited"));
            }
        }

        // check pv is not already in the VG or another VG
        // Does it have text metadata??
        if let Ok(metadata) = pvh.read_metadata() {
            // Find the textmap for the vg, among all the other stuff.
            // (It's the only textmap.)
            let mut vg_name = Cow::Borrowed("<unknown>");
            for (key, value) in metadata {
                match value {
                    Entry::TextMap(_) => {
                        vg_name = Cow::Owned(key);
                        break
                    },
                    _ => {}
                }
            }

            return Err(Error::new(Other, format!("PV already in VG {}", vg_name)));
        }

        let da = try!(pvh.data_areas.get(0)
                      .ok_or(Error::new(Other, "Could not find data area in PV")));

        // figure out how many extents fit in the PV's data area
        // pe_start aligned to extent size
        let dev_size_sectors = pvh.size / SECTOR_SIZE as u64;
        let pe_start_sectors = align_to(
            (da.offset / SECTOR_SIZE as u64) as usize,
            self.extent_size as usize) as u64;
        let mda1_size_sectors = match pvh.metadata_areas.get(1) {
            Some(pvarea) => pvarea.size / SECTOR_SIZE as u64,
            None => 0,
        };
        let area_size_sectors = dev_size_sectors - pe_start_sectors - mda1_size_sectors;
        let pe_count = area_size_sectors / self.extent_size;

        let name = format!("pv{}", self.pvs.len());

        // make a PV and add it to self
        let pv = PV {
            name: name.clone(),
            id: pvh.uuid.clone(),
            device: dev,
            status: vec!["ALLOCATABLE".to_string()],
            flags: Vec::new(),
            dev_size: dev_size_sectors,
            pe_start: pe_start_sectors,
            pe_count: pe_count,
        };

        self.pvs.insert(name, pv);

        self.commit()
    }

    /// Create a new linear logical volume in the volume group.
    pub fn new_linear_lv(&mut self, name: &str, extent_size: u64) -> Result<()> {
        if self.lvs.contains_key(name) {
            return Err(Error::new(Other, "LV already exists"));
        }

        let mut contig_area = None;
        for (pvname, areas) in self.free_areas() {
            for (start, len) in areas {
                if len >= extent_size {
                    contig_area = Some((pvname, start));
                    break;
                }
            }
        }

        // we don't support multiple segments yet
        let (pv_with_area, area_start) = match contig_area {
            None => return Err(Error::new(Other, "no contiguous area for new LV")),
            Some(x) => x,
        };

        let segment = Segment {
            name: "segment1".to_string(),
            start_extent: 0,
            extent_count: extent_size,
            ty: "striped".to_string(),
            stripes: vec![(pv_with_area, area_start)],
        };

        let mut lv = LV {
            name: name.to_string(),
            id: make_uuid(),
            status: vec!["READ".to_string(),
                         "WRITE".to_string(),
                         "VISIBLE".to_string()],
            flags: Vec::new(),
            creation_host: uname().nodename().to_string(),
            creation_time: now().to_timespec().sec,
            segments: vec![segment],
            device: None,
        };

        // poke dm and tell it about a new device
        {
            let dm = try!(DM::new(self));
            try!(dm.activate_device(&mut lv));
        }

        self.lvs.insert(name.to_string(), lv);

        self.commit()
    }

    /// Destroy a logical volume.
    pub fn lv_remove(&mut self, name: &str) -> Result<()> {
        match self.lvs.remove(name) {
            None => Err(Error::new(Other, "LV not found in VG")),
            Some(mut lv) => {
                {
                    let dm = try!(DM::new(self));
                    try!(dm.deactivate_device(&mut lv));
                }

                self.commit()
            },
        }
    }

    fn commit(&mut self) -> Result<()> {
        self.seqno += 1;

        let map: LvmTextMap = self.clone().into();

        let mut disk_map = LvmTextMap::new();
        disk_map.insert("contents".to_string(),
                        Entry::String("Text Format Volume Group".to_string()));
        disk_map.insert("version".to_string(), Entry::Number(1));
        disk_map.insert("description".to_string(), Entry::String("".to_string()));
        disk_map.insert("creation_host".to_string(),
                        Entry::String(uname().nodename().to_string()));
        disk_map.insert("creation_time".to_string(),
                        Entry::Number(now().to_timespec().sec));
        disk_map.insert(self.name.clone(), Entry::TextMap(Box::new(map.clone())));

        // TODO: atomicity of updating pvs, metad, dm
        for pv in self.pvs.values() {
            if let Some(path) = pv.device.path() {
                let mut pvheader = PvHeader::find_in_dev(&path)
                    .expect("could not find pvheader");

                try!(pvheader.write_metadata(&disk_map));
            }
        }

        lvmetad::vg_update(&self.name, &map)
    }

    // Returns e.g. {"pv0": {0: 45, 47: 100, 100: 200} }
    // This means extents 0-44 are used, 45 and 46 are not,
    // 47-99 are used, then 100-199 are used.
    //
    // Adjacent used areas are not merged.
    //
    // PVs with no used areas are not in the outer map at all.
    //
    fn used_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut used_map = BTreeMap::new();

        for lv in self.lvs.values() {
            for seg in &lv.segments {
                for &(ref pvname, start) in &seg.stripes {
                    used_map.entry(pvname.to_string())
                        .or_insert(BTreeMap::new())
                        .insert(start as u64, seg.extent_count);
                }
            }
        }

        used_map
    }

    // Returns e.g. {"pv0": {45: 47, 200: 1000} }
    // (assuming pv0 has 1000 extents)
    //
    fn free_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut free_map = BTreeMap::new();

        for (pvname, mut area_map) in self.used_areas() {

            // Insert an entry to mark the end of the PV so the fold works
            // correctly
            let pv = self.pvs.get(&pvname)
                .expect("area map name refers to nonexistent PV");
            area_map.insert(pv.pe_count, 0);

            area_map.iter()
                .fold(0, |prev_end, (start, len)| {
                    if prev_end < *start {
                        free_map.entry(pvname.clone())
                            .or_insert(BTreeMap::new())
                            .insert(prev_end, start-prev_end);
                    }
                    start + len
                });
        }

        // Also return completely-unused PVs
        for (pvname, pv) in &self.pvs {
            if !free_map.contains_key(pvname) {
                let mut map = BTreeMap::new();
                map.insert(0, pv.pe_count);
                free_map.insert(pvname.clone(), map);
            }
        }

        free_map
    }
}

impl From<VG> for LvmTextMap {
    fn from(vg: VG) -> Self {
        let mut map = LvmTextMap::new();

        map.insert("id".to_string(), Entry::String(vg.id));
        map.insert("seqno".to_string(),
                   Entry::Number(vg.seqno as i64));
        map.insert("format".to_string(), Entry::String(vg.format));

        map.insert("max_pv".to_string(), Entry::Number(0));
        map.insert("max_lv".to_string(), Entry::Number(0));

        map.insert("status".to_string(),
                   Entry::List(
                       Box::new(
                           vg.status
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("flags".to_string(),
                   Entry::List(
                       Box::new(
                           vg.flags
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("extent_size".to_string(),
                   Entry::Number(vg.extent_size as i64));
        map.insert("metadata_copies".to_string(),
                   Entry::Number(vg.metadata_copies as i64));
        map.insert("physical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.pvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        if !vg.lvs.is_empty() {
            map.insert("logical_volumes".to_string(),
                       Entry::TextMap(
                           Box::new(
                               vg.lvs
                                   .into_iter()
                                   .map(|(k, v)|
                                        (k, Entry::TextMap(Box::new(v.into()))))
                                   .collect())));
        }

        map
    }
}
<commit_msg>Implement VG::create()<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Volume Groups

use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::str::FromStr;
use std::borrow::Cow;

use time::now;
use nix::sys::utsname::uname;

use lv::{LV, Segment};
use pv::{PV, Device};
use pvlabel::{PvHeader, SECTOR_SIZE};
use parser::{LvmTextMap, Entry};
use lvmetad;
use dm;
use dm::DM;
use util::{align_to, make_uuid};

const DEFAULT_EXTENT_SIZE: u64 = 8192;  // 4MiB

/// A Volume Group.
#[derive(Debug, PartialEq, Clone)]
pub struct VG {
    /// Name.
    pub name: String,
    /// Uuid.
    pub id: String,
    /// The generation of metadata this VG represents.
    pub seqno: u64,
    /// Always "LVM2".
    pub format: String,
    /// Status.
    pub status: Vec<String>,
    /// Flags.
    pub flags: Vec<String>,
    /// Size of each extent, in 512-byte sectors.
    pub extent_size: u64,
    /// Maximum number of LVs, 0 means no limit.
    pub max_lv: u64,
    /// Maximum number of PVs, 0 means no limit.
    pub max_pv: u64,
    /// How many metadata copies (?)
    pub metadata_copies: u64,
    /// Physical Volumes within this volume group.
    pub pvs: BTreeMap<String, PV>,
    /// Logical Volumes within this volume group.
    pub lvs: BTreeMap<String, LV>,
}

impl VG {
    /// Create a Volume Group from one or more initialized PvHeaders.
    pub fn create(name: &str, pvhs: Vec<PvHeader>) -> Result<VG> {
        if pvhs.len() == 0 {
            return Err(Error::new(Other, "One or more PvHeaders required"));
        }

        let metadata_areas = pvhs.iter()
            .map(|x| x.metadata_areas.len())
            .sum::<usize>();
        if metadata_areas == 0 {
            return Err(Error::new(Other, "PVs must have at least one metadata area"));
        }

        let mut vg = VG {
            name: name.to_string(),
            id: make_uuid(),
            seqno: 0,
            format: "lvm2".to_string(),
            status: vec!["READ".to_string(),
                         "WRITE".to_string(),
                         "RESIZEABLE".to_string()],
            flags: Vec::new(),
            extent_size: DEFAULT_EXTENT_SIZE,
            max_lv: 0,
            max_pv: 0,
            metadata_copies: 0,
            pvs: BTreeMap::new(),
            lvs: BTreeMap::new(),
        };

        for pv in &pvhs {
            try!(vg.add_pv(pv));
        }

        Ok(vg)
    }

    /// The total number of extents in use in the volume group.
    pub fn extents_in_use(&self) -> u64 {
        self.lvs
            .values()
            .map(|x| x.used_extents())
            .sum()
    }

    /// The total number of free extents in the volume group.
    pub fn extents_free(&self) -> u64 {
        self.extents() - self.extents_in_use()
    }

    /// The total number of extents in the volume group.
    pub fn extents(&self) -> u64 {
        self.pvs
            .values()
            .map(|x| x.pe_count)
            .sum()
    }

    // Recursively walk DM deps to see if device is present
    fn depends_on(dev: Device, dm_majors: &BTreeSet<u32>, dm: &DM) -> bool {
        if !dm_majors.contains(&dev.major) {
            return false;
        }

        if let Ok(dep_list) = dm.list_deps(dev) {
            for d in dep_list {
                if d == dev {
                    return true;
                } else if Self::depends_on(d, dm_majors, dm) {
                    return true;
                }
            }
        }

        false
    }

    /// Add a non-affiliated PV to this VG.
    pub fn add_pv(&mut self, pvh: &PvHeader) -> Result<()> {
        // Check pv is not on an LV from the vg:
        // 1) is pv's major a devicemapper major?
        // 2) Walk dm deps (equiv. of LVM2 dev_manager_device_uses_vg)
        let dm_majors = dm::dev_majors();
        let dev = try!(Device::from_str(&pvh.dev_path.to_string_lossy()));
        {
            let dm = try!(DM::new(&self));
            if Self::depends_on(dev, &dm_majors, &dm) {
                return Err(Error::new(Other, "Dependency loops prohibited"));
            }
        }

        // check pv is not already in the VG or another VG
        // Does it have text metadata??
        if let Ok(metadata) = pvh.read_metadata() {
            // Find the textmap for the vg, among all the other stuff.
            // (It's the only textmap.)
            let mut vg_name = Cow::Borrowed("<unknown>");
            for (key, value) in metadata {
                match value {
                    Entry::TextMap(_) => {
                        vg_name = Cow::Owned(key);
                        break
                    },
                    _ => {}
                }
            }

            return Err(Error::new(Other, format!("PV already in VG {}", vg_name)));
        }

        let da = try!(pvh.data_areas.get(0)
                      .ok_or(Error::new(Other, "Could not find data area in PV")));

        // figure out how many extents fit in the PV's data area
        // pe_start aligned to extent size
        let dev_size_sectors = pvh.size / SECTOR_SIZE as u64;
        let pe_start_sectors = align_to(
            (da.offset / SECTOR_SIZE as u64) as usize,
            self.extent_size as usize) as u64;
        let mda1_size_sectors = match pvh.metadata_areas.get(1) {
            Some(pvarea) => pvarea.size / SECTOR_SIZE as u64,
            None => 0,
        };
        let area_size_sectors = dev_size_sectors - pe_start_sectors - mda1_size_sectors;
        let pe_count = area_size_sectors / self.extent_size;

        let name = format!("pv{}", self.pvs.len());

        // make a PV and add it to self
        let pv = PV {
            name: name.clone(),
            id: pvh.uuid.clone(),
            device: dev,
            status: vec!["ALLOCATABLE".to_string()],
            flags: Vec::new(),
            dev_size: dev_size_sectors,
            pe_start: pe_start_sectors,
            pe_count: pe_count,
        };

        self.pvs.insert(name, pv);

        self.commit()
    }

    /// Create a new linear logical volume in the volume group.
    pub fn new_linear_lv(&mut self, name: &str, extent_size: u64) -> Result<()> {
        if self.lvs.contains_key(name) {
            return Err(Error::new(Other, "LV already exists"));
        }

        let mut contig_area = None;
        for (pvname, areas) in self.free_areas() {
            for (start, len) in areas {
                if len >= extent_size {
                    contig_area = Some((pvname, start));
                    break;
                }
            }
        }

        // we don't support multiple segments yet
        let (pv_with_area, area_start) = match contig_area {
            None => return Err(Error::new(Other, "no contiguous area for new LV")),
            Some(x) => x,
        };

        let segment = Segment {
            name: "segment1".to_string(),
            start_extent: 0,
            extent_count: extent_size,
            ty: "striped".to_string(),
            stripes: vec![(pv_with_area, area_start)],
        };

        let mut lv = LV {
            name: name.to_string(),
            id: make_uuid(),
            status: vec!["READ".to_string(),
                         "WRITE".to_string(),
                         "VISIBLE".to_string()],
            flags: Vec::new(),
            creation_host: uname().nodename().to_string(),
            creation_time: now().to_timespec().sec,
            segments: vec![segment],
            device: None,
        };

        // poke dm and tell it about a new device
        {
            let dm = try!(DM::new(self));
            try!(dm.activate_device(&mut lv));
        }

        self.lvs.insert(name.to_string(), lv);

        self.commit()
    }

    /// Destroy a logical volume.
    pub fn lv_remove(&mut self, name: &str) -> Result<()> {
        match self.lvs.remove(name) {
            None => Err(Error::new(Other, "LV not found in VG")),
            Some(mut lv) => {
                {
                    let dm = try!(DM::new(self));
                    try!(dm.deactivate_device(&mut lv));
                }

                self.commit()
            },
        }
    }

    fn commit(&mut self) -> Result<()> {
        self.seqno += 1;

        let map: LvmTextMap = self.clone().into();

        let mut disk_map = LvmTextMap::new();
        disk_map.insert("contents".to_string(),
                        Entry::String("Text Format Volume Group".to_string()));
        disk_map.insert("version".to_string(), Entry::Number(1));
        disk_map.insert("description".to_string(), Entry::String("".to_string()));
        disk_map.insert("creation_host".to_string(),
                        Entry::String(uname().nodename().to_string()));
        disk_map.insert("creation_time".to_string(),
                        Entry::Number(now().to_timespec().sec));
        disk_map.insert(self.name.clone(), Entry::TextMap(Box::new(map.clone())));

        // TODO: atomicity of updating pvs, metad, dm
        for pv in self.pvs.values() {
            if let Some(path) = pv.device.path() {
                let mut pvheader = PvHeader::find_in_dev(&path)
                    .expect("could not find pvheader");

                try!(pvheader.write_metadata(&disk_map));
            }
        }

        lvmetad::vg_update(&self.name, &map)
    }

    // Returns e.g. {"pv0": {0: 45, 47: 100, 100: 200} }
    // This means extents 0-44 are used, 45 and 46 are not,
    // 47-99 are used, then 100-199 are used.
    //
    // Adjacent used areas are not merged.
    //
    // PVs with no used areas are not in the outer map at all.
    //
    fn used_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut used_map = BTreeMap::new();

        for lv in self.lvs.values() {
            for seg in &lv.segments {
                for &(ref pvname, start) in &seg.stripes {
                    used_map.entry(pvname.to_string())
                        .or_insert(BTreeMap::new())
                        .insert(start as u64, seg.extent_count);
                }
            }
        }

        used_map
    }

    // Returns e.g. {"pv0": {45: 47, 200: 1000} }
    // (assuming pv0 has 1000 extents)
    //
    fn free_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut free_map = BTreeMap::new();

        for (pvname, mut area_map) in self.used_areas() {

            // Insert an entry to mark the end of the PV so the fold works
            // correctly
            let pv = self.pvs.get(&pvname)
                .expect("area map name refers to nonexistent PV");
            area_map.insert(pv.pe_count, 0);

            area_map.iter()
                .fold(0, |prev_end, (start, len)| {
                    if prev_end < *start {
                        free_map.entry(pvname.clone())
                            .or_insert(BTreeMap::new())
                            .insert(prev_end, start-prev_end);
                    }
                    start + len
                });
        }

        // Also return completely-unused PVs
        for (pvname, pv) in &self.pvs {
            if !free_map.contains_key(pvname) {
                let mut map = BTreeMap::new();
                map.insert(0, pv.pe_count);
                free_map.insert(pvname.clone(), map);
            }
        }

        free_map
    }
}

impl From<VG> for LvmTextMap {
    fn from(vg: VG) -> Self {
        let mut map = LvmTextMap::new();

        map.insert("id".to_string(), Entry::String(vg.id));
        map.insert("seqno".to_string(),
                   Entry::Number(vg.seqno as i64));
        map.insert("format".to_string(), Entry::String(vg.format));

        map.insert("max_pv".to_string(), Entry::Number(0));
        map.insert("max_lv".to_string(), Entry::Number(0));

        map.insert("status".to_string(),
                   Entry::List(
                       Box::new(
                           vg.status
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("flags".to_string(),
                   Entry::List(
                       Box::new(
                           vg.flags
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("extent_size".to_string(),
                   Entry::Number(vg.extent_size as i64));
        map.insert("metadata_copies".to_string(),
                   Entry::Number(vg.metadata_copies as i64));
        map.insert("physical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.pvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        if !vg.lvs.is_empty() {
            map.insert("logical_volumes".to_string(),
                       Entry::TextMap(
                           Box::new(
                               vg.lvs
                                   .into_iter()
                                   .map(|(k, v)|
                                        (k, Entry::TextMap(Box::new(v.into()))))
                                   .collect())));
        }

        map
    }
}
<|endoftext|>


<commit_before>// rustyVM - Java VM written in pure Rust
// Copyright (c) 2013 Alexander Gessler
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

// Core VM API and thread management
// (but not actual bytecode interpretation - see thread.rs for this)

use std::hashmap::{HashMap};

use std::cast::transmute_mut;

use objectbroker;
use classloader::{ClassLoader};
use object::{JavaObjectId};
use thread::{ThreadContext};

// TODO: restructure so this becomes the main crate

pub enum VMToBrokerControlMessage {
	VM_TO_BROKER_DO_SHUTDOWN,
	VM_TO_BROKER_ACK_SHUTDOWN
}

pub enum BrokerToVMControlMessage {
	BROKER_TO_VM_DID_SHUTDOWN(int /* exit_code */ ),
}

// Primary Java Virtual Machine API

// The purpose of the VM is to provide a public API to initialize and
// administrate a virtual machine.
//
// A VM has a well-defined lifecycle:
//
// CREATED -> RUNNING -> EXITED
//
// Where
//
//   CREATED occurs after a VM has been created, but run_thread()
//   has not been called yet.
//
//   RUNNING occurs after run_thread() has been called at least
//   once and persists while at least one Java thread is running
//   without the 'daemon' flag.
//
//   EXITED is the state in which the VM is placed if either
//     - the last Java thread without the 'daemon' flag terminates
//     - System.exit() is called
//     - exit() is invoked on the VM instance.
//
//   Once EXITED is reached, the only supported operation is
//

pub struct VM {
	// Duplex connection to Broker task
	//
	// reason for this not being a extra::DuplexStream: this would
	// require broker to select() on multiple ports, which is
	//   a) not possible because Port<> is a type, not a trait and
	//      there is no generalized select() that would work on
	//		DuplexStream (could have our own DuplexStream though)
	//      or ports of different types at all.
	//   b) select() is slow and increases the broker task's overhead
	priv broker_chan : SharedChan<objectbroker::ObjectBrokerMessage>,
	priv broker_port : Port<BrokerToVMControlMessage>,

	priv classloader : ClassLoader,

	// If the VM is known to have exited, this is Some() of the exit
	// value. Otherwise, this is None. See exit()
	priv exit_code : Option<int>,
}

impl VM {

	// ----------------------------------------------
	//
	//
	pub fn new(classloader : ClassLoader) -> VM {
		// construct an ObjectBroker. The broker, not the VM,
		// is the ultimate owner of all Java resources.
		let (port, chan) = Chan::new();
		VM {
			classloader : classloader,
			broker_port : port,
			broker_chan : objectbroker::ObjectBroker::new(chan).launch(),
			exit_code   : None
		}
	}

	// ----------------------------------------------
	// Spawn a new Java thread given a class, method and (optional but
	// required if the given method is an instance method) a Java object
	// to set as the *this* object for the method.
	//
	// The thread is immediately able to run, but the exact time where
	// it starts is determined by the scheduler. run_thread() returns
	// immediately and does not wait for the thread to run.
	//
	// This method can be called multiple times on a VM, but not if the
	// VM is exited. As termination of a VM can be triggered by java code,
	// this is an inherent race condition which can be checked for using
	// is_exited() and through run_thread()'s return value.
	//
	// None is returned if the VM was exited already, and Some(tid) otherwise
	// where tid is the unique identifier of the new thread.
	//
	pub fn run_thread(&mut self, class : &str, method : &str, obj : Option<JavaObjectId>) -> Option<uint> {
		// Problem: if broker is already exited, broker_chan is hung up and
		// causes propagating failure as soon as ThreadContext registers.
		//
		// Solution: the broker cannot abandon the the broker_chan until we
		// acknowledge shutdown, which is strictly after the exit code is
		// capture in self.exit_code. As race conditions on self are impossible,
		// a single check on is_exited() is sufficient.
		if self.is_exited().is_some() {
			return None;
		}

		// note: the ThreadContext immediately registers itself with the broker.
		// this prevents the VM from shutting down as the thread is non-daemon
		// by default.
		let t = ThreadContext::new(self.broker_chan.clone());
		let tid = t.get_tid();
		// TODO: setup method context etc

		// this transfers ownership into a new task, which interprets the thread code
		t.execute();

		return Some(tid);
	}

	// ----------------------------------------------
	// Exit the VM. This interrupts all threads and
	// therefore forces them to terminate.
	//
	// This is a blocking API. It returns the exit code of the Java program,
	// i.e. the value given to System.exit(), a 0 if all threads exited normally
	// and an undefined negative value if a terminal exception caused the exit.
	pub fn exit(mut self) -> int {
		self.intern_await_exit();
		self.exit_code.unwrap()
		// because we own `self`, the destructor drop() gets called
	}

	// ----------------------------------------------
	// Check if the VM has exited already (see class docs for a more detailed
	// explanation of possible lifetime states). This method is an inherent
	// race condition. The return value is None if the VM is not exited yet
	// and otherwise Some() of the exit code. See exit() for a description
	// of exit codes.
	pub fn is_exited(&self) -> Option<int> {
		if self.exit_code.is_some() {
			return self.exit_code;
		}

		// from outside view, is_exited() is a simple getter that does
		// not affect the visible behaviour of the VM. Internally,
		// is_exited() polls the broker's exit status and acknowledges
		// reception, allowing the broker to destruct itself.
		let this = unsafe { transmute_mut(self) };

		loop {
			match this.broker_port.try_recv() {
				Some(BROKER_TO_VM_DID_SHUTDOWN(code)) => {
					this.exit_code = Some(code);

					// acknowledge - this renders our broker chan and port hung up
					// but because exit_code is set we know now to use them.
					this.broker_chan.try_send(objectbroker::OB_VM_TO_BROKER(VM_TO_BROKER_ACK_SHUTDOWN));
					return this.exit_code;
				},
				// since the broker cannot hang up before we acknowledge
				// (and control would not have reached here in this case)
				// this means there is no more message.
				None => (),
			}
		}
		return None;
	}

	// IMPL

	// ----------------------------------------------
	fn intern_await_exit(&mut self) {
		if self.exit_code.is_some() {
			return;
		}

		debug!("VM: exiting");

		// send a SHUTDOWN message to the broker and wait for a SHUTDOWN
		// message as response, signalling that all threads have shut down.
		//
		// Ignore any failures happening on the way - we may be racing against
		// a Java thread calling System.exit().
		if self.broker_chan.try_send(objectbroker::OB_VM_TO_BROKER(VM_TO_BROKER_DO_SHUTDOWN)) {
			while self.is_exited().is_none() {}
		}
	}
}

// proper cleanup once the VM goes out of scope
impl Drop for VM {
	fn drop(&mut self) {
		self.intern_await_exit();
	}
}

<commit_msg>VM: exit() doc update<commit_after>// rustyVM - Java VM written in pure Rust
// Copyright (c) 2013 Alexander Gessler
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

// Core VM API and thread management
// (but not actual bytecode interpretation - see thread.rs for this)

use std::hashmap::{HashMap};

use std::cast::transmute_mut;

use objectbroker;
use classloader::{ClassLoader};
use object::{JavaObjectId};
use thread::{ThreadContext};

// TODO: restructure so this becomes the main crate

pub enum VMToBrokerControlMessage {
	VM_TO_BROKER_DO_SHUTDOWN,
	VM_TO_BROKER_ACK_SHUTDOWN
}

pub enum BrokerToVMControlMessage {
	BROKER_TO_VM_DID_SHUTDOWN(int /* exit_code */ ),
}

// Primary Java Virtual Machine API

// The purpose of the VM is to provide a public API to initialize and
// administrate a virtual machine.
//
// A VM has a well-defined lifecycle:
//
// CREATED -> RUNNING -> EXITED
//
// Where
//
//   CREATED occurs after a VM has been created, but run_thread()
//   has not been called yet.
//
//   RUNNING occurs after run_thread() has been called at least
//   once and persists while at least one Java thread is running
//   without the 'daemon' flag.
//
//   EXITED is the state in which the VM is placed if either
//     - the last Java thread without the 'daemon' flag terminates
//     - System.exit() is called
//     - exit() is invoked on the VM instance
//

pub struct VM {
	// Duplex connection to Broker task
	//
	// reason for this not being a extra::DuplexStream: this would
	// require broker to select() on multiple ports, which is
	//   a) not possible because Port<> is a type, not a trait and
	//      there is no generalized select() that would work on
	//		DuplexStream (could have our own DuplexStream though)
	//      or ports of different types at all.
	//   b) select() is slow and increases the broker task's overhead
	priv broker_chan : SharedChan<objectbroker::ObjectBrokerMessage>,
	priv broker_port : Port<BrokerToVMControlMessage>,

	priv classloader : ClassLoader,

	// If the VM is known to have exited, this is Some() of the exit
	// value. Otherwise, this is None. See exit()
	priv exit_code : Option<int>,
}

impl VM {

	// ----------------------------------------------
	//
	//
	pub fn new(classloader : ClassLoader) -> VM {
		// construct an ObjectBroker. The broker, not the VM,
		// is the ultimate owner of all Java resources.
		let (port, chan) = Chan::new();
		VM {
			classloader : classloader,
			broker_port : port,
			broker_chan : objectbroker::ObjectBroker::new(chan).launch(),
			exit_code   : None
		}
	}

	// ----------------------------------------------
	// Spawn a new Java thread given a class, method and (optional but
	// required if the given method is an instance method) a Java object
	// to set as the *this* object for the method.
	//
	// The thread is immediately able to run, but the exact time where
	// it starts is determined by the scheduler. run_thread() returns
	// immediately and does not wait for the thread to run.
	//
	// This method can be called multiple times on a VM, but not if the
	// VM is exited. As termination of a VM can be triggered by java code,
	// this is an inherent race condition which can be checked for using
	// is_exited() and through run_thread()'s return value.
	//
	// None is returned if the VM was exited already, and Some(tid) otherwise
	// where tid is the unique identifier of the new thread.
	//
	pub fn run_thread(&mut self, class : &str, method : &str, obj : Option<JavaObjectId>) -> Option<uint> {
		// Problem: if broker is already exited, broker_chan is hung up and
		// causes propagating failure as soon as ThreadContext registers.
		//
		// Solution: the broker cannot abandon the the broker_chan until we
		// acknowledge shutdown, which is strictly after the exit code is
		// capture in self.exit_code. As race conditions on self are impossible,
		// a single check on is_exited() is sufficient.
		if self.is_exited().is_some() {
			return None;
		}

		// note: the ThreadContext immediately registers itself with the broker.
		// this prevents the VM from shutting down as the thread is non-daemon
		// by default.
		let t = ThreadContext::new(self.broker_chan.clone());
		let tid = t.get_tid();
		// TODO: setup method context etc

		// this transfers ownership into a new task, which interprets the thread code
		t.execute();

		return Some(tid);
	}

	// ----------------------------------------------
	// Exit the VM. This interrupts all threads and
	// therefore forces them to terminate.
	//
	// This is a blocking API. It returns the exit code of the Java program,
	// i.e. the value given to System.exit(), a 0 if all threads exited normally
	// and an undefined negative value if a terminal exception caused the exit.
	//
	// exit() is idempotent.
	pub fn exit(mut self) -> int {
		self.intern_await_exit();
		self.exit_code.unwrap()
		// because we own `self`, the destructor drop() gets called
	}

	// ----------------------------------------------
	// Check if the VM has exited already (see class docs for a more detailed
	// explanation of possible lifetime states). This method is an inherent
	// race condition. The return value is None if the VM is not exited yet
	// and otherwise Some() of the exit code. See exit() for a description
	// of exit codes.
	pub fn is_exited(&self) -> Option<int> {
		if self.exit_code.is_some() {
			return self.exit_code;
		}

		// from outside view, is_exited() is a simple getter that does
		// not affect the visible behaviour of the VM. Internally,
		// is_exited() polls the broker's exit status and acknowledges
		// reception, allowing the broker to destruct itself.
		let this = unsafe { transmute_mut(self) };

		loop {
			match this.broker_port.try_recv() {
				Some(BROKER_TO_VM_DID_SHUTDOWN(code)) => {
					this.exit_code = Some(code);

					// acknowledge - this renders our broker chan and port hung up
					// but because exit_code is set we know now to use them.
					this.broker_chan.try_send(objectbroker::OB_VM_TO_BROKER(VM_TO_BROKER_ACK_SHUTDOWN));
					return this.exit_code;
				},
				// since the broker cannot hang up before we acknowledge
				// (and control would not have reached here in this case)
				// this means there is no more message.
				None => (),
			}
		}
		return None;
	}

	// IMPL

	// ----------------------------------------------
	fn intern_await_exit(&mut self) {
		if self.exit_code.is_some() {
			return;
		}

		debug!("VM: exiting");

		// send a SHUTDOWN message to the broker and wait for a SHUTDOWN
		// message as response, signalling that all threads have shut down.
		//
		// Ignore any failures happening on the way - we may be racing against
		// a Java thread calling System.exit().
		if self.broker_chan.try_send(objectbroker::OB_VM_TO_BROKER(VM_TO_BROKER_DO_SHUTDOWN)) {
			while self.is_exited().is_none() {}
		}
	}
}

// proper cleanup once the VM goes out of scope
impl Drop for VM {
	fn drop(&mut self) {
		self.intern_await_exit();
	}
}

<|endoftext|>


<commit_before>use std::num::FromPrimitive;

#[derive(FromPrimitive)]
pub enum Instruction {
	INTEGER = 0x00,
	STRING = 0x01,
	ADD = 0x02,
	SHOWINTEGER = 0x0A,
	SHOWVERSION = 0x0E,
	EXITVM = 0x0F
}

pub fn perin_version() -> f32{
	0.1
}

pub struct PerinVM{
	push: bool,
	stack: Vec<u8>
}

impl PerinVM{
	pub fn new() -> PerinVM{
		println!("Starting PerinVM instance");
		PerinVM{push: false, stack: vec![]}
	}
	pub fn interpreter(&mut self,bytecode: &'static str) -> (){
		for execbyte in bytecode.chars() {
			self.execute(execbyte as u8);
		}
	}
	fn execute(&mut self, execbyte: u8) -> () {
		if self.push {
			self.push(execbyte);
			self.push=false;
		}else{
			let op: Option<Instruction> = FromPrimitive::from_u8(execbyte);
			match op{
				None => {
					println!("Unknown instruction, skipping...");
				},
				Some(bc) => {
					match bc{
						Instruction::INTEGER => {
							self.push=true;
						},
						Instruction::ADD => {
							let a=self.pop() as int;
							let b=self.pop() as int;
							let c=a+b;
							self.push(c as u8);
						},
						Instruction::SHOWINTEGER => {
							println!("Integer value {}",self.pop() as int);
						},
						Instruction::SHOWVERSION => {
							println!("PerinVM v0.1.0");
						},
						Instruction::EXITVM => {
							println!("Exit VM");
						},
						Instruction::STRING => {
							println!("Unsupported instruction 'STRING' ");
						}
					}
				}
			}

		}
	}
	fn push(&mut self, value: u8) -> (){
		self.stack.push(value);
	}
	fn pop(&mut self) -> u8{
		let a: Option<u8>=self.stack.pop();
		match a{
			None => {
				println!("Failed to pop");
				0
			},
			Some(result) => {
				result
			}
		}
	}
}
<commit_msg>Using i32 instead of int<commit_after>use std::num::FromPrimitive;

#[derive(FromPrimitive)]
pub enum Instruction {
	INTEGER = 0x00,
	STRING = 0x01,
	ADD = 0x02,
	SHOWINTEGER = 0x0A,
	SHOWVERSION = 0x0E,
	EXITVM = 0x0F
}

pub fn perin_version() -> f32{
	0.1
}

pub struct PerinVM{
	push: bool,
	stack: Vec<u8>
}

impl PerinVM{
	pub fn new() -> PerinVM{
		println!("Starting PerinVM instance");
		PerinVM{push: false, stack: vec![]}
	}
	pub fn interpreter(&mut self,bytecode: &'static str) -> (){
		for execbyte in bytecode.chars() {
			self.execute(execbyte as u8);
		}
	}
	fn execute(&mut self, execbyte: u8) -> () {
		if self.push {
			self.push(execbyte);
			self.push=false;
		}else{
			let op: Option<Instruction> = FromPrimitive::from_u8(execbyte);
			match op{
				None => {
					println!("Unknown instruction, skipping...");
				},
				Some(bc) => {
					match bc{
						Instruction::INTEGER => {
							self.push=true;
						},
						Instruction::ADD => {
							let a=self.pop() as i32;
							let b=self.pop() as i32;
							let c=a+b;
							self.push(c as u8);
						},
						Instruction::SHOWINTEGER => {
							println!("Integer value {}",self.pop() as i32);
						},
						Instruction::SHOWVERSION => {
							println!("PerinVM v0.1.0");
						},
						Instruction::EXITVM => {
							println!("Exit VM");
						},
						Instruction::STRING => {
							println!("Unsupported instruction 'STRING' ");
						}
					}
				}
			}

		}
	}
	fn push(&mut self, value: u8) -> (){
		self.stack.push(value);
	}
	fn pop(&mut self) -> u8{
		let a: Option<u8>=self.stack.pop();
		match a{
			None => {
				println!("Failed to pop");
				0
			},
			Some(result) => {
				result
			}
		}
	}
}
<|endoftext|>


<commit_before>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage, DebugInfoBuilder,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let ditype = dibuilder
        .create_basic_type(
            "type_name",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::Public,
        )
        .unwrap();
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::Public,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::Public,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder
        .create_basic_type(
            "i32",
            32,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::Public,
        )
        .unwrap();
    let i64ty = dibuilder
        .create_basic_type(
            "i64",
            64,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::Public,
        )
        .unwrap();
    let f32ty = dibuilder
        .create_basic_type(
            "f32",
            32,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::Public,
        )
        .unwrap();
    let f64ty = dibuilder
        .create_basic_type(
            "f64",
            64,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::Public,
        )
        .unwrap();

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|ty| unsafe { dibuilder.create_placeholder_derived_type(&context) })
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::Public,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::Public,
            ty.as_type(),
        );
        unsafe {
            dibuilder.replace_placeholder_derived_type(*placeholder, member);
        }
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_no_explicit_finalize() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    drop(dibuilder);

    assert!(module.verify().is_ok());
}

#[llvm_versions(8.0..=latest)]
#[test]
fn test_replacing_placeholder_with_placeholder() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let i32ty = dibuilder
        .create_basic_type("i32", 32, 0x07, DIFlags::Public)
        .unwrap();
    let typedefty = dibuilder.create_typedef(
        i32ty.as_type(),
        "",
        compile_unit.get_file(),
        0,
        compile_unit.get_file().as_debug_info_scope(),
        #[cfg(not(any(feature = "llvm8-0", feature = "llvm9-0")))]
        32,
    );

    unsafe {
        let ph1 = dibuilder.create_placeholder_derived_type(&context);
        let ph2 = dibuilder.create_placeholder_derived_type(&context);

        dibuilder.replace_placeholder_derived_type(ph2, ph1);
        dibuilder.replace_placeholder_derived_type(ph1, typedefty);
    }
}

#[test]
fn test_anonymous_basic_type() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    assert_eq!(
        dibuilder.create_basic_type(
            "",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::Zero
        ),
        Err("basic types must have names")
    );
}
<commit_msg>Fix test for DIFlags naming change.<commit_after>use inkwell::context::Context;
use inkwell::debug_info::{
    AsDIScope, DIFlags, DIFlagsConstants, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage,
    DebugInfoBuilder,
};
use inkwell::module::FlagBehavior;

#[test]
fn test_smoke() {
    let context = Context::create();
    let module = context.create_module("bin");

    let debug_metadata_version = context.i32_type().const_int(3, false);
    module.add_basic_value_flag(
        "Debug Info Version",
        FlagBehavior::Warning,
        debug_metadata_version,
    );
    let builder = context.create_builder();
    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let ditype = dibuilder
        .create_basic_type(
            "type_name",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let subroutine_type = dibuilder.create_subroutine_type(
        compile_unit.get_file(),
        Some(ditype.as_type()),
        &[],
        DIFlags::PUBLIC,
    );
    let func_scope: DISubprogram<'_> = dibuilder.create_function(
        compile_unit.as_debug_info_scope(),
        "main",
        None,
        compile_unit.get_file(),
        0,
        subroutine_type,
        true,
        true,
        0,
        DIFlags::PUBLIC,
        false,
    );

    let fn_type = context.i64_type().fn_type(&[], false);
    let fn_val = module.add_function("fn_name_str", fn_type, None);
    fn_val.set_subprogram(func_scope);

    let basic_block = context.append_basic_block(fn_val, "entry");
    builder.position_at_end(basic_block);
    builder.build_return(Some(&context.i64_type().const_zero()));

    let lexical_block = dibuilder.create_lexical_block(
        func_scope.as_debug_info_scope(),
        compile_unit.get_file(),
        0,
        0,
    );

    let loc =
        dibuilder.create_debug_location(&context, 0, 0, lexical_block.as_debug_info_scope(), None);
    builder.set_current_debug_location(&context, loc);

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_struct_with_placeholders() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    // Some byte aligned integer types.
    let i32ty = dibuilder
        .create_basic_type(
            "i32",
            32,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let i64ty = dibuilder
        .create_basic_type(
            "i64",
            64,
            0x07,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let f32ty = dibuilder
        .create_basic_type(
            "f32",
            32,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();
    let f64ty = dibuilder
        .create_basic_type(
            "f64",
            64,
            0x04,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::PUBLIC,
        )
        .unwrap();

    let member_sizes = vec![32, 64, 32, 64];
    let member_types = vec![i32ty, i64ty, f32ty, f64ty];
    let member_placeholders = member_types
        .iter()
        .map(|ty| unsafe { dibuilder.create_placeholder_derived_type(&context) })
        .collect::<Vec<_>>();
    let member_placeholders_as_ditype = member_types
        .iter()
        .map(|ty| ty.as_type())
        .collect::<Vec<_>>();

    let structty = dibuilder.create_struct_type(
        compile_unit.get_file().as_debug_info_scope(),
        "",
        compile_unit.get_file(),
        0,
        192,
        8,
        DIFlags::PUBLIC,
        None,
        member_placeholders_as_ditype.as_slice(),
        0,
        None,
        "",
    );

    let mut offset = 0;
    for ((placeholder, ty), size) in member_placeholders
        .iter()
        .zip(member_types.iter())
        .zip(member_sizes.iter())
    {
        let member = dibuilder.create_member_type(
            structty.as_debug_info_scope(),
            "",
            compile_unit.get_file(),
            0,
            *size,
            8,
            offset,
            DIFlags::PUBLIC,
            ty.as_type(),
        );
        unsafe {
            dibuilder.replace_placeholder_derived_type(*placeholder, member);
        }
        offset += size;
    }

    dibuilder.finalize();

    assert!(module.verify().is_ok());
}

#[test]
fn test_no_explicit_finalize() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    drop(dibuilder);

    assert!(module.verify().is_ok());
}

#[llvm_versions(8.0..=latest)]
#[test]
fn test_replacing_placeholder_with_placeholder() {
    let context = Context::create();
    let module = context.create_module("");

    let (dibuilder, compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    let i32ty = dibuilder
        .create_basic_type("i32", 32, 0x07, DIFlags::PUBLIC)
        .unwrap();
    let typedefty = dibuilder.create_typedef(
        i32ty.as_type(),
        "",
        compile_unit.get_file(),
        0,
        compile_unit.get_file().as_debug_info_scope(),
        #[cfg(not(any(feature = "llvm8-0", feature = "llvm9-0")))]
        32,
    );

    unsafe {
        let ph1 = dibuilder.create_placeholder_derived_type(&context);
        let ph2 = dibuilder.create_placeholder_derived_type(&context);

        dibuilder.replace_placeholder_derived_type(ph2, ph1);
        dibuilder.replace_placeholder_derived_type(ph1, typedefty);
    }
}

#[test]
fn test_anonymous_basic_type() {
    let context = Context::create();
    let module = context.create_module("bin");

    let (dibuilder, _compile_unit) = module.create_debug_info_builder(
        true,
        DWARFSourceLanguage::C,
        "source_file",
        ".",
        "my llvm compiler frontend",
        false,
        "",
        0,
        "",
        DWARFEmissionKind::Full,
        0,
        false,
        false,
    );

    assert_eq!(
        dibuilder.create_basic_type(
            "",
            0_u64,
            0x00,
            #[cfg(not(feature = "llvm7-0"))]
            DIFlags::ZERO
        ),
        Err("basic types must have names")
    );
}
<|endoftext|>


<commit_before>//! Constants for use throughout the library.
//!
//! Constants include APRS-IS servers, HTTP headers, AX.25 control bytes, symbol mapping, and KISS
//! data.

use std::collections::HashMap;

/// Array of main APRS-IS servers
pub static APRSIS_SERVERS: &'static [&'static str; 2] = &["rotate.aprs.net", "noam.aprs2.net"];
/// Name of libary to present
pub static APRSIS_SW_VERSION: &'static str = "APRS_Rust_Library";

/// HTTP headers
lazy_static! {
    pub static ref APRSIS_HTTP_HEADERS: HashMap<&'static str, &'static str> = {
        let mut h: HashMap<&'static str, &'static str> = HashMap::new();
        h.insert("content-type", "application/octet-stream");
        h.insert("accept", "text/plain");
        h
    };
}

pub const APRSIS_FILTER_PORT: usize = 14580;
pub const APRSIS_RX_PORT: usize = 8080;
pub static APRSIS_URL: &'static str = "http://srvr.aprs-is.net:8080";

pub const RECV_BUFFER: usize = 1024;

pub static DEFAULT_TOCALL: &'static str = "APYT70";

/// AX.25 Flag - The flag field at each end of the frame is the bit sequence 0x7E
/// that separates each frame.
pub const AX25_FLAG: u8 = 0x7E;
/// AX.25 Control Field - This field is set to 0x03 (UI-frame).
pub const AX25_CONTROL_FIELD: u8 = 0x03;
/// AX.25 Protocol ID - This field is set to 0xF0 (no layer 3 protocol).
pub const AX25_PROTOCOL_ID: u8 = 0xF0;
/// A good place to split AX.25 address from information fields.
pub const ADDR_INFO_DELIM: &'static [u8] = &[0x03, 0xF0];

/// Data symbol map
lazy_static! {
    pub static ref DATA_TYPE_MAP: HashMap<u8, &'static str> = {
        let mut d: HashMap<u8, &'static str> = HashMap::new();
        d.insert(b'>', "status");
        d.insert(b'!', "position_nots_nomsg");
        d.insert(b'=', "position_nots_msg");
        d.insert(b'T', "telemetry");
        d.insert(b';', "object");
        d.insert(b'`', "old_mice");
        d
    };
}

/// KISS Command Codes
/// https://en.wikipedia.org/wiki/KISS_(TNC)#Command_Codes
pub const KISS_DATA_FRAME: u8 = 0x00;
<commit_msg>Comprehensive list of aprs servers. Previously was limited to rotate and noam, but there are others available.<commit_after>//! Constants for use throughout the library.
//!
//! Constants include APRS-IS servers, HTTP headers, AX.25 control bytes, symbol mapping, and KISS
//! data.

use std::collections::HashMap;

/// Array of main APRS-IS servers
pub static APRSIS_SERVERS: &'static [&'static str; 7] = &[
    "rotate.aprs.net",
    "rotate.aprs2.net",
    "noam.aprs2.net",
    "euro.aprs2.net",
    "aunz.aprs2.net",
    "soam.aprs2.net",
    "asia.aprs2.net"
];
/// Name of libary to present
pub static APRSIS_SW_VERSION: &'static str = "APRSrust";

/// HTTP headers
lazy_static! {
    pub static ref APRSIS_HTTP_HEADERS: HashMap<&'static str, &'static str> = {
        let mut h: HashMap<&'static str, &'static str> = HashMap::new();
        h.insert("content-type", "application/octet-stream");
        h.insert("accept", "text/plain");
        h
    };
}

pub const APRSIS_FILTER_PORT: usize = 14580;
pub const APRSIS_RX_PORT: usize = 8080;
pub static APRSIS_URL: &'static str = "http://srvr.aprs-is.net:8080";

pub const RECV_BUFFER: usize = 1024;

pub static DEFAULT_TOCALL: &'static str = "APYT70";

/// AX.25 Flag - The flag field at each end of the frame is the bit sequence 0x7E
/// that separates each frame.
pub const AX25_FLAG: u8 = 0x7E;
/// AX.25 Control Field - This field is set to 0x03 (UI-frame).
pub const AX25_CONTROL_FIELD: u8 = 0x03;
/// AX.25 Protocol ID - This field is set to 0xF0 (no layer 3 protocol).
pub const AX25_PROTOCOL_ID: u8 = 0xF0;
/// A good place to split AX.25 address from information fields.
pub const ADDR_INFO_DELIM: &'static [u8] = &[0x03, 0xF0];

/// Data symbol map
lazy_static! {
    pub static ref DATA_TYPE_MAP: HashMap<u8, &'static str> = {
        let mut d: HashMap<u8, &'static str> = HashMap::new();
        d.insert(b'>', "status");
        d.insert(b'!', "position_nots_nomsg");
        d.insert(b'=', "position_nots_msg");
        d.insert(b'T', "telemetry");
        d.insert(b';', "object");
        d.insert(b'`', "old_mice");
        d
    };
}

/// KISS Command Codes
/// https://en.wikipedia.org/wiki/KISS_(TNC)#Command_Codes
pub const KISS_DATA_FRAME: u8 = 0x00;
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright 2017 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

// This file contains a minimal example of using Claxon with Ogg and Hound
// to decode a flac stream inside an ogg container to a wav file. See also
// https://xiph.org/flac/ogg_mapping.html.

extern crate claxon;
extern crate hound;
extern crate ogg;

use std::env;
use std::fs::File;
use std::io;
use std::path::Path;

use claxon::input::ReadBytes;
use claxon::metadata::MetadataBlock;
use claxon::metadata::read_metadata_block_with_header;
use hound::{WavSpec, WavWriter};

fn decode_file(fname: &Path) {
    // Create a file to read from. The ogg crate will read "packets" from here.
    let file = File::open(fname).expect("failed to open ogg file");
    let bufread = io::BufReader::new(file);
    let mut preader = ogg::PacketReader::new(bufread);

    // According to the FLAC to Ogg mapping, the first packet contains the
    // streaminfo.
    let first_packet = preader.read_packet_expected().expect("failed to read ogg");

    let (header_packets_left, streaminfo) = {
        let mut cursor = io::Cursor::new(&first_packet.data);

        // The first 7 bytes contain magic values and version info. We don't
        // verify this. A real application should. Because we are using an
        // `io::Cursor`, the IO operation will not fail, so the unwrap is safe.
        cursor.skip(7).unwrap();

        // Next is a 16-bit big-endian number that specifies the number of
        // header packets that follow. Claxon exposes a `ReadBytes` trait that
        // simplifies reading this.
        let header_packets_left = cursor.read_be_u16().unwrap();

        // The 'fLaC' magic signature follows. We don't verify it.
        cursor.skip(4).unwrap();

        // Next is the streaminfo metadata block, which we return to the outer
        // scope.
        match read_metadata_block_with_header(&mut cursor) {
          Ok(MetadataBlock::StreamInfo(si)) => (header_packets_left, si),
          Ok(..) => panic!("expected streaminfo, found other metadata block"),
          Err(err) => panic!("failed to read streaminfo: {:?}", err),
        }
    };

    // Skip over the packets that contain metadata. We do decode the metadata
    // just for demonstration purposes, but then we throw it away.
    for _ in 0..header_packets_left {
        let packet = preader.read_packet_expected().expect("failed to read ogg");
        let mut cursor = io::Cursor::new(&packet.data);
        let _metadata_block = read_metadata_block_with_header(&mut cursor).unwrap();
    }

    // Build a wav writer to write the decoded audio to a wav file.
    let spec = WavSpec {
        channels: streaminfo.channels as u16,
        sample_rate: streaminfo.sample_rate,
        bits_per_sample: streaminfo.bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let opt_wav_writer = WavWriter::create(fname_wav, spec);
    let mut _wav_writer = opt_wav_writer.expect("failed to create wav file");

    // TODO: Actually read audio packets.
}

fn main() {
    for fname in env::args().skip(1) {
        decode_file(&Path::new(&fname));
    }
}
<commit_msg>Refactor handling of first packet in ogg example<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright 2017 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

// This file contains a minimal example of using Claxon with Ogg and Hound
// to decode a flac stream inside an ogg container to a wav file. See also
// https://xiph.org/flac/ogg_mapping.html.

extern crate claxon;
extern crate hound;
extern crate ogg;

use std::env;
use std::fs::File;
use std::io;
use std::path::Path;

use claxon::input::ReadBytes;
use claxon::metadata::{StreamInfo, read_metadata_block_with_header};
use hound::{WavSpec, WavWriter};

fn decode_file(fname: &Path) {
    // Create a file to read from. The ogg crate will read "packets" from here.
    let file = File::open(fname).expect("failed to open ogg file");
    let bufread = io::BufReader::new(file);
    let mut preader = ogg::PacketReader::new(bufread);

    // According to the FLAC to Ogg mapping, the first packet contains the
    // streaminfo. It also contains a count of how many metadata packets follow.
    let first_packet = preader.read_packet_expected().expect("failed to read ogg");
    let (streaminfo, header_packets_left) = read_first_packet(&first_packet);

    // Skip over the packets that contain metadata. We do decode the metadata
    // just for demonstration purposes, but then we throw it away.
    for _ in 0..header_packets_left {
        let packet = preader.read_packet_expected().expect("failed to read ogg");
        let mut cursor = io::Cursor::new(&packet.data);
        let _metadata_block = read_metadata_block_with_header(&mut cursor).unwrap();
    }

    // Build a wav writer to write the decoded audio to a wav file.
    let spec = WavSpec {
        channels: streaminfo.channels as u16,
        sample_rate: streaminfo.sample_rate,
        bits_per_sample: streaminfo.bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let opt_wav_writer = WavWriter::create(fname_wav, spec);
    let mut _wav_writer = opt_wav_writer.expect("failed to create wav file");

    // TODO: Actually read audio packets.
}

/// Decode the streaminfo block, and the number of metadata packets that still follow.
fn read_first_packet(packet: &ogg::Packet) -> (StreamInfo, u16) {
    use claxon::metadata::MetadataBlock;

    let mut cursor = io::Cursor::new(&packet.data);

    // The first 7 bytes contain magic values and version info. We don't
    // verify this. A real application should. Because we are using an
    // `io::Cursor`, the IO operation will not fail, so the unwrap is safe.
    cursor.skip(7).unwrap();

    // Next is a 16-bit big-endian number that specifies the number of header
    // packets that follow. Claxon exposes a `ReadBytes` trait that simplifies
    // reading this.
    let header_packets_left = cursor.read_be_u16().unwrap();

    // The 'fLaC' magic signature follows. We don't verify it.
    cursor.skip(4).unwrap();

    // Next is the streaminfo metadata block, which we return.
    match read_metadata_block_with_header(&mut cursor) {
      Ok(MetadataBlock::StreamInfo(si)) => (si, header_packets_left),
      Ok(..) => panic!("expected streaminfo, found other metadata block"),
      Err(err) => panic!("failed to read streaminfo: {:?}", err),
    }
}

fn main() {
    for fname in env::args().skip(1) {
        decode_file(&Path::new(&fname));
    }
}
<|endoftext|>


<commit_before>use std::rc::*;
use super::treenode::*;

///
/// Trait implemented by types that can work as a tree node index
///
pub trait TreeNodeIndex {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<T: TreeNode>(&'static self, parent_node: &'static T) -> Option<&Rc<TreeNode>>;
}

impl TreeNodeIndex for usize {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<T: TreeNode>(&'static self, parent_node: &'static T) -> Option<&Rc<TreeNode>> {
        let mut pos = *self;
        let mut current_child = parent_node.get_child_ref().to_owned();

        loop {
            match current_child {
                None        => return None,
                Some(child) => {
                    if pos == 0 { return current_child; }

                    pos = pos-1;
                    current_child = child.get_sibling_ref().to_owned();
                }
            }
        }
    }
}

///
/// Provides the ability to reference the children of a tree node by looking up a particular index
///
pub trait TreeNodeLookup : TreeNode {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<TIndex: TreeNodeIndex>(&'static self, index: TIndex) -> &TreeNode where TIndex: 'static;
}

impl<T: TreeNode> TreeNodeLookup for T {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<TIndex: TreeNodeIndex>(&'static self, index: TIndex) -> &TreeNode where TIndex: 'static {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}

/*
impl<TIndex: TreeNodeIndex> Index<TIndex> for TreeNode {
    type Output = TreeNode;

    fn index<'a>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}
*/

#[cfg(test)]
mod treenode_index_tests {
    use super::super::values::*;
    use super::super::treenode::*;
    use super::super::basictree::*;
    use std::rc::*;

    #[test]
    fn can_get_first_child() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        assert!(tree.get_child_at(0).is_some());
        assert!((tree.get_child_at(0).unwrap().get_tag()) == "child");
        assert!(tree.get_sibling_ref().is_none());
    }
}
<commit_msg>Aha, problem was that the lifetime of the reference in the *option* wasn't bound to the parent treenode so it might not have survived outside the lookup.<commit_after>use std::rc::*;
use super::treenode::*;

///
/// Trait implemented by types that can work as a tree node index
///
pub trait TreeNodeIndex {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a>(&self, parent_node: &'a TreeNode) -> Option<&'a Rc<TreeNode>>;
}

impl TreeNodeIndex for usize {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a>(&self, parent_node: &'a TreeNode) -> Option<&'a Rc<TreeNode>> {
        let mut pos = *self;
        let mut current_child = parent_node.get_child_ref().to_owned();

        loop {
            match current_child {
                None        => return None,
                Some(child) => {
                    if pos == 0 { return current_child; }

                    pos = pos-1;
                    current_child = child.get_sibling_ref().to_owned();
                }
            }
        }
    }
}

///
/// Provides the ability to reference the children of a tree node by looking up a particular index
///
pub trait TreeNodeLookup : TreeNode {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<'a, TIndex: TreeNodeIndex>(&'a self, index: TIndex) -> &'a TreeNode;
}

impl<T: TreeNode> TreeNodeLookup for T {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<'a, TIndex: TreeNodeIndex>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}

/*
impl<TIndex: TreeNodeIndex> Index<TIndex> for TreeNode {
    type Output = TreeNode;

    fn index<'a>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}
*/

#[cfg(test)]
mod treenode_index_tests {
    use super::super::treenode::*;
    use super::super::basictree::*;
    use std::rc::*;

    #[test]
    fn lookup_usize() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        let lookup = 0.lookup_index(&tree);
        assert!(lookup.is_some());
        assert!(lookup.unwrap().get_tag() == "first_child");
        assert!(tree.get_sibling_ref().is_none());
    }

    #[test]
    fn can_get_first_child() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        assert!((tree.get_child_at(0).get_tag()) == "first_child");
        assert!(tree.get_sibling_ref().is_none());
    }
}
<|endoftext|>


<commit_before>extern crate ggez;
extern crate clap;
use clap::{Arg, App};
use ggez::*;
use ggez::graphics::{DrawMode, Point2};
use ggez::event::{Keycode, Mod};

use std::env;
use std::path;

enum WindowToggle {
    NONE,
    FORWARD,
    REVERSE,
}

struct WindowSettings {
    window_size_toggle: WindowToggle,
    toggle_fullscreen: bool,
    is_fullscreen: bool,
    num_of_resolutions: usize,
    resolution_index: usize,
}

struct MainState {
    angle: f32, // in radians
    zoom: f32,
    image: graphics::Image,
    window_settings: WindowSettings,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let mut s = MainState {
            angle: 0.0,
            zoom: 1.0,
            image: graphics::Image::new(ctx, "/tile.png")?,
            window_settings: WindowSettings {
                toggle_fullscreen: false,
                window_size_toggle: WindowToggle::NONE,
                is_fullscreen: false,
                resolution_index: 0,
                num_of_resolutions: 0,
            },
        };

        let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
        s.window_settings.num_of_resolutions = resolutions.len();

        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        const DESIRED_FPS: u32 = 60;
        while timer::check_update_time(ctx, DESIRED_FPS) {
            self.angle = self.angle + 0.01;

            if self.window_settings.toggle_fullscreen {
                ggez::graphics::set_fullscreen(ctx, self.window_settings.is_fullscreen)?;
                self.window_settings.toggle_fullscreen = false;
            }

            match self.window_settings.window_size_toggle {
                WindowToggle::FORWARD | WindowToggle::REVERSE => {
                    let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
                    let (width, height) = resolutions[self.window_settings.resolution_index];

                    ggez::graphics::set_resolution(ctx, width, height)?;

                    self.window_settings.window_size_toggle = WindowToggle::NONE;
                }
                _ => {}
            }
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::BLACK);
        graphics::clear(ctx);
        let rotation = timer::get_ticks(ctx) % 1000;
        graphics::set_color(ctx, graphics::WHITE)?;
        let circle = graphics::Mesh::new_circle(ctx,
                                                DrawMode::Line(3.0),
                                                Point2::new(0.0, 0.0),
                                                100.0,
                                                4.0)?;
        graphics::draw(ctx, &self.image, Point2::new(400.0, 300.0), 0.0)?;
        graphics::draw(ctx, &circle, Point2::new(400.0, 300.0), rotation as f32)?;

        const COUNT: i32 = 10;
        for x in -COUNT..COUNT {
            for y in -COUNT..COUNT {
                const SPACING: i32 = 100;
                let fx = (x * SPACING) as f32;
                let fy = (y * SPACING) as f32;
                // println!("POS: {},{}", fx, fy);
                let r = (x as f32) / (COUNT as f32);
                let b = (y as f32) / (COUNT as f32);
                // println!("R: {}", r);
                let color = graphics::Color::new(r, 0.0, b, 1.0);
                graphics::set_color(ctx, color)?;
                graphics::rectangle(ctx, graphics::DrawMode::Fill, graphics::Rect::new(fx, fy, 5.0, 5.0))?
            }
        }
        graphics::present(ctx);
        Ok(())
    }

    fn key_up_event(&mut self, ctx: &mut Context, keycode: Keycode, _keymod: Mod, repeat: bool) {
        if !repeat {
            match keycode {
                Keycode::F => {
                    self.window_settings.toggle_fullscreen = true;
                    self.window_settings.is_fullscreen = !self.window_settings.is_fullscreen;
                }
                Keycode::H => {
                    self.window_settings.window_size_toggle = WindowToggle::FORWARD;
                    self.window_settings.resolution_index += 1;
                    self.window_settings.resolution_index %=
                        self.window_settings.num_of_resolutions;
                }
                Keycode::G => {
                    if self.window_settings.resolution_index > 0 {
                        self.window_settings.window_size_toggle = WindowToggle::REVERSE;
                        self.window_settings.resolution_index -= 1;
                        self.window_settings.resolution_index %=
                            self.window_settings.num_of_resolutions;
                    }
                },
                Keycode::Up => {
                    self.zoom += 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();

                },
                Keycode::Down => {
                    self.zoom -= 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();
                }
                _ => {}
            }
        }
    }

    fn resize_event(&mut self, ctx: &mut Context, width: u32, height: u32) {
        println!("Resized screen to {}, {}", width, height);
        // BUGGO: Should be able to return an actual error here!
        let new_rect = graphics::Rect::new(0.0,
                                           0.0,
                                           width as f32 * self.zoom,
                                           height as f32 * self.zoom);
        // graphics::set_screen_coordinates(ctx, new_rect).unwrap();
    }
}

pub fn main() {
    let matches = App::new("graphics settings example")
        .arg(Arg::with_name("msaa")
                 .short("m")
                 .value_name("N")
                 .help("Number of MSAA samples to do (powers of 2 from 1 to 16)")
                 .takes_value(true))
        .get_matches();

    let msaa: u32 = matches
        .value_of("msaa")
        .unwrap_or("1")
        .parse()
        .expect("Option msaa needs to be a number!");
    let mut c = conf::Conf::new();
    c.window_setup.samples =
        conf::NumSamples::from_u32(msaa).expect("Option msaa needs to be 1, 2, 4, 8 or 16!");
    c.window_setup.resizable = true;
    // c.window_mode.min_height = 50;
    // c.window_mode.max_height = 5000;
    // c.window_mode.min_width = 50;
    // c.window_mode.max_width = 5000;

    let ctx = &mut Context::load_from_conf("graphics_settings", "ggez", c).unwrap();

    // We add the CARGO_MANIFEST_DIR/resources do the filesystems paths so
    // we we look in the cargo project for files.
    if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        ctx.filesystem.mount(&path, true);
        println!("Adding path {:?}", path);
    } else {
        println!("not building with cargo?");
    }

    let state = &mut MainState::new(ctx).unwrap();
    event::run(ctx, state).unwrap();
}
<commit_msg>Added projection toggle to graphics_settings example<commit_after>extern crate ggez;
extern crate clap;
use clap::{Arg, App};
use ggez::*;
use ggez::graphics::{DrawMode, Point2};
use ggez::event::{Keycode, Mod};

use std::env;
use std::path;

enum WindowToggle {
    NONE,
    FORWARD,
    REVERSE,
}

struct WindowSettings {
    window_size_toggle: WindowToggle,
    toggle_fullscreen: bool,
    is_fullscreen: bool,
    num_of_resolutions: usize,
    resolution_index: usize,
    resize_projection: bool,
}

struct MainState {
    angle: f32, // in radians
    zoom: f32,
    image: graphics::Image,
    window_settings: WindowSettings,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let mut s = MainState {
            angle: 0.0,
            zoom: 1.0,
            image: graphics::Image::new(ctx, "/tile.png")?,
            window_settings: WindowSettings {
                toggle_fullscreen: false,
                window_size_toggle: WindowToggle::NONE,
                is_fullscreen: false,
                resolution_index: 0,
                num_of_resolutions: 0,
                resize_projection: false,
            },
        };

        let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
        s.window_settings.num_of_resolutions = resolutions.len();

        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        const DESIRED_FPS: u32 = 60;
        while timer::check_update_time(ctx, DESIRED_FPS) {
            self.angle = self.angle + 0.01;

            if self.window_settings.toggle_fullscreen {
                ggez::graphics::set_fullscreen(ctx, self.window_settings.is_fullscreen)?;
                self.window_settings.toggle_fullscreen = false;
            }

            match self.window_settings.window_size_toggle {
                WindowToggle::FORWARD | WindowToggle::REVERSE => {
                    let resolutions = ggez::graphics::get_fullscreen_modes(ctx, 0)?;
                    let (width, height) = resolutions[self.window_settings.resolution_index];

                    ggez::graphics::set_resolution(ctx, width, height)?;

                    self.window_settings.window_size_toggle = WindowToggle::NONE;
                }
                _ => {}
            }
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::set_background_color(ctx, graphics::BLACK);
        graphics::clear(ctx);
        let rotation = timer::get_ticks(ctx) % 1000;
        graphics::set_color(ctx, graphics::WHITE)?;
        let circle = graphics::Mesh::new_circle(ctx,
                                                DrawMode::Line(3.0),
                                                Point2::new(0.0, 0.0),
                                                100.0,
                                                4.0)?;
        graphics::draw(ctx, &self.image, Point2::new(400.0, 300.0), 0.0)?;
        graphics::draw(ctx, &circle, Point2::new(400.0, 300.0), rotation as f32)?;

        const COUNT: i32 = 10;
        for x in -COUNT..COUNT {
            for y in -COUNT..COUNT {
                const SPACING: i32 = 100;
                let fx = (x * SPACING) as f32;
                let fy = (y * SPACING) as f32;
                // println!("POS: {},{}", fx, fy);
                let r = (x as f32) / (COUNT as f32);
                let b = (y as f32) / (COUNT as f32);
                // println!("R: {}", r);
                let color = graphics::Color::new(r, 0.0, b, 1.0);
                graphics::set_color(ctx, color)?;
                graphics::rectangle(ctx, graphics::DrawMode::Fill, graphics::Rect::new(fx, fy, 5.0, 5.0))?
            }
        }
        graphics::present(ctx);
        Ok(())
    }

    fn key_up_event(&mut self, ctx: &mut Context, keycode: Keycode, _keymod: Mod, repeat: bool) {
        if !repeat {
            match keycode {
                Keycode::F => {
                    self.window_settings.toggle_fullscreen = true;
                    self.window_settings.is_fullscreen = !self.window_settings.is_fullscreen;
                }
                Keycode::H => {
                    self.window_settings.window_size_toggle = WindowToggle::FORWARD;
                    self.window_settings.resolution_index += 1;
                    self.window_settings.resolution_index %=
                        self.window_settings.num_of_resolutions;
                }
                Keycode::G => {
                    if self.window_settings.resolution_index > 0 {
                        self.window_settings.window_size_toggle = WindowToggle::REVERSE;
                        self.window_settings.resolution_index -= 1;
                        self.window_settings.resolution_index %=
                            self.window_settings.num_of_resolutions;
                    }
                },
                Keycode::Up => {
                    self.zoom += 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();

                },
                Keycode::Down => {
                    self.zoom -= 0.1;
                    println!("Zoom is now {}", self.zoom);
                    let (w, h) = graphics::get_size(ctx);
                    let new_rect = graphics::Rect::new(0.0,
                                                    0.0,
                                                    w as f32 * self.zoom,
                                                    h as f32 * self.zoom);
                    graphics::set_screen_coordinates(ctx, new_rect).unwrap();
                },
                Keycode::Space => {
                    self.window_settings.resize_projection = !self.window_settings.resize_projection;
                    println!("Resizing the projection on window resize is now: {}", self.window_settings.resize_projection);
                }
                _ => {}
            }
        }
    }

    fn resize_event(&mut self, ctx: &mut Context, width: u32, height: u32) {
        println!("Resized screen to {}, {}", width, height);
        // BUGGO: Should be able to return an actual error here!
        if self.window_settings.resize_projection {
            let new_rect = graphics::Rect::new(0.0,
                                            0.0,
                                            width as f32 * self.zoom,
                                            height as f32 * self.zoom);
            graphics::set_screen_coordinates(ctx, new_rect).unwrap();
        }
    }
}

pub fn main() {
    let matches = App::new("graphics settings example")
        .arg(Arg::with_name("msaa")
                 .short("m")
                 .value_name("N")
                 .help("Number of MSAA samples to do (powers of 2 from 1 to 16)")
                 .takes_value(true))
        .get_matches();

    let msaa: u32 = matches
        .value_of("msaa")
        .unwrap_or("1")
        .parse()
        .expect("Option msaa needs to be a number!");
    let mut c = conf::Conf::new();
    c.window_setup.samples =
        conf::NumSamples::from_u32(msaa).expect("Option msaa needs to be 1, 2, 4, 8 or 16!");
    c.window_setup.resizable = true;

    let ctx = &mut Context::load_from_conf("graphics_settings", "ggez", c).unwrap();

    // We add the CARGO_MANIFEST_DIR/resources do the filesystems paths so
    // we we look in the cargo project for files.
    if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        ctx.filesystem.mount(&path, true);
        println!("Adding path {:?}", path);
    } else {
        println!("not building with cargo?");
    }

    let state = &mut MainState::new(ctx).unwrap();
    event::run(ctx, state).unwrap();
}
<|endoftext|>


<commit_before>use bit_vec::BitVec;
use std::slice::Iter;
use lfsr;

#[derive(PartialEq, Debug)]
pub struct FibonacciLFSR {
    state: BitVec,
    taps: Vec<usize>,
}

impl FibonacciLFSR {
    pub fn from_iter(iter: Iter<usize>) -> Self {
        let &len = iter.clone().max().unwrap();

        let state = BitVec::from_elem(len, true);

        let mut taps: Vec<usize> = iter.map(|&t| t).collect();
        taps.sort();
        taps.dedup();

        FibonacciLFSR { state: state, taps: taps, }
    }

    fn shift(&mut self) {
        lfsr::shift(&mut self.state);
    }

    fn feedback_bit(&mut self) -> bool {
        self.taps
            .iter()
            .map(|&i| self.state[i-1])
            .fold(false, |acc, b| acc ^ b)
    }

    pub fn iter(&mut self) -> lfsr::LFSRIter<FibonacciLFSR> {
        lfsr::LFSRIter { lfsr: self }
    }
}

impl lfsr::LFSR for FibonacciLFSR {
    fn output(&self) -> bool {
        let len = self.state.len();
        self.state[len - 1]
    }

    fn step(&mut self) {
        let b = self.feedback_bit();

        self.shift();

        self.state.set(0, b);
    }
}
<commit_msg>Whitespace nit<commit_after>use bit_vec::BitVec;
use std::slice::Iter;
use lfsr;

#[derive(PartialEq, Debug)]
pub struct FibonacciLFSR {
    state: BitVec,
    taps: Vec<usize>,
}

impl FibonacciLFSR {
    pub fn from_iter(iter: Iter<usize>) -> Self {
        let &len = iter.clone().max().unwrap();

        let state = BitVec::from_elem(len, true);

        let mut taps: Vec<usize> = iter.map(|&t| t).collect();
        taps.sort();
        taps.dedup();

        FibonacciLFSR { state: state, taps: taps, }
    }

    fn shift(&mut self) {
        lfsr::shift(&mut self.state);
    }

    fn feedback_bit(&mut self) -> bool {
        self.taps
            .iter()
            .map(|&i| self.state[i - 1])
            .fold(false, |acc, b| acc ^ b)
    }

    pub fn iter(&mut self) -> lfsr::LFSRIter<FibonacciLFSR> {
        lfsr::LFSRIter { lfsr: self }
    }
}

impl lfsr::LFSR for FibonacciLFSR {
    fn output(&self) -> bool {
        let len = self.state.len();
        self.state[len - 1]
    }

    fn step(&mut self) {
        let b = self.feedback_bit();

        self.shift();

        self.state.set(0, b);
    }
}
<|endoftext|>