<commit_before>use gtk::{ self, Window as GTKWindow, WindowType, WidgetExt,
           Inhibit, Widget, Menu, MenuShellExt };
use libappindicator::{AppIndicator,
                      AppIndicatorStatus};
use std::cell::{RefCell};
use std::collections::HashMap;
use {SystrayEvent, SystrayError};
use glib;
use std;
use std::thread;
use std::sync::mpsc::{channel, Sender};

// Gtk specific struct that will live only in the Gtk thread, since a lot of the
// base types involved don't implement Send (for good reason).
pub struct GtkSystrayApp {
    menu: gtk::Menu,
    ai: AppIndicator,
    menu_items: RefCell<HashMap<u32, gtk::MenuItem>>,
    event_tx: Sender<SystrayEvent>
}

thread_local!(static GTK_STASH: RefCell<Option<GtkSystrayApp>> = RefCell::new(None));

pub struct MenuItemInfo {
    mid: u32,
    title: String,
    tooltip: String,
    disabled: bool,
    checked: bool
}

impl GtkSystrayApp {
    pub fn new(event_tx: Sender<SystrayEvent>) -> Result<GtkSystrayApp, SystrayError> {
        if let Err(e) = gtk::init() {
            return Err(SystrayError::OsError(format!("{}", "Gtk init error!")));
        }
        let mut m = gtk::Menu::new();
        let mut ai = AppIndicator::new("", "");
        ai.set_status(AppIndicatorStatus::APP_INDICATOR_STATUS_ACTIVE);
        ai.set_menu(&mut m);
        Ok(GtkSystrayApp {
            menu: m,
            ai: ai,
            menu_items: RefCell::new(HashMap::new()),
            event_tx: event_tx
        })
    }

    pub fn add_menu_entry(&self, item_name: &String) {
        // MenuItemInfo *mii = (MenuItemInfo*)data;
	      // GList* it;
	      // for(it = global_menu_items; it != NULL; it = it->next) {
		    //     MenuItemNode* item = (MenuItemNode*)(it->data);
		    //     if(item->menu_id == mii->menu_id){
			  //         gtk_menu_item_set_label(GTK_MENU_ITEM(item->menu_item), mii->title);
			  //         break;
		    //     }
	      // }
        let m = gtk::MenuItem::new_with_label("test");
        self.menu.append(&m);
        self.menu.show_all();
        //self.menu_items.insert(self.menu_idx, m);
	      // // menu id doesn't exist, add new item
	      // if(it == NULL) {
		    //     GtkWidget *menu_item = gtk_menu_item_new_with_label(mii->title);
		    //     int *id = malloc(sizeof(int));
		    //     *id = mii->menu_id;
		    //     g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(_systray_menu_item_selected), id);
		    //     gtk_menu_shell_append(GTK_MENU_SHELL(global_tray_menu), menu_item);

		    //     MenuItemNode* new_item = malloc(sizeof(MenuItemNode));
		    //     new_item->menu_id = mii->menu_id;
		    //     new_item->menu_item = menu_item;
		    //     GList* new_node = malloc(sizeof(GList));
		    //     new_node->data = new_item;
		    //     new_node->next = global_menu_items;
		    //     if(global_menu_items != NULL) {
			  //         global_menu_items->prev = new_node;
		    //     }
		    //     global_menu_items = new_node;
		    //     it = new_node;
	      // }
	      // GtkWidget * menu_item = GTK_WIDGET(((MenuItemNode*)(it->data))->menu_item);
	      // gtk_widget_set_sensitive(menu_item, mii->disabled == 1 ? FALSE : TRUE);
	      // gtk_widget_show_all(global_tray_menu);

	      // free(mii->title);
	      // free(mii->tooltip);
	      // free(mii);
        // return FALSE;
    }
}

pub struct Window {
    gtk_loop: Option<thread::JoinHandle<()>>
}

type Callback = Box<(Fn(&GtkSystrayApp) -> () + 'static)>;

// Convenience function to clean up thread local unwrapping
fn run_on_gtk_thread<F>(f: F)
    where F: std::ops::Fn(&GtkSystrayApp) -> () + Send + 'static {
    // Note this is glib, not gtk. Calling gtk::idle_add will panic us due to
    // being on different threads. glib::idle_add can run across threads.
    glib::idle_add(move || {
        GTK_STASH.with(|stash| {
            let stash = stash.borrow();
            let stash = stash.as_ref();
            if let Some(stash) = stash {
                f(stash);
            }
        });
        gtk::Continue(false)
    });
}

impl Window {
    pub fn new(event_tx: Sender<SystrayEvent>) -> Result<Window, SystrayError> {
        let (tx, rx) = channel();
        let gtk_loop = thread::spawn(move || {
            GTK_STASH.with(|stash| {
                match GtkSystrayApp::new(event_tx) {
                    Ok(data) => {
                        (*stash.borrow_mut()) = Some(data);
                        tx.send(Ok(()));
                    }
                    Err(e) => {
                        tx.send(Err(e));
                        return;
                    }
                }
            });
            gtk::main();
        });
        match rx.recv().unwrap() {
            Ok(()) => Ok(Window {
                gtk_loop: Some(gtk_loop)
            }),
            Err(e) => {
                Err(e)
            }
        }
    }

    pub fn add_menu_entry(&self, item_name: &String) -> Result<u32, SystrayError> {
        let n = item_name.clone();
        run_on_gtk_thread(move |stash : &GtkSystrayApp| {
            stash.add_menu_entry(&n);
        });
        Ok(0)
    }

    pub fn add_menu_seperator(&self) -> Result<u32, SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn set_icon_from_file(&self, file: &str) -> Result<(), SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn set_icon_from_resource(&self, resource: &str) -> Result<(), SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn shutdown(&self) -> Result<(), SystrayError> {
        Ok(())
    }

    pub fn set_tooltip(&self, tooltip: &str) -> Result<(), SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn quit(&self) {
        panic!("Not implemented on this platform!");
    }

}
<commit_msg>feat: Add actual menu item title setting, quit function<commit_after>use gtk::{ self, Window as GTKWindow, WindowType, WidgetExt,
           Inhibit, Widget, Menu, MenuShellExt };
use libappindicator::{AppIndicator,
                      AppIndicatorStatus};
use std::cell::{RefCell};
use std::collections::HashMap;
use {SystrayEvent, SystrayError};
use glib;
use std;
use std::thread;
use std::sync::mpsc::{channel, Sender};

// Gtk specific struct that will live only in the Gtk thread, since a lot of the
// base types involved don't implement Send (for good reason).
pub struct GtkSystrayApp {
    menu: gtk::Menu,
    ai: AppIndicator,
    menu_items: RefCell<HashMap<u32, gtk::MenuItem>>,
    event_tx: Sender<SystrayEvent>
}

thread_local!(static GTK_STASH: RefCell<Option<GtkSystrayApp>> = RefCell::new(None));

pub struct MenuItemInfo {
    mid: u32,
    title: String,
    tooltip: String,
    disabled: bool,
    checked: bool
}

impl GtkSystrayApp {
    pub fn new(event_tx: Sender<SystrayEvent>) -> Result<GtkSystrayApp, SystrayError> {
        if let Err(e) = gtk::init() {
            return Err(SystrayError::OsError(format!("{}", "Gtk init error!")));
        }
        let mut m = gtk::Menu::new();
        let mut ai = AppIndicator::new("", "");
        ai.set_status(AppIndicatorStatus::APP_INDICATOR_STATUS_ACTIVE);
        ai.set_menu(&mut m);
        Ok(GtkSystrayApp {
            menu: m,
            ai: ai,
            menu_items: RefCell::new(HashMap::new()),
            event_tx: event_tx
        })
    }

    pub fn add_menu_entry(&self, item_name: &String) {
        // MenuItemInfo *mii = (MenuItemInfo*)data;
	      // GList* it;
	      // for(it = global_menu_items; it != NULL; it = it->next) {
		    //     MenuItemNode* item = (MenuItemNode*)(it->data);
		    //     if(item->menu_id == mii->menu_id){
			  //         gtk_menu_item_set_label(GTK_MENU_ITEM(item->menu_item), mii->title);
			  //         break;
		    //     }
	      // }
        let m = gtk::MenuItem::new_with_label(item_name);
        self.menu.append(&m);
        self.menu.show_all();
        //self.menu_items.insert(self.menu_idx, m);
	      // // menu id doesn't exist, add new item
	      // if(it == NULL) {
		    //     GtkWidget *menu_item = gtk_menu_item_new_with_label(mii->title);
		    //     int *id = malloc(sizeof(int));
		    //     *id = mii->menu_id;
		    //     g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(_systray_menu_item_selected), id);
		    //     gtk_menu_shell_append(GTK_MENU_SHELL(global_tray_menu), menu_item);

		    //     MenuItemNode* new_item = malloc(sizeof(MenuItemNode));
		    //     new_item->menu_id = mii->menu_id;
		    //     new_item->menu_item = menu_item;
		    //     GList* new_node = malloc(sizeof(GList));
		    //     new_node->data = new_item;
		    //     new_node->next = global_menu_items;
		    //     if(global_menu_items != NULL) {
			  //         global_menu_items->prev = new_node;
		    //     }
		    //     global_menu_items = new_node;
		    //     it = new_node;
	      // }
	      // GtkWidget * menu_item = GTK_WIDGET(((MenuItemNode*)(it->data))->menu_item);
	      // gtk_widget_set_sensitive(menu_item, mii->disabled == 1 ? FALSE : TRUE);
	      // gtk_widget_show_all(global_tray_menu);

	      // free(mii->title);
	      // free(mii->tooltip);
	      // free(mii);
        // return FALSE;
    }
}

pub struct Window {
    gtk_loop: Option<thread::JoinHandle<()>>
}

type Callback = Box<(Fn(&GtkSystrayApp) -> () + 'static)>;

// Convenience function to clean up thread local unwrapping
fn run_on_gtk_thread<F>(f: F)
    where F: std::ops::Fn(&GtkSystrayApp) -> () + Send + 'static {
    // Note this is glib, not gtk. Calling gtk::idle_add will panic us due to
    // being on different threads. glib::idle_add can run across threads.
    glib::idle_add(move || {
        GTK_STASH.with(|stash| {
            let stash = stash.borrow();
            let stash = stash.as_ref();
            if let Some(stash) = stash {
                f(stash);
            }
        });
        gtk::Continue(false)
    });
}

impl Window {
    pub fn new(event_tx: Sender<SystrayEvent>) -> Result<Window, SystrayError> {
        let (tx, rx) = channel();
        let gtk_loop = thread::spawn(move || {
            GTK_STASH.with(|stash| {
                match GtkSystrayApp::new(event_tx) {
                    Ok(data) => {
                        (*stash.borrow_mut()) = Some(data);
                        tx.send(Ok(()));
                    }
                    Err(e) => {
                        tx.send(Err(e));
                        return;
                    }
                }
            });
            gtk::main();
        });
        match rx.recv().unwrap() {
            Ok(()) => Ok(Window {
                gtk_loop: Some(gtk_loop)
            }),
            Err(e) => {
                Err(e)
            }
        }
    }

    pub fn add_menu_entry(&self, item_name: &String) -> Result<u32, SystrayError> {
        let n = item_name.clone();
        run_on_gtk_thread(move |stash : &GtkSystrayApp| {
            stash.add_menu_entry(&n);
        });
        Ok(0)
    }

    pub fn add_menu_seperator(&self) -> Result<u32, SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn set_icon_from_file(&self, file: &str) -> Result<(), SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn set_icon_from_resource(&self, resource: &str) -> Result<(), SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn shutdown(&self) -> Result<(), SystrayError> {
        Ok(())
    }

    pub fn set_tooltip(&self, tooltip: &str) -> Result<(), SystrayError> {
        panic!("Not implemented on this platform!");
    }

    pub fn quit(&self) {
        glib::idle_add(|| {
            gtk::main_quit();
            glib::Continue(false)
        });
    }

}
<|endoftext|>


<commit_before>extern crate gstreamer as gst;

use std::mem;

use std::sync::{Arc, Mutex};

use super::{AudioBuffer, SampleExtractor};

// The DoubleBuffer is reponsible for ensuring a thread safe double buffering
// mechanism that receives samples from GStreamer, prepares an extraction of
// these samples and presents the most recent extraction to an external
// mechanism (e.g. UI).
// The DoubleBuffer hosts two SampleExtractors and an AudioBuffer:
//   - The SampleExtractor trait is designed to allow the extraction of samples
//   depending on certains conditions as defined in its concrete implementation.
//   - The AudioBuffer manages the container for all the samples received.
// The DoubleBuffer prepares the extraction in the working_buffer and exposes
// the exposed_buffer during that time. When the extration is done, the buffers
// are swapped.
pub struct DoubleAudioBuffer {
    audio_buffer: AudioBuffer,
    exposed_buffer_mtx: Arc<Mutex<Box<SampleExtractor>>>,
    working_buffer: Option<Box<SampleExtractor>>,
    first_sample_to_keep: usize,
}

impl DoubleAudioBuffer {
    // need 2 arguments for new as we can't clone buffers as they are known
    // as trait SampleExtractor
    pub fn new(
        buffer_duration: u64,
        exposed_buffer: Box<SampleExtractor>,
        working_buffer: Box<SampleExtractor>
    ) -> DoubleAudioBuffer {
        DoubleAudioBuffer {
            audio_buffer: AudioBuffer::new(buffer_duration),
            exposed_buffer_mtx: Arc::new(Mutex::new(exposed_buffer)),
            working_buffer: Some(working_buffer),
            first_sample_to_keep: 0,
        }
    }

    // Get a reference on the exposed buffer mutex.
    pub fn get_exposed_buffer_mtx(&self) -> Arc<Mutex<Box<SampleExtractor>>> {
        Arc::clone(&self.exposed_buffer_mtx)
    }

    pub fn cleanup(&mut self) {
        self.audio_buffer.cleanup();

        {
            let exposed_buffer = &mut self.exposed_buffer_mtx.lock()
                .expect("DoubleAudioBuffer: couldn't lock exposed_buffer_mtx while setting audio sink");
            exposed_buffer.cleanup();
        }

        self.working_buffer.as_mut()
            .expect("DoubleAudioBuffer: couldn't get working_buffer while setting audio sink")
            .cleanup();
        self.first_sample_to_keep = 0;
    }

    // Initialize buffer with audio stream capabilities
    // and GStreamer element for position reference
    pub fn set_audio_caps_and_ref(&mut self,
        caps: &gst::Caps,
        audio_ref: &gst::Element
    ) {
        self.audio_buffer.set_caps(caps);

        {
            let exposed_buffer = &mut self.exposed_buffer_mtx.lock()
                .expect("DoubleAudioBuffer: couldn't lock exposed_buffer_mtx while setting audio sink");
            exposed_buffer.set_audio_sink(audio_ref.clone());
        }

        self.working_buffer.as_mut()
            .expect("DoubleAudioBuffer: couldn't get working_buffer while setting audio sink")
            .set_audio_sink(audio_ref.clone());
    }

    pub fn handle_eos(&mut self) {
        self.audio_buffer.handle_eos();
        // extract last samples and swap
        self.extract_samples();
        // update second buffer too
        self.extract_samples();
    }

    pub fn push_gst_sample(&mut self, sample: gst::Sample) {
        // store incoming samples
        self.audio_buffer.push_gst_sample(sample, self.first_sample_to_keep);

        // extract new samples and swap
        self.extract_samples();
    }

    // Update the working extractor with new samples and swap.
    pub fn extract_samples(&mut self) {
        let mut working_buffer = self.working_buffer.take()
            .expect("DoubleSampleExtractor: failed to take working buffer while updating");
        working_buffer.extract_samples(&self.audio_buffer);

        // swap buffers
        {
            let exposed_buffer_box = &mut *self.exposed_buffer_mtx.lock()
                .expect("DoubleSampleExtractor: failed to lock the exposed buffer for swap");
            // get latest conditions from the previously exposed buffer
            // in order to smoothen rendering between frames
            working_buffer.update_concrete_state(exposed_buffer_box);
            mem::swap(exposed_buffer_box, &mut working_buffer);
        }

        self.first_sample_to_keep = working_buffer.get_first_sample();

        self.working_buffer = Some(working_buffer);
        // self.working_buffer is now the buffer previously in
        // self.exposed_buffer_mtx
    }

    // Refresh the working buffer with current conditions and swap.
    pub fn refresh(&mut self) {
        let mut working_buffer = self.working_buffer.take()
            .expect("DoubleSampleExtractor: failed to take working buffer while updating");

        // get latest conditions
        {
            let exposed_buffer_box = &mut *self.exposed_buffer_mtx.lock()
                .expect("DoubleSampleExtractor: failed to lock the exposed buffer for swap");
            // get latest conditions from the previously exposed buffer
            working_buffer.update_concrete_state(exposed_buffer_box);
        }

        // refresh working buffer
        working_buffer.refresh(&self.audio_buffer);

        // swap buffers
        {
            let exposed_buffer_box = &mut *self.exposed_buffer_mtx.lock()
                .expect("DoubleSampleExtractor: failed to lock the exposed buffer for swap");
            // get latest conditions from the previously exposed buffer
            // in order to smoothen rendering between frames
            working_buffer.update_concrete_state(exposed_buffer_box);
            mem::swap(exposed_buffer_box, &mut working_buffer);
        }

        self.first_sample_to_keep = working_buffer.get_first_sample();

        self.working_buffer = Some(working_buffer);
        // self.working_buffer is now the buffer previously in
        // self.exposed_buffer_mtx
    }
}
<commit_msg>DoubleAudioBuffer: simplify refresh (#35) Refresh will be triggered from the exposed buffer side. This means that there is no reason to limit the lock on the exposed buffer since caller is already locked waiting for the refresh to complete.<commit_after>extern crate gstreamer as gst;

use std::mem;

use std::sync::{Arc, Mutex};

use super::{AudioBuffer, SampleExtractor};

// The DoubleBuffer is reponsible for ensuring a thread safe double buffering
// mechanism that receives samples from GStreamer, prepares an extraction of
// these samples and presents the most recent extraction to an external
// mechanism (e.g. UI).
// The DoubleBuffer hosts two SampleExtractors and an AudioBuffer:
//   - The SampleExtractor trait is designed to allow the extraction of samples
//   depending on certains conditions as defined in its concrete implementation.
//   - The AudioBuffer manages the container for all the samples received.
// The DoubleBuffer prepares the extraction in the working_buffer and exposes
// the exposed_buffer during that time. When the extration is done, the buffers
// are swapped.
pub struct DoubleAudioBuffer {
    audio_buffer: AudioBuffer,
    exposed_buffer_mtx: Arc<Mutex<Box<SampleExtractor>>>,
    working_buffer: Option<Box<SampleExtractor>>,
    first_sample_to_keep: usize,
}

impl DoubleAudioBuffer {
    // need 2 arguments for new as we can't clone buffers as they are known
    // as trait SampleExtractor
    pub fn new(
        buffer_duration: u64,
        exposed_buffer: Box<SampleExtractor>,
        working_buffer: Box<SampleExtractor>
    ) -> DoubleAudioBuffer {
        DoubleAudioBuffer {
            audio_buffer: AudioBuffer::new(buffer_duration),
            exposed_buffer_mtx: Arc::new(Mutex::new(exposed_buffer)),
            working_buffer: Some(working_buffer),
            first_sample_to_keep: 0,
        }
    }

    // Get a reference on the exposed buffer mutex.
    pub fn get_exposed_buffer_mtx(&self) -> Arc<Mutex<Box<SampleExtractor>>> {
        Arc::clone(&self.exposed_buffer_mtx)
    }

    pub fn cleanup(&mut self) {
        self.audio_buffer.cleanup();

        {
            let exposed_buffer = &mut self.exposed_buffer_mtx.lock()
                .expect("DoubleAudioBuffer: couldn't lock exposed_buffer_mtx while setting audio sink");
            exposed_buffer.cleanup();
        }

        self.working_buffer.as_mut()
            .expect("DoubleAudioBuffer: couldn't get working_buffer while setting audio sink")
            .cleanup();
        self.first_sample_to_keep = 0;
    }

    // Initialize buffer with audio stream capabilities
    // and GStreamer element for position reference
    pub fn set_audio_caps_and_ref(&mut self,
        caps: &gst::Caps,
        audio_ref: &gst::Element
    ) {
        self.audio_buffer.set_caps(caps);

        {
            let exposed_buffer = &mut self.exposed_buffer_mtx.lock()
                .expect("DoubleAudioBuffer: couldn't lock exposed_buffer_mtx while setting audio sink");
            exposed_buffer.set_audio_sink(audio_ref.clone());
        }

        self.working_buffer.as_mut()
            .expect("DoubleAudioBuffer: couldn't get working_buffer while setting audio sink")
            .set_audio_sink(audio_ref.clone());
    }

    pub fn handle_eos(&mut self) {
        self.audio_buffer.handle_eos();
        // extract last samples and swap
        self.extract_samples();
        // update second buffer too
        self.extract_samples();
    }

    pub fn push_gst_sample(&mut self, sample: gst::Sample) {
        // store incoming samples
        self.audio_buffer.push_gst_sample(sample, self.first_sample_to_keep);

        // extract new samples and swap
        self.extract_samples();
    }

    // Update the working extractor with new samples and swap.
    pub fn extract_samples(&mut self) {
        let mut working_buffer = self.working_buffer.take()
            .expect("DoubleAudioBuffer::extract_samples: failed to take working buffer");
        working_buffer.extract_samples(&self.audio_buffer);

        // swap buffers
        {
            let exposed_buffer_box = &mut *self.exposed_buffer_mtx.lock()
                .expect("DoubleAudioBuffer::extract_samples: failed to lock the exposed buffer");
            // get latest conditions from the previously exposed buffer
            // in order to smoothen rendering between frames
            working_buffer.update_concrete_state(exposed_buffer_box);
            mem::swap(exposed_buffer_box, &mut working_buffer);
        }

        self.first_sample_to_keep = working_buffer.get_first_sample();

        self.working_buffer = Some(working_buffer);
        // self.working_buffer is now the buffer previously in
        // self.exposed_buffer_mtx
    }

    // Refresh the working buffer with current conditions and swap.
    pub fn refresh(&mut self) {
        let mut working_buffer = self.working_buffer.take()
            .expect("DoubleAudioBuffer::refresh: failed to take working buffer");

        {
            let exposed_buffer_box = &mut *self.exposed_buffer_mtx.lock()
                .expect("DoubleAudioBuffer:::refresh: failed to lock the exposed buffer");
            // get latest conditions from the previously exposed buffer
            working_buffer.update_concrete_state(exposed_buffer_box);

            // refresh working buffer
            working_buffer.refresh(&self.audio_buffer);

            // swap buffers
            mem::swap(exposed_buffer_box, &mut working_buffer);
        }

        self.first_sample_to_keep = working_buffer.get_first_sample();

        self.working_buffer = Some(working_buffer);
        // self.working_buffer is now the buffer previously in
        // self.exposed_buffer_mtx
    }
}
<|endoftext|>


<commit_before>//! # ADC module
//!
//! This module provides access to the ADC of the stm32f0 board.
//! You can:
//!
//! * configure a PIN in Input
//! * read the analog value from the PIN
//!
//! ## Examples
//!
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::adc;
//!
//! let p = adc::Input::setup(adc::Pin::P4);
//! let b = p.read();
//! ```

use cortex_m;
use stm32f0x2::{ADC, GPIOA, GPIOC, RCC};

/// ADC Channel
pub enum Channel {
    ADC0,
    ADC1,
    ADC13,
    ADC14,
}

/// Input Mode Pin
pub struct Analog {
    pin: Channel,
}
impl Analog {
    /// Setup a PIN in Input Mode
    pub fn setup(pin: Channel) -> Analog {
        setup_pin(&pin);
        Analog { pin }
    }
    /// Read the analog value of a PIN
    pub fn read(&self) -> u16 {
        cortex_m::interrupt::free(|cs| {
            let adc = ADC.borrow(cs);

            // ADC Channel selection
            match self.pin {
                Channel::ADC0 => adc.chselr.write(|w| w.chsel0().set_bit()),
                Channel::ADC1 => adc.chselr.write(|w| w.chsel1().set_bit()),
                Channel::ADC13 => adc.chselr.write(|w| w.chsel13().set_bit()),
                Channel::ADC14 => adc.chselr.write(|w| w.chsel14().set_bit()),
            }

            // Active ADC and Start Conversion
            adc.cr.write(|w| w.aden().set_bit().adstart().set_bit());

            // Wait end of conversation
            while adc.isr.read().eoc().bit_is_clear() {}

            // Return result
            adc.dr.read().data().bits()
        })
    }
}

fn setup_pin(pin: &Channel) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let gpioc = GPIOC.borrow(cs);
        let gpioa = GPIOA.borrow(cs);
        // Clock Activation
        match *pin {
            Channel::ADC0 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Channel::ADC1 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Channel::ADC13 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
            Channel::ADC14 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
        }

        // Clock activation ADC
        rcc.apb2enr.modify(|_, w| w.adcen().enabled());

        // PA Analog Input Channel
        match *pin {
            Channel::ADC0 => gpioa.moder.modify(|_, w| w.moder0().analog()),
            Channel::ADC1 => gpioa.moder.modify(|_, w| w.moder1().analog()),
            Channel::ADC13 => gpioc.moder.modify(|_, w| w.moder3().analog()),
            Channel::ADC14 => gpioc.moder.modify(|_, w| w.moder4().analog()),
        }
    });
}
<commit_msg>renaming channel to pin renaming ADC to PA or PC<commit_after>//! # ADC module
//!
//! This module provides access to the ADC of the stm32f0 board.
//! You can:
//!
//! * configure a PIN in Input
//! * read the analog value from the PIN
//!
//! ## Examples
//!
//! ```
//! extern crate stm32f0_hal;
//!
//! use stm32f0_hal::adc;
//!
//! let p = adc::Input::setup(adc::Pin::P4);
//! let b = p.read();
//! ```

use cortex_m;
use stm32f0x2::{ADC, GPIOA, GPIOC, RCC};

/// ADC Pin
pub enum Pin {
    PA0,
    PA1,
    PC13,
    PC14,
}

/// Input Mode Pin
pub struct Analog {
    pin: Pin,
}
impl Analog {
    /// Setup a PIN in Input Mode
    pub fn setup(pin: Pin) -> Analog {
        setup_pin(&pin);
        Analog { pin }
    }
    /// Read the analog value of a PIN
    pub fn read(&self) -> u16 {
        cortex_m::interrupt::free(|cs| {
            let adc = ADC.borrow(cs);

            // ADC Pin selection
            match self.pin {
                Pin::PA0 => adc.chselr.write(|w| w.chsel0().set_bit()),
                Pin::PA1 => adc.chselr.write(|w| w.chsel1().set_bit()),
                Pin::PC13 => adc.chselr.write(|w| w.chsel13().set_bit()),
                Pin::PC14 => adc.chselr.write(|w| w.chsel14().set_bit()),
            }

            // Active ADC and Start Conversion
            adc.cr.write(|w| w.aden().set_bit().adstart().set_bit());

            // Wait end of conversation
            while adc.isr.read().eoc().bit_is_clear() {}

            // Return result
            adc.dr.read().data().bits()
        })
    }
}

fn setup_pin(pin: &Pin) {
    cortex_m::interrupt::free(|cs| {
        let rcc = RCC.borrow(cs);
        let gpioa = GPIOA.borrow(cs);
        let gpioc = GPIOC.borrow(cs);
        // Clock Activation
        match *pin {
            Pin::PA0 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Pin::PA1 => rcc.ahbenr.modify(|_, w| w.iopaen().enabled()),
            Pin::PC13 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
            Pin::PC14 => rcc.ahbenr.modify(|_, w| w.iopcen().enabled()),
        }

        // Clock activation ADC
        rcc.apb2enr.modify(|_, w| w.adcen().enabled());

        // PA Analog Input Pin
        match *pin {
            Pin::PA0 => gpioa.moder.modify(|_, w| w.moder0().analog()),
            Pin::PA1 => gpioa.moder.modify(|_, w| w.moder1().analog()),
            Pin::PC13 => gpioc.moder.modify(|_, w| w.moder3().analog()),
            Pin::PC14 => gpioc.moder.modify(|_, w| w.moder4().analog()),
        }
    });
}
<|endoftext|>


<commit_before>mod generated;

use std::fmt;
use SyntaxKind::*;

pub use self::generated::SyntaxKind;

impl fmt::Debug for SyntaxKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = self.info().name;
        f.write_str(name)
    }
}

pub(crate) struct SyntaxInfo {
    pub name: &'static str,
}

impl SyntaxKind {
    pub(crate) fn is_trivia(self: SyntaxKind) -> bool {
        match self {
            WHITESPACE | COMMENT | DOC_COMMENT => true,
            _ => false,
        }
    }
}
<commit_msg>minor<commit_after>mod generated;

use std::fmt;
use SyntaxKind::*;

pub use self::generated::SyntaxKind;

impl fmt::Debug for SyntaxKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = self.info().name;
        f.write_str(name)
    }
}

pub(crate) struct SyntaxInfo {
    pub name: &'static str,
}

impl SyntaxKind {
    pub(crate) fn is_trivia(self) -> bool {
        match self {
            WHITESPACE | COMMENT | DOC_COMMENT => true,
            _ => false,
        }
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use std::collections::HashSet;
use std::fmt::{self, Display};
use std::str::FromStr;
use syn::{Error, Expr, Lit, Result};

pub struct DiscriminantSet {
    values: HashSet<Discriminant>,
    previous: Option<Discriminant>,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct Discriminant {
    magnitude: u32,
}

impl DiscriminantSet {
    pub fn new() -> Self {
        DiscriminantSet {
            values: HashSet::new(),
            previous: None,
        }
    }

    pub fn insert(&mut self, expr: &Expr) -> Result<Discriminant> {
        let discriminant = expr_to_discriminant(expr)?;
        insert(self, discriminant)
    }

    pub fn insert_next(&mut self) -> Result<Discriminant> {
        let discriminant = match self.previous {
            None => Discriminant::zero(),
            Some(mut discriminant) => {
                if discriminant.magnitude == u32::MAX {
                    let msg = format!("discriminant overflow on value after {}", u32::MAX);
                    return Err(Error::new(Span::call_site(), msg));
                }
                discriminant.magnitude += 1;
                discriminant
            }
        };
        insert(self, discriminant)
    }
}

fn expr_to_discriminant(expr: &Expr) -> Result<Discriminant> {
    if let Expr::Lit(expr) = expr {
        if let Lit::Int(lit) = &expr.lit {
            return lit.base10_parse::<Discriminant>();
        }
    }
    Err(Error::new_spanned(
        expr,
        "enums with non-integer literal discriminants are not supported yet",
    ))
}

fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discriminant> {
    if set.values.insert(discriminant) {
        set.previous = Some(discriminant);
        Ok(discriminant)
    } else {
        let msg = format!("discriminant value `{}` already exists", discriminant);
        Err(Error::new(Span::call_site(), msg))
    }
}

impl Discriminant {
    fn zero() -> Self {
        Discriminant { magnitude: 0 }
    }
}

impl Display for Discriminant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.magnitude, f)
    }
}

impl ToTokens for Discriminant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        Literal::u32_unsuffixed(self.magnitude).to_tokens(tokens);
    }
}

impl FromStr for Discriminant {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        match s.parse::<u32>() {
            Ok(magnitude) => Ok(Discriminant { magnitude }),
            Err(_) => Err(Error::new(
                Span::call_site(),
                "discriminant value outside of supported range",
            )),
        }
    }
}
<commit_msg>Parse negative discriminants<commit_after>use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use std::collections::HashSet;
use std::fmt::{self, Display};
use std::str::FromStr;
use syn::{Error, Expr, Lit, Result, Token, UnOp};

pub struct DiscriminantSet {
    values: HashSet<Discriminant>,
    previous: Option<Discriminant>,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct Discriminant {
    negative: bool,
    magnitude: u32,
}

impl DiscriminantSet {
    pub fn new() -> Self {
        DiscriminantSet {
            values: HashSet::new(),
            previous: None,
        }
    }

    pub fn insert(&mut self, expr: &Expr) -> Result<Discriminant> {
        let discriminant = expr_to_discriminant(expr)?;
        insert(self, discriminant)
    }

    pub fn insert_next(&mut self) -> Result<Discriminant> {
        let discriminant = match self.previous {
            None => Discriminant::zero(),
            Some(mut discriminant) if discriminant.negative => {
                discriminant.magnitude -= 1;
                if discriminant.magnitude == 0 {
                    discriminant.negative = false;
                }
                discriminant
            }
            Some(mut discriminant) => {
                if discriminant.magnitude == u32::MAX {
                    let msg = format!("discriminant overflow on value after {}", u32::MAX);
                    return Err(Error::new(Span::call_site(), msg));
                }
                discriminant.magnitude += 1;
                discriminant
            }
        };
        insert(self, discriminant)
    }
}

fn expr_to_discriminant(expr: &Expr) -> Result<Discriminant> {
    match expr {
        Expr::Lit(expr) => {
            if let Lit::Int(lit) = &expr.lit {
                return lit.base10_parse::<Discriminant>();
            }
        }
        Expr::Unary(unary) => {
            if let UnOp::Neg(_) = unary.op {
                let mut discriminant = expr_to_discriminant(&unary.expr)?;
                discriminant.negative ^= true;
                return Ok(discriminant);
            }
        }
        _ => {}
    }
    Err(Error::new_spanned(
        expr,
        "enums with non-integer literal discriminants are not supported yet",
    ))
}

fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discriminant> {
    if set.values.insert(discriminant) {
        set.previous = Some(discriminant);
        Ok(discriminant)
    } else {
        let msg = format!("discriminant value `{}` already exists", discriminant);
        Err(Error::new(Span::call_site(), msg))
    }
}

impl Discriminant {
    fn zero() -> Self {
        Discriminant {
            negative: false,
            magnitude: 0,
        }
    }
}

impl Display for Discriminant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.negative {
            f.write_str("-")?;
        }
        Display::fmt(&self.magnitude, f)
    }
}

impl ToTokens for Discriminant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        if self.negative {
            Token![-](Span::call_site()).to_tokens(tokens);
        }
        Literal::u32_unsuffixed(self.magnitude).to_tokens(tokens);
    }
}

impl FromStr for Discriminant {
    type Err = Error;

    fn from_str(mut s: &str) -> Result<Self> {
        let negative = s.starts_with('-');
        if negative {
            s = &s[1..];
        }
        match s.parse::<u32>() {
            Ok(magnitude) => Ok(Discriminant {
                negative,
                magnitude,
            }),
            Err(_) => Err(Error::new(
                Span::call_site(),
                "discriminant value outside of supported range",
            )),
        }
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Jordi Boggiano <j.boggiano@seld.be>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

use clap::{App, AppSettings};
use uucore::error::UResult;

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    uu_app().get_matches_from(args);
    Ok(())
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name()).setting(AppSettings::InferLongArgs)
}
<commit_msg>true: Rework to return true more often<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Jordi Boggiano <j.boggiano@seld.be>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
use clap::{App, AppSettings, ErrorKind};
use std::io::Write;
use uucore::error::{set_exit_code, UResult};

static ABOUT: &str = "
 Returns true, a successful exit status.

 Immediately returns with the exit status `0`, except when invoked with one of the recognized
 options. In those cases it will try to write the help or version text. Any IO error during this
 operation causes the program to return `1` instead.
";

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let app = uu_app();

    if let Err(err) = app.try_get_matches_from(args) {
        if let ErrorKind::DisplayHelp | ErrorKind::DisplayVersion = err.kind {
            if let Err(print_fail) = err.print() {
                // Try to display this error.
                let _ = writeln!(std::io::stderr(), "{}: {}", uucore::util_name(), print_fail);
                // Mirror GNU options. When failing to print warnings or version flags, then we exit
                // with FAIL. This avoids allocation some error information which may result in yet
                // other types of failure.
                set_exit_code(1);
            }
        }
    }

    Ok(())
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name())
        .version(clap::crate_version!())
        .about(ABOUT)
        .setting(AppSettings::InferLongArgs)
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A helper module to probe the Windows Registry when looking for
//! windows-specific tools.

use std::process::Command;

use Tool;

/// Attempts to find a tool within an MSVC installation using the Windows
/// registry as a point to search from.
///
/// The `target` argument is the target that the tool should work for (e.g.
/// compile or link for) and the `tool` argument is the tool to find (e.g.
/// `cl.exe` or `link.exe`).
///
/// This function will return `None` if the tool could not be found, or it will
/// return `Some(cmd)` which represents a command that's ready to execute the
/// tool with the appropriate environment variables set.
///
/// Note that this function always returns `None` for non-MSVC targets.
pub fn find(target: &str, tool: &str) -> Option<Command> {
    find_tool(target, tool).map(|c| c.to_command())
}

/// Similar to the `find` function above, this function will attempt the same
/// operation (finding a MSVC tool in a local install) but instead returns a
/// `Tool` which may be introspected.
#[cfg(not(windows))]
pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
    None
}

/// Documented above.
#[cfg(windows)]
pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
    use std::env;
    use std::ffi::OsString;
    use std::io;
    use std::fs;
    use std::path::{Path, PathBuf};
    use registry::{RegistryKey, LOCAL_MACHINE};

    if !target.contains("msvc") { return None }

    // When finding binaries the 32-bit version is at the top level but the
    // versions to cross to other architectures are stored in sub-folders.
    // Unknown architectures also just bail out early to return the standard
    // `link.exe` command.
    let extra = if target.starts_with("i686") {
        ""
    } else if target.starts_with("x86_64") {
        "amd64"
    } else if target.starts_with("arm") {
        "arm"
    } else {
        return None
    };

    let vs_install_dir = get_vs_install_dir();
    let mut path_to_add = None;

    // First up, we need to find the `link.exe` binary itself, and there's a few
    // locations that we can look. First up is the standard VCINSTALLDIR
    // environment variable which is normally set by the vcvarsall.bat file. If
    // an environment is set up manually by whomever's driving the compiler then
    // we shouldn't muck with that decision and should instead respect that.
    //
    // Finally we read the Windows registry to discover the VS install root.
    // From here we probe just to make sure that it exists.
    let mut cmd = env::var_os("VCINSTALLDIR").and_then(|dir| {
        let mut p = PathBuf::from(dir);
        p.push("bin");
        p.push(extra);
        let tool = p.join(tool);
        if fs::metadata(&tool).is_ok() {
            path_to_add = Some(p);
            Some(tool)
        } else {
            None
        }
    }).or_else(|| {
        env::var_os("PATH").and_then(|path| {
            env::split_paths(&path).map(|p| p.join(tool)).find(|path| {
                fs::metadata(path).is_ok()
            })
        })
    }).or_else(|| {
        vs_install_dir.as_ref().and_then(|p| {
            let mut p = p.join("VC/bin");
            p.push(extra);
            let tool = p.join(tool);
            if fs::metadata(&tool).is_ok() {
                path_to_add = Some(p);
                Some(tool)
            } else {
                None
            }
        })
    }).map(|tool| {
        Tool::new(tool.into())
    }).unwrap_or_else(|| {
        Tool::new(tool.into())
    });

    let mut paths = Vec::new();
    if let Some(path) = path_to_add {
        paths.push(path);
        if let Some(root) = get_windows_sdk_bin_path(target) {
            paths.push(root);
        }
    }
    if let Some(path) = env::var_os("PATH") {
        paths.extend(env::split_paths(&path));
    }
    cmd.env.push(("PATH".into(), env::join_paths(&paths).unwrap().into()));

    // The MSVC compiler uses the INCLUDE environment variable as the default
    // lookup path for headers. This environment variable is normally set up
    // by the VS shells, so we only want to start adding our own pieces if it's
    // not set.
    //
    // If we're adding our own pieces, then we need to add two primary
    // directories to the default search path for the linker. The first is in
    // the VS install direcotry and the next is the Windows SDK directory.
    if env::var_os("INCLUDE").is_none() {
        let mut includes = Vec::new();
        if let Some(ref vs_install_dir) = vs_install_dir {
            includes.push(vs_install_dir.join("VC/include"));
            if let Some((ucrt_root, vers)) = ucrt_install_dir(vs_install_dir) {
                let include = ucrt_root.join("Include").join(vers);
                includes.push(include.join("ucrt"));
                includes.push(include.join("um"));
                includes.push(include.join("winrt"));
                includes.push(include.join("shared"));
            }
        }
        if let Some((path, major)) = get_windows_sdk_path() {
            if major >= 8 {
                includes.push(path.join("include/shared"));
                includes.push(path.join("include/um"));
                includes.push(path.join("include/winrt"));
            } else {
                includes.push(path.join("include"));
            }
        } else if let Some(ref vs_install_dir) = vs_install_dir {
            includes.push(vs_install_dir.clone());
        }
        cmd.env.push(("INCLUDE".into(),
                      env::join_paths(&includes).unwrap().into()));
    }

    // Similarly with INCLUDE above, let's set LIB if it's not defined.
    if env::var_os("LIB").is_none() {
        let mut libs = Vec::new();
        if let Some(ref vs_install_dir) = vs_install_dir {
            libs.push(vs_install_dir.join("VC/lib").join(extra));
            if let Some((ucrt_root, vers)) = ucrt_install_dir(vs_install_dir) {
                if let Some(arch) = windows_sdk_v8_subdir(target) {
                    let lib = ucrt_root.join("Lib").join(vers);
                    libs.push(lib.join("ucrt").join(arch));
                    libs.push(lib.join("um").join(arch));
                }
            }
        }
        if let Some(path) = get_windows_sdk_lib_path(target) {
            libs.push(path);
        }
        cmd.env.push(("LIB".into(), env::join_paths(&libs).unwrap().into()));
    }

    return Some(cmd);

    // When looking for the Visual Studio installation directory we look in a
    // number of locations in varying degrees of precedence:
    //
    // 1. The Visual Studio registry keys
    // 2. The Visual Studio Express registry keys
    // 3. A number of somewhat standard environment variables
    //
    // If we find a hit from any of these keys then we strip off the IDE/Tools
    // folders which are typically found at the end.
    //
    // As a final note, when we take a look at the registry keys they're
    // typically found underneath the version of what's installed, but we don't
    // quite know what's installed. As a result we probe all sub-keys of the two
    // keys we're looking at to find out the maximum version of what's installed
    // and we use that root directory.
    fn get_vs_install_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio".as_ref()).or_else(|_| {
            LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VCExpress".as_ref())
        }).ok().and_then(|key| {
            max_version(&key).and_then(|(_vers, key)| {
                key.query_str("InstallDir").ok()
            })
        }).or_else(|| {
            env::var_os("VS120COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS100COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS90COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS80COMNTOOLS")
        }).map(PathBuf::from).and_then(|mut dir| {
            if dir.ends_with("Common7/IDE") || dir.ends_with("Common7/Tools") {
                dir.pop();
                dir.pop();
                Some(dir)
            } else {
                None
            }
        })
    }

    // Given a registry key, look at all the sub keys and find the one which has
    // the maximal numeric value.
    //
    // Returns the name of the maximal key as well as the opened maximal key.
    fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
        let mut max_vers = 0;
        let mut max_key = None;
        for subkey in key.iter().filter_map(|k| k.ok()) {
            let val = subkey.to_str().and_then(|s| {
                s.trim_left_matches("v").replace(".", "").parse().ok()
            });
            let val = match val {
                Some(s) => s,
                None => continue,
            };
            if val > max_vers {
                if let Ok(k) = key.open(&subkey) {
                    max_vers = val;
                    max_key = Some((subkey, k));
                }
            }
        }
        return max_key
    }

    fn get_windows_sdk_path() -> Option<(PathBuf, usize)> {
        let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows";
        let key = LOCAL_MACHINE.open(key.as_ref());
        let (n, k) = match key.ok().as_ref().and_then(max_version) {
            Some(p) => p,
            None => return None,
        };
        let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, ".");
        let major = parts.next().unwrap().parse::<usize>().unwrap();
        let _minor = parts.next().unwrap().parse::<usize>().unwrap();
        k.query_str("InstallationFolder").ok().map(|p| {
            (PathBuf::from(p), major)
        })
    }

    fn get_windows_sdk_lib_path(target: &str) -> Option<PathBuf> {
        let (mut root, major) = match get_windows_sdk_path() {
            Some(pair) => pair,
            None => return None,
        };
        root.push("Lib");
        if major <= 7 {
            // In Windows SDK 7.x, x86 libraries are directly in the Lib
            // folder, x64 libraries are inside, and it's not necessary to
            // link agains the SDK 7.x when targeting ARM or other
            // architectures.
            if target.starts_with("i686") {
                Some(root)
            } else if target.starts_with("x86_64") {
                Some(root.join("x64"))
            } else {
                None
            }
        } else {
            // Windows SDK 8.x installes libraries in a folder whose names
            // depend on the version of the OS you're targeting. By default
            // choose the newest, which usually corresponds to the version of
            // the OS you've installed the SDK on.
            let extra = match windows_sdk_v8_subdir(target) {
                Some(extra) => extra,
                None => return None,
            };
            ["winv6.3", "win8", "win7"].iter().map(|p| root.join(p)).find(|part| {
                fs::metadata(part).is_ok()
            }).map(|path| {
                path.join("um").join(extra)
            })
        }
    }

    fn get_windows_sdk_bin_path(target: &str) -> Option<PathBuf> {
        let (mut root, major) = match get_windows_sdk_path() {
            Some(pair) => pair,
            None => return None,
        };
        root.push("bin");
        if major <= 7 {
            None // untested path, not sure if this dir exists
        } else {
            root.push(match windows_sdk_v8_subdir(target) {
                Some(extra) => extra,
                None => return None,
            });
            if fs::metadata(&root).is_ok() {Some(root)} else {None}
        }
    }

    fn windows_sdk_v8_subdir(target: &str) -> Option<&'static str> {
        if target.starts_with("i686") {
            Some("x86")
        } else if target.starts_with("x86_64") {
            Some("x64")
        } else if target.starts_with("arm") {
            Some("arm")
        } else {
            None
        }
    }

    fn ucrt_install_dir(vs_install_dir: &Path) -> Option<(PathBuf, String)> {
        let is_vs_14 = vs_install_dir.iter().filter_map(|p| p.to_str()).any(|s| {
            s == "Microsoft Visual Studio 14.0"
        });
        if !is_vs_14 {
            return None
        }
        let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
        let sdk_dir = LOCAL_MACHINE.open(key.as_ref()).and_then(|p| {
            p.query_str("KitsRoot10")
        }).map(PathBuf::from);
        let sdk_dir = match sdk_dir {
            Ok(p) => p,
            Err(..) => return None,
        };
        (move || -> io::Result<_> {
            let mut max = None;
            let mut max_s = None;
            for entry in try!(fs::read_dir(&sdk_dir.join("Lib"))) {
                let entry = try!(entry);
                if let Ok(s) = entry.file_name().into_string() {
                    if let Ok(u) = s.replace(".", "").parse::<usize>() {
                        if Some(u) > max {
                            max = Some(u);
                            max_s = Some(s);
                        }
                    }
                }
            }
            Ok(max_s.map(|m| (sdk_dir, m)))
        })().ok().and_then(|x| x)
    }
}
<commit_msg>Add support for finding msbuild<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A helper module to probe the Windows Registry when looking for
//! windows-specific tools.

use std::process::Command;

use Tool;

/// Attempts to find a tool within an MSVC installation using the Windows
/// registry as a point to search from.
///
/// The `target` argument is the target that the tool should work for (e.g.
/// compile or link for) and the `tool` argument is the tool to find (e.g.
/// `cl.exe` or `link.exe`).
///
/// This function will return `None` if the tool could not be found, or it will
/// return `Some(cmd)` which represents a command that's ready to execute the
/// tool with the appropriate environment variables set.
///
/// Note that this function always returns `None` for non-MSVC targets.
pub fn find(target: &str, tool: &str) -> Option<Command> {
    find_tool(target, tool).map(|c| c.to_command())
}

/// Similar to the `find` function above, this function will attempt the same
/// operation (finding a MSVC tool in a local install) but instead returns a
/// `Tool` which may be introspected.
#[cfg(not(windows))]
pub fn find_tool(_target: &str, _tool: &str) -> Option<Tool> {
    None
}

/// Documented above.
#[cfg(windows)]
pub fn find_tool(target: &str, tool: &str) -> Option<Tool> {
    use std::env;
    use std::ffi::OsString;
    use std::io;
    use std::fs;
    use std::path::{Path, PathBuf};
    use registry::{RegistryKey, LOCAL_MACHINE};

    if !target.contains("msvc") { return None }

    if tool.contains("msbuild") {
        return find_msbuild()
    }

    // When finding binaries the 32-bit version is at the top level but the
    // versions to cross to other architectures are stored in sub-folders.
    // Unknown architectures also just bail out early to return the standard
    // `link.exe` command.
    let extra = if target.starts_with("i686") {
        ""
    } else if target.starts_with("x86_64") {
        "amd64"
    } else if target.starts_with("arm") {
        "arm"
    } else {
        return None
    };

    let vs_install_dir = get_vs_install_dir();
    let mut path_to_add = None;

    // First up, we need to find the `link.exe` binary itself, and there's a few
    // locations that we can look. First up is the standard VCINSTALLDIR
    // environment variable which is normally set by the vcvarsall.bat file. If
    // an environment is set up manually by whomever's driving the compiler then
    // we shouldn't muck with that decision and should instead respect that.
    //
    // Finally we read the Windows registry to discover the VS install root.
    // From here we probe just to make sure that it exists.
    let mut cmd = env::var_os("VCINSTALLDIR").and_then(|dir| {
        let mut p = PathBuf::from(dir);
        p.push("bin");
        p.push(extra);
        let tool = p.join(tool);
        if fs::metadata(&tool).is_ok() {
            path_to_add = Some(p);
            Some(tool)
        } else {
            None
        }
    }).or_else(|| {
        env::var_os("PATH").and_then(|path| {
            env::split_paths(&path).map(|p| p.join(tool)).find(|path| {
                fs::metadata(path).is_ok()
            })
        })
    }).or_else(|| {
        vs_install_dir.as_ref().and_then(|p| {
            let mut p = p.join("VC/bin");
            p.push(extra);
            let tool = p.join(tool);
            if fs::metadata(&tool).is_ok() {
                path_to_add = Some(p);
                Some(tool)
            } else {
                None
            }
        })
    }).map(|tool| {
        Tool::new(tool.into())
    }).unwrap_or_else(|| {
        Tool::new(tool.into())
    });

    let mut paths = Vec::new();
    if let Some(path) = path_to_add {
        paths.push(path);
        if let Some(root) = get_windows_sdk_bin_path(target) {
            paths.push(root);
        }
    }
    if let Some(path) = env::var_os("PATH") {
        paths.extend(env::split_paths(&path));
    }
    cmd.env.push(("PATH".into(), env::join_paths(&paths).unwrap().into()));

    // The MSVC compiler uses the INCLUDE environment variable as the default
    // lookup path for headers. This environment variable is normally set up
    // by the VS shells, so we only want to start adding our own pieces if it's
    // not set.
    //
    // If we're adding our own pieces, then we need to add two primary
    // directories to the default search path for the linker. The first is in
    // the VS install direcotry and the next is the Windows SDK directory.
    if env::var_os("INCLUDE").is_none() {
        let mut includes = Vec::new();
        if let Some(ref vs_install_dir) = vs_install_dir {
            includes.push(vs_install_dir.join("VC/include"));
            if let Some((ucrt_root, vers)) = ucrt_install_dir(vs_install_dir) {
                let include = ucrt_root.join("Include").join(vers);
                includes.push(include.join("ucrt"));
                includes.push(include.join("um"));
                includes.push(include.join("winrt"));
                includes.push(include.join("shared"));
            }
        }
        if let Some((path, major)) = get_windows_sdk_path() {
            if major >= 8 {
                includes.push(path.join("include/shared"));
                includes.push(path.join("include/um"));
                includes.push(path.join("include/winrt"));
            } else {
                includes.push(path.join("include"));
            }
        } else if let Some(ref vs_install_dir) = vs_install_dir {
            includes.push(vs_install_dir.clone());
        }
        cmd.env.push(("INCLUDE".into(),
                      env::join_paths(&includes).unwrap().into()));
    }

    // Similarly with INCLUDE above, let's set LIB if it's not defined.
    if env::var_os("LIB").is_none() {
        let mut libs = Vec::new();
        if let Some(ref vs_install_dir) = vs_install_dir {
            libs.push(vs_install_dir.join("VC/lib").join(extra));
            if let Some((ucrt_root, vers)) = ucrt_install_dir(vs_install_dir) {
                if let Some(arch) = windows_sdk_v8_subdir(target) {
                    let lib = ucrt_root.join("Lib").join(vers);
                    libs.push(lib.join("ucrt").join(arch));
                    libs.push(lib.join("um").join(arch));
                }
            }
        }
        if let Some(path) = get_windows_sdk_lib_path(target) {
            libs.push(path);
        }
        cmd.env.push(("LIB".into(), env::join_paths(&libs).unwrap().into()));
    }

    return Some(cmd);

    // When looking for the Visual Studio installation directory we look in a
    // number of locations in varying degrees of precedence:
    //
    // 1. The Visual Studio registry keys
    // 2. The Visual Studio Express registry keys
    // 3. A number of somewhat standard environment variables
    //
    // If we find a hit from any of these keys then we strip off the IDE/Tools
    // folders which are typically found at the end.
    //
    // As a final note, when we take a look at the registry keys they're
    // typically found underneath the version of what's installed, but we don't
    // quite know what's installed. As a result we probe all sub-keys of the two
    // keys we're looking at to find out the maximum version of what's installed
    // and we use that root directory.
    fn get_vs_install_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio".as_ref()).or_else(|_| {
            LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VCExpress".as_ref())
        }).ok().and_then(|key| {
            max_version(&key).and_then(|(_vers, key)| {
                key.query_str("InstallDir").ok()
            })
        }).or_else(|| {
            env::var_os("VS120COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS100COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS90COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS80COMNTOOLS")
        }).map(PathBuf::from).and_then(|mut dir| {
            if dir.ends_with("Common7/IDE") || dir.ends_with("Common7/Tools") {
                dir.pop();
                dir.pop();
                Some(dir)
            } else {
                None
            }
        })
    }

    // Given a registry key, look at all the sub keys and find the one which has
    // the maximal numeric value.
    //
    // Returns the name of the maximal key as well as the opened maximal key.
    fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
        let mut max_vers = 0;
        let mut max_key = None;
        for subkey in key.iter().filter_map(|k| k.ok()) {
            let val = subkey.to_str().and_then(|s| {
                s.trim_left_matches("v").replace(".", "").parse().ok()
            });
            let val = match val {
                Some(s) => s,
                None => continue,
            };
            if val > max_vers {
                if let Ok(k) = key.open(&subkey) {
                    max_vers = val;
                    max_key = Some((subkey, k));
                }
            }
        }
        return max_key
    }

    fn get_windows_sdk_path() -> Option<(PathBuf, usize)> {
        let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows";
        let key = LOCAL_MACHINE.open(key.as_ref());
        let (n, k) = match key.ok().as_ref().and_then(max_version) {
            Some(p) => p,
            None => return None,
        };
        let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, ".");
        let major = parts.next().unwrap().parse::<usize>().unwrap();
        let _minor = parts.next().unwrap().parse::<usize>().unwrap();
        k.query_str("InstallationFolder").ok().map(|p| {
            (PathBuf::from(p), major)
        })
    }

    fn get_windows_sdk_lib_path(target: &str) -> Option<PathBuf> {
        let (mut root, major) = match get_windows_sdk_path() {
            Some(pair) => pair,
            None => return None,
        };
        root.push("Lib");
        if major <= 7 {
            // In Windows SDK 7.x, x86 libraries are directly in the Lib
            // folder, x64 libraries are inside, and it's not necessary to
            // link agains the SDK 7.x when targeting ARM or other
            // architectures.
            if target.starts_with("i686") {
                Some(root)
            } else if target.starts_with("x86_64") {
                Some(root.join("x64"))
            } else {
                None
            }
        } else {
            // Windows SDK 8.x installes libraries in a folder whose names
            // depend on the version of the OS you're targeting. By default
            // choose the newest, which usually corresponds to the version of
            // the OS you've installed the SDK on.
            let extra = match windows_sdk_v8_subdir(target) {
                Some(extra) => extra,
                None => return None,
            };
            ["winv6.3", "win8", "win7"].iter().map(|p| root.join(p)).find(|part| {
                fs::metadata(part).is_ok()
            }).map(|path| {
                path.join("um").join(extra)
            })
        }
    }

    fn get_windows_sdk_bin_path(target: &str) -> Option<PathBuf> {
        let (mut root, major) = match get_windows_sdk_path() {
            Some(pair) => pair,
            None => return None,
        };
        root.push("bin");
        if major <= 7 {
            None // untested path, not sure if this dir exists
        } else {
            root.push(match windows_sdk_v8_subdir(target) {
                Some(extra) => extra,
                None => return None,
            });
            if fs::metadata(&root).is_ok() {Some(root)} else {None}
        }
    }

    fn windows_sdk_v8_subdir(target: &str) -> Option<&'static str> {
        if target.starts_with("i686") {
            Some("x86")
        } else if target.starts_with("x86_64") {
            Some("x64")
        } else if target.starts_with("arm") {
            Some("arm")
        } else {
            None
        }
    }

    fn ucrt_install_dir(vs_install_dir: &Path) -> Option<(PathBuf, String)> {
        let is_vs_14 = vs_install_dir.iter().filter_map(|p| p.to_str()).any(|s| {
            s == "Microsoft Visual Studio 14.0"
        });
        if !is_vs_14 {
            return None
        }
        let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
        let sdk_dir = LOCAL_MACHINE.open(key.as_ref()).and_then(|p| {
            p.query_str("KitsRoot10")
        }).map(PathBuf::from);
        let sdk_dir = match sdk_dir {
            Ok(p) => p,
            Err(..) => return None,
        };
        (move || -> io::Result<_> {
            let mut max = None;
            let mut max_s = None;
            for entry in try!(fs::read_dir(&sdk_dir.join("Lib"))) {
                let entry = try!(entry);
                if let Ok(s) = entry.file_name().into_string() {
                    if let Ok(u) = s.replace(".", "").parse::<usize>() {
                        if Some(u) > max {
                            max = Some(u);
                            max_s = Some(s);
                        }
                    }
                }
            }
            Ok(max_s.map(|m| (sdk_dir, m)))
        })().ok().and_then(|x| x)
    }

    // see http://stackoverflow.com/questions/328017/path-to-msbuild
    fn find_msbuild() -> Option<Tool> {
        let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions";
        LOCAL_MACHINE.open(key.as_ref()).ok().and_then(|key| {
            max_version(&key).and_then(|(_vers, key)| {
                key.query_str("MSBuildToolsPath").ok()
            })
        }).map(|path| {
            Tool::new(path.into())
        })
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Condition variables

pub use os::cond_var::internal::{CondVar, COND_VAR_INIT};

#[cfg(multitasking)]
mod internal {
  use core::option::{None, Some};
  use core::ty::Unsafe;
  use core::kinds::marker;
  use core::kinds::Share;

  use hal::cortex_m3::sched::NoInterrupts;
  use util::queue::{Queue, Node};
  use os::task::{TaskDescriptor, Tasks};

  /// A condition variable
  pub struct CondVar {
    waiting: Queue<*mut TaskDescriptor>
  }

  /// Static initializer
  pub const COND_VAR_INIT: CondVar = CondVar {
    waiting: Queue {
      head: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
      tail: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
    }
  };

  impl CondVar {
    /// Create a new condition variable
    pub fn new() -> CondVar {
      CondVar { waiting: Queue::new() }
    }

    /// Wait on a condition variable.
    pub fn wait(&self) {
      /*
       * The signalling thread is responsible for removing the waiting
       * thread which ensures that a signal wakes up exactly one thread
       * whenever there is one waiting.
       */
      unsafe {
        let crit = NoInterrupts::new();
        let mut waiting = Node::new(Tasks.current_task() as *mut TaskDescriptor);
        self.waiting.push(&mut waiting, &crit);
        Tasks.current_task().block(crit);
      }
    }

    /// Wake up a thread waiting on a condition variable.
    pub fn signal(&self) {
      unsafe {
        let crit = NoInterrupts::new();
        match self.waiting.pop(&crit) {
          None => { },
          Some(task) => (*(*task).data).unblock(&crit)
        }
      }
    }

    /// Wake up all threads waiting on a condition variable.
    pub fn broadcast(&self) {
      unsafe {
        let crit = NoInterrupts::new();
        loop {
          match self.waiting.pop(&crit) {
            None => break,
            Some(task) => (*(*task).data).unblock(&crit)
          }
        }
      }
    }
  }

  impl Share for CondVar {}
}

#[cfg(not(multitasking))]
mod internal {
  use core::kinds::marker;
  use core::kinds::Share;
  use core::cell::UnsafeCell;

  use util::support::wfi;

  /// A condition variable
  pub struct CondVar {
    waiting: UnsafeCell<bool>,
    nocopy: marker::NoCopy
  }

  /// Static initializer
  pub const COND_VAR_INIT: CondVar = CondVar {
    waiting: UnsafeCell { value: false },
    nocopy: marker::NoCopy,
  };

  impl CondVar {
    /// Create a new condition variable
    pub fn new() -> CondVar {
      CondVar {
        waiting: UnsafeCell::new(false),
        nocopy: marker::NoCopy,
      }
    }

    /// Wait on a condition variable.
    pub fn wait(&self) {
      unsafe {
        while *self.waiting.get() {
          wfi();
        }
      }
    }

    /// Wake up a thread waiting on a condition variable.
    pub fn signal(&self) {
      unsafe {
        *self.waiting.get() = true;
      }
    }

    /// Wake up all threads waiting on a condition variable.
    pub fn broadcast(&self) {
      self.signal();
    }
  }

  impl Share for CondVar {}
}
<commit_msg>cond_var: Fix inverted logic; a race condition remains<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Condition variables

pub use os::cond_var::internal::{CondVar, COND_VAR_INIT};

#[cfg(multitasking)]
mod internal {
  use core::option::{None, Some};
  use core::ty::Unsafe;
  use core::kinds::marker;
  use core::kinds::Share;

  use hal::cortex_m3::sched::NoInterrupts;
  use util::queue::{Queue, Node};
  use os::task::{TaskDescriptor, Tasks};

  /// A condition variable
  pub struct CondVar {
    waiting: Queue<*mut TaskDescriptor>
  }

  /// Static initializer
  pub const COND_VAR_INIT: CondVar = CondVar {
    waiting: Queue {
      head: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
      tail: Unsafe { value: 0 as *mut Node<*mut TaskDescriptor>, marker1: marker::InvariantType },
    }
  };

  impl CondVar {
    /// Create a new condition variable
    pub fn new() -> CondVar {
      CondVar { waiting: Queue::new() }
    }

    /// Wait on a condition variable.
    pub fn wait(&self) {
      /*
       * The signalling thread is responsible for removing the waiting
       * thread which ensures that a signal wakes up exactly one thread
       * whenever there is one waiting.
       */
      unsafe {
        let crit = NoInterrupts::new();
        let mut waiting = Node::new(Tasks.current_task() as *mut TaskDescriptor);
        self.waiting.push(&mut waiting, &crit);
        Tasks.current_task().block(crit);
      }
    }

    /// Wake up a thread waiting on a condition variable.
    pub fn signal(&self) {
      unsafe {
        let crit = NoInterrupts::new();
        match self.waiting.pop(&crit) {
          None => { },
          Some(task) => (*(*task).data).unblock(&crit)
        }
      }
    }

    /// Wake up all threads waiting on a condition variable.
    pub fn broadcast(&self) {
      unsafe {
        let crit = NoInterrupts::new();
        loop {
          match self.waiting.pop(&crit) {
            None => break,
            Some(task) => (*(*task).data).unblock(&crit)
          }
        }
      }
    }
  }

  impl Share for CondVar {}
}

#[cfg(not(multitasking))]
mod internal {
  use core::kinds::marker;
  use core::kinds::Share;
  use core::cell::UnsafeCell;

  use util::support::wfi;

  /// A condition variable
  pub struct CondVar {
    waiting: UnsafeCell<bool>,
    nocopy: marker::NoCopy
  }

  /// Static initializer
  pub const COND_VAR_INIT: CondVar = CondVar {
    waiting: UnsafeCell { value: false },
    nocopy: marker::NoCopy,
  };

  impl CondVar {
    /// Create a new condition variable
    pub fn new() -> CondVar {
      CondVar {
        waiting: UnsafeCell::new(false),
        nocopy: marker::NoCopy,
      }
    }

    /// Wait on a condition variable.
    pub fn wait(&self) {
      unsafe {
        // TODO(bgamari): There is a race condition here
        *self.waiting.get() = true;
        while *self.waiting.get() {
          wfi();
        }
      }
    }

    /// Wake up a thread waiting on a condition variable.
    pub fn signal(&self) {
      unsafe {
        *self.waiting.get() = false;
      }
    }

    /// Wake up all threads waiting on a condition variable.
    pub fn broadcast(&self) {
      self.signal();
    }
  }

  impl Share for CondVar {}
}
<|endoftext|>


<commit_before>/// Figure 8.5: Print a description of the exit status, and
/// Figure 8.6: Demonstrate various exit statuses
///
/// Takeaway: Rust intercepts the division by zero with its panic handler.
/// To make the exception "fall through" we need to replace rusts panic handler
/// by our own (at least that's what the guys on IRC suggested). Sadly in order to
/// go sure that it was *really* a division by zero we need to do a string comparison..
///
/// $ f06-exit-status
/// normal termination, exit status = 7
/// abnormal termination, signal number = 6
/// abnormal termination, signal number = 8

extern crate libc;
extern crate apue;

use libc::{c_int, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG, SIGFPE};
use libc::{exit, wait, fork, abort, raise};
use apue::{LibcResult, err_sys};
use std::panic;

unsafe fn pr_exit(status: c_int) {
    if WIFEXITED(status) {
        println!("normal termination, exit status = {}", WEXITSTATUS(status));
    } else if WIFSIGNALED(status) {
        println!("abnormal termination, signal number = {} {}",
                 WTERMSIG(status),
                 if WCOREDUMP(status) {
                     " (core file generated)"
                 } else {
                     ""
                 });
    } else if WIFSTOPPED(status) {
        println!("child stopped, signal number = {}", WSTOPSIG(status));
    }
}

fn handle_panic(e: &panic::PanicInfo) {
    match e.payload().downcast_ref::<String>() {
        Some(as_string) if as_string == "attempt to divide by zero" => {
            unsafe { raise(SIGFPE) };
        }
        _ => {
            panic!("unknown error occurred");
        },
    }
}

fn main() {
    panic::set_hook(Box::new(handle_panic));
    unsafe {
        let mut status: c_int = 0;
        let mut pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            exit(7);
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            abort(); // generate SIGABRT
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            status /= 0; // divide by 0 generates SIGFPE
        }

        if wait(&mut status) != pid {
            err_sys("wait error");
        }
        pr_exit(status);
    }
}<commit_msg>Rust fmt<commit_after>/// Figure 8.5: Print a description of the exit status, and
/// Figure 8.6: Demonstrate various exit statuses
///
/// Takeaway: Rust intercepts the division by zero with its panic handler.
/// To make the exception "fall through" we need to replace rusts panic handler
/// by our own (at least that's what the guys on IRC suggested). Sadly in order to
/// go sure that it was *really* a division by zero we need to do a string comparison..
///
/// $ f06-exit-status
/// normal termination, exit status = 7
/// abnormal termination, signal number = 6
/// abnormal termination, signal number = 8

extern crate libc;
extern crate apue;

use libc::{c_int, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG,
           SIGFPE};
use libc::{exit, wait, fork, abort, raise};
use apue::{LibcResult, err_sys};
use std::panic;

unsafe fn pr_exit(status: c_int) {
    if WIFEXITED(status) {
        println!("normal termination, exit status = {}", WEXITSTATUS(status));
    } else if WIFSIGNALED(status) {
        println!("abnormal termination, signal number = {} {}",
                 WTERMSIG(status),
                 if WCOREDUMP(status) {
                     " (core file generated)"
                 } else {
                     ""
                 });
    } else if WIFSTOPPED(status) {
        println!("child stopped, signal number = {}", WSTOPSIG(status));
    }
}

fn handle_panic(e: &panic::PanicInfo) {
    match e.payload().downcast_ref::<String>() {
        Some(as_string) if as_string == "attempt to divide by zero" => {
            unsafe { raise(SIGFPE) };
        }
        _ => {
            panic!("unknown error occurred");
        }
    }
}

fn main() {
    panic::set_hook(Box::new(handle_panic));
    unsafe {
        let mut status: c_int = 0;
        let mut pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            exit(7);
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            abort(); // generate SIGABRT
        }
        if wait(&mut status) != pid {
            // wait for child
            err_sys("wait error");
        }
        pr_exit(status);

        pid = fork().to_option().expect("fork error");
        if pid == 0 {
            // child
            status /= 0; // divide by 0 generates SIGFPE
        }

        if wait(&mut status) != pid {
            err_sys("wait error");
        }
        pr_exit(status);
    }
}
<|endoftext|>


<commit_before>use std::{io::Cursor, path::Path};

use rocksdb::{
    BlockBasedIndexType, BlockBasedOptions, ColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode,
    IteratorMode, MergeOperands, Options, ReadOptions, SliceTransform, WriteBatch, DB,
};

use crate::model::{
    GameId, GameInfo, Month, PersonalEntry, PersonalKey, PersonalKeyPrefix, PersonalStatus, UserId,
};

#[derive(Debug)]
pub struct Database {
    inner: DB,
}

impl Database {
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Database, rocksdb::Error> {
        let mut db_opts = Options::default();
        db_opts.create_if_missing(true);
        db_opts.create_missing_column_families(true);

        let mut personal_opts = Options::default();
        personal_opts.set_merge_operator_associative("personal merge", personal_merge);
        personal_opts
            .set_prefix_extractor(SliceTransform::create_fixed_prefix(PersonalKeyPrefix::SIZE));
        let mut personal_block_opts = BlockBasedOptions::default();
        personal_block_opts.set_index_type(BlockBasedIndexType::HashSearch);
        personal_block_opts.set_block_size(4 * 1024);
        personal_block_opts.set_bloom_filter(8, true);
        personal_opts.set_block_based_table_factory(&personal_block_opts);

        let mut game_opts = Options::default();
        game_opts.set_merge_operator_associative("game merge", game_merge);
        game_opts.set_prefix_extractor(SliceTransform::create_noop());
        let mut game_block_opts = BlockBasedOptions::default();
        game_block_opts.set_index_type(BlockBasedIndexType::HashSearch);
        game_block_opts.set_block_size(1024);
        game_opts.set_block_based_table_factory(&game_block_opts);

        let mut player_opts = Options::default();
        player_opts.set_prefix_extractor(SliceTransform::create_noop());
        let mut player_block_opts = BlockBasedOptions::default();
        player_block_opts.set_index_type(BlockBasedIndexType::HashSearch);
        player_block_opts.set_block_size(1024);
        player_opts.set_block_based_table_factory(&player_block_opts);

        let inner = DBWithThreadMode::open_cf_descriptors(
            &db_opts,
            path,
            vec![
                ColumnFamilyDescriptor::new("personal", personal_opts),
                ColumnFamilyDescriptor::new("game", game_opts),
                ColumnFamilyDescriptor::new("player", player_opts),
            ],
        )?;

        Ok(Database { inner })
    }

    pub fn queryable(&self) -> QueryableDatabase<'_> {
        QueryableDatabase {
            db: &self.inner,
            cf_personal: self.inner.cf_handle("personal").expect("cf personal"),
            cf_game: self.inner.cf_handle("game").expect("cf game"),
            cf_player: self.inner.cf_handle("player").expect("cf player"),
        }
    }
}

pub struct QueryableDatabase<'a> {
    db: &'a DB,
    cf_personal: &'a ColumnFamily,
    cf_game: &'a ColumnFamily,
    cf_player: &'a ColumnFamily,
}

impl QueryableDatabase<'_> {
    pub fn db_property(&self, name: &str) -> Result<Option<String>, rocksdb::Error> {
        self.db.property_value(name)
    }

    pub fn game_property(&self, name: &str) -> Result<Option<String>, rocksdb::Error> {
        self.db.property_value_cf(self.cf_game, name)
    }

    pub fn personal_property(&self, name: &str) -> Result<Option<String>, rocksdb::Error> {
        self.db.property_value_cf(self.cf_personal, name)
    }

    pub fn get_game_info(&self, id: GameId) -> Result<Option<GameInfo>, rocksdb::Error> {
        Ok(self.db.get_cf(self.cf_game, id.to_bytes())?.map(|buf| {
            let mut cursor = Cursor::new(buf);
            GameInfo::read(&mut cursor).expect("deserialize game info")
        }))
    }

    pub fn get_personal(
        &self,
        key: &PersonalKeyPrefix,
        since: Month,
        until: Month,
    ) -> Result<PersonalEntry, rocksdb::Error> {
        let mut opt = ReadOptions::default();
        opt.set_prefix_same_as_start(true);
        opt.set_iterate_lower_bound(key.with_month(since).into_bytes());
        opt.set_iterate_upper_bound(key.with_month(until.add_months_saturating(1)).into_bytes());

        let iterator = self
            .db
            .iterator_cf_opt(self.cf_personal, opt, IteratorMode::Start);

        let mut entry = PersonalEntry::default();
        for (_key, value) in iterator {
            let mut cursor = Cursor::new(value);
            entry
                .extend_from_reader(&mut cursor)
                .expect("deserialize personal entry");
        }

        Ok(entry)
    }

    pub fn get_player_status(&self, id: &UserId) -> Result<Option<PersonalStatus>, rocksdb::Error> {
        Ok(self.db.get_cf(self.cf_player, id.as_str())?.map(|buf| {
            let mut cursor = Cursor::new(buf);
            PersonalStatus::read(&mut cursor).expect("deserialize status")
        }))
    }

    pub fn put_player_status(
        &self,
        id: &UserId,
        status: &PersonalStatus,
    ) -> Result<(), rocksdb::Error> {
        let mut cursor = Cursor::new(Vec::with_capacity(PersonalStatus::SIZE_HINT));
        status.write(&mut cursor).expect("serialize status");
        self.db
            .put_cf(self.cf_player, id.as_str(), cursor.into_inner())
    }

    pub fn batch(&self) -> Batch<'_> {
        Batch {
            queryable: self,
            batch: WriteBatch::default(),
        }
    }
}

pub struct Batch<'a> {
    queryable: &'a QueryableDatabase<'a>,
    batch: WriteBatch,
}

impl Batch<'_> {
    pub fn merge_personal(&mut self, key: PersonalKey, entry: PersonalEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(PersonalEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize personal entry");
        self.batch.merge_cf(
            self.queryable.cf_personal,
            key.into_bytes(),
            cursor.into_inner(),
        );
    }

    pub fn merge_game_info(&mut self, id: GameId, info: GameInfo) {
        let mut cursor = Cursor::new(Vec::with_capacity(GameInfo::SIZE_HINT));
        info.write(&mut cursor).expect("serialize game info");
        self.batch
            .merge_cf(self.queryable.cf_game, id.to_bytes(), cursor.into_inner());
    }

    pub fn write(self) -> Result<(), rocksdb::Error> {
        self.queryable.db.write(self.batch)
    }
}

fn game_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    // Take latest game info, but merge index status.
    let mut info: Option<GameInfo> = None;
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        let mut new_info = GameInfo::read(&mut cursor).expect("read for game merge");
        if let Some(old_info) = info {
            new_info.indexed.white |= old_info.indexed.white;
            new_info.indexed.black |= old_info.indexed.black;
        }
        info = Some(new_info);
        size_hint = op.len();
    }
    info.map(|info| {
        let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
        info.write(&mut cursor).expect("write game");
        cursor.into_inner()
    })
}

fn personal_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = PersonalEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for personal merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write personal entry");
    Some(cursor.into_inner())
}
<commit_msg>add helpers for cf_master_game<commit_after>use std::{io::Cursor, path::Path};

use rocksdb::{
    BlockBasedIndexType, BlockBasedOptions, ColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode,
    IteratorMode, MergeOperands, Options, ReadOptions, SliceTransform, WriteBatch, DB,
};

use crate::model::{
    GameId, GameInfo, MasterGame, Month, PersonalEntry, PersonalKey, PersonalKeyPrefix,
    PersonalStatus, UserId,
};

#[derive(Debug)]
pub struct Database {
    inner: DB,
}

impl Database {
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Database, rocksdb::Error> {
        let mut db_opts = Options::default();
        db_opts.create_if_missing(true);
        db_opts.create_missing_column_families(true);

        let mut personal_opts = Options::default();
        personal_opts.set_merge_operator_associative("personal merge", personal_merge);
        personal_opts
            .set_prefix_extractor(SliceTransform::create_fixed_prefix(PersonalKeyPrefix::SIZE));
        let mut personal_block_opts = BlockBasedOptions::default();
        personal_block_opts.set_index_type(BlockBasedIndexType::HashSearch);
        personal_block_opts.set_block_size(4 * 1024);
        personal_block_opts.set_bloom_filter(8, true);
        personal_opts.set_block_based_table_factory(&personal_block_opts);

        let mut game_opts = Options::default();
        game_opts.set_merge_operator_associative("game merge", game_merge);
        game_opts.set_prefix_extractor(SliceTransform::create_noop());
        let mut game_block_opts = BlockBasedOptions::default();
        game_block_opts.set_index_type(BlockBasedIndexType::HashSearch);
        game_block_opts.set_block_size(1024);
        game_opts.set_block_based_table_factory(&game_block_opts);

        let mut player_opts = Options::default();
        player_opts.set_prefix_extractor(SliceTransform::create_noop());
        let mut player_block_opts = BlockBasedOptions::default();
        player_block_opts.set_index_type(BlockBasedIndexType::HashSearch);
        player_block_opts.set_block_size(1024);
        player_opts.set_block_based_table_factory(&player_block_opts);

        let inner = DBWithThreadMode::open_cf_descriptors(
            &db_opts,
            path,
            vec![
                ColumnFamilyDescriptor::new("personal", personal_opts),
                ColumnFamilyDescriptor::new("game", game_opts),
                ColumnFamilyDescriptor::new("player", player_opts),
                ColumnFamilyDescriptor::new("master", todo!()),
                ColumnFamilyDescriptor::new("master_game", todo!()),
            ],
        )?;

        Ok(Database { inner })
    }

    pub fn queryable(&self) -> QueryableDatabase<'_> {
        QueryableDatabase {
            db: &self.inner,
            cf_personal: self.inner.cf_handle("personal").expect("cf personal"),
            cf_game: self.inner.cf_handle("game").expect("cf game"),
            cf_player: self.inner.cf_handle("player").expect("cf player"),
            cf_master: self.inner.cf_handle("master").expect("cf master"),
            cf_master_game: self.inner.cf_handle("master_game").expect("cf master_game"),
        }
    }
}

pub struct QueryableDatabase<'a> {
    db: &'a DB,
    cf_personal: &'a ColumnFamily,
    cf_game: &'a ColumnFamily,
    cf_player: &'a ColumnFamily,
    cf_master: &'a ColumnFamily,
    cf_master_game: &'a ColumnFamily,
}

impl QueryableDatabase<'_> {
    pub fn db_property(&self, name: &str) -> Result<Option<String>, rocksdb::Error> {
        self.db.property_value(name)
    }

    pub fn game_property(&self, name: &str) -> Result<Option<String>, rocksdb::Error> {
        self.db.property_value_cf(self.cf_game, name)
    }

    pub fn personal_property(&self, name: &str) -> Result<Option<String>, rocksdb::Error> {
        self.db.property_value_cf(self.cf_personal, name)
    }

    pub fn get_game_info(&self, id: GameId) -> Result<Option<GameInfo>, rocksdb::Error> {
        Ok(self.db.get_cf(self.cf_game, id.to_bytes())?.map(|buf| {
            let mut cursor = Cursor::new(buf);
            GameInfo::read(&mut cursor).expect("deserialize game info")
        }))
    }

    pub fn get_personal(
        &self,
        key: &PersonalKeyPrefix,
        since: Month,
        until: Month,
    ) -> Result<PersonalEntry, rocksdb::Error> {
        let mut opt = ReadOptions::default();
        opt.set_prefix_same_as_start(true);
        opt.set_iterate_lower_bound(key.with_month(since).into_bytes());
        opt.set_iterate_upper_bound(key.with_month(until.add_months_saturating(1)).into_bytes());

        let iterator = self
            .db
            .iterator_cf_opt(self.cf_personal, opt, IteratorMode::Start);

        let mut entry = PersonalEntry::default();
        for (_key, value) in iterator {
            let mut cursor = Cursor::new(value);
            entry
                .extend_from_reader(&mut cursor)
                .expect("deserialize personal entry");
        }

        Ok(entry)
    }

    pub fn get_player_status(&self, id: &UserId) -> Result<Option<PersonalStatus>, rocksdb::Error> {
        Ok(self.db.get_cf(self.cf_player, id.as_str())?.map(|buf| {
            let mut cursor = Cursor::new(buf);
            PersonalStatus::read(&mut cursor).expect("deserialize status")
        }))
    }

    pub fn put_player_status(
        &self,
        id: &UserId,
        status: &PersonalStatus,
    ) -> Result<(), rocksdb::Error> {
        let mut cursor = Cursor::new(Vec::with_capacity(PersonalStatus::SIZE_HINT));
        status.write(&mut cursor).expect("serialize status");
        self.db
            .put_cf(self.cf_player, id.as_str(), cursor.into_inner())
    }

    pub fn get_master_game(&self, id: GameId) -> Result<Option<MasterGame>, rocksdb::Error> {
        Ok(self
            .db
            .get_cf(self.cf_master_game, id.to_bytes())?
            .map(|buf| serde_json::from_slice(&buf).expect("deserialize master game")))
    }

    pub fn batch(&self) -> Batch<'_> {
        Batch {
            queryable: self,
            batch: WriteBatch::default(),
        }
    }
}

pub struct Batch<'a> {
    queryable: &'a QueryableDatabase<'a>,
    batch: WriteBatch,
}

impl Batch<'_> {
    pub fn merge_personal(&mut self, key: PersonalKey, entry: PersonalEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(PersonalEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize personal entry");
        self.batch.merge_cf(
            self.queryable.cf_personal,
            key.into_bytes(),
            cursor.into_inner(),
        );
    }

    pub fn merge_game_info(&mut self, id: GameId, info: GameInfo) {
        let mut cursor = Cursor::new(Vec::with_capacity(GameInfo::SIZE_HINT));
        info.write(&mut cursor).expect("serialize game info");
        self.batch
            .merge_cf(self.queryable.cf_game, id.to_bytes(), cursor.into_inner());
    }

    pub fn put_master_game(&mut self, id: GameId, game: MasterGame) {
        self.batch.put_cf(
            self.queryable.cf_master_game,
            id.to_bytes(),
            serde_json::to_vec(game).expect("serialize master game"),
        );
    }

    pub fn write(self) -> Result<(), rocksdb::Error> {
        self.queryable.db.write(self.batch)
    }
}

fn game_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    // Take latest game info, but merge index status.
    let mut info: Option<GameInfo> = None;
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        let mut new_info = GameInfo::read(&mut cursor).expect("read for game merge");
        if let Some(old_info) = info {
            new_info.indexed.white |= old_info.indexed.white;
            new_info.indexed.black |= old_info.indexed.black;
        }
        info = Some(new_info);
        size_hint = op.len();
    }
    info.map(|info| {
        let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
        info.write(&mut cursor).expect("write game");
        cursor.into_inner()
    })
}

fn personal_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = PersonalEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for personal merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write personal entry");
    Some(cursor.into_inner())
}
<|endoftext|>