<commit_before>use std::{mem, ptr, slice};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::Mutex;
use std::io::{stderr, Write};
use std::thread::sleep;
use std::time::Duration;
use memalloc::{allocate, deallocate};

use winapi::*;

use winmm_sys::{
    midiInGetNumDevs,
    midiInGetDevCapsW,
    midiInOpen,
    midiInStart,
    midiInClose,
    midiInReset,
    midiInStop,
    midiInAddBuffer,
    midiInPrepareHeader,
    midiInUnprepareHeader,
    midiOutGetNumDevs,
    midiOutGetDevCapsW,
    midiOutOpen,
    midiOutReset,
    midiOutClose,
    midiOutPrepareHeader,
    midiOutUnprepareHeader,
    midiOutLongMsg,
    midiOutShortMsg,
};

use ::{MidiMessage, Ignore};
use ::errors::*;

mod handler;

const RT_SYSEX_BUFFER_SIZE: usize = 1024;
const RT_SYSEX_BUFFER_COUNT: usize = 4;

// helper for string conversion
fn from_wide_ptr<'a>(ptr: *const u16, max_len: usize) -> OsString {
    unsafe {
        assert!(!ptr.is_null());
        let len = (0..max_len as isize).position(|i| *ptr.offset(i) == 0).unwrap();
        let slice = slice::from_raw_parts(ptr, len);
        OsString::from_wide(slice)
    }
}

// TODO: make sure that these structs are all `Send`

#[derive(Debug)]
pub struct MidiInput {
    ignore_flags: Ignore
}

pub struct MidiInputConnection<T> {
    handler_data: Box<HandlerData<T>>,
}

/// This is all the data that is stored on the heap as long as a connection
/// is opened and passed to the callback handler.
///
/// It is important that `user_data` is the last field to not influence
/// offsets after monomorphization.
struct HandlerData<T> {
    message: MidiMessage,
    last_time: Option<u64>,
    sysex_buffer: [LPMIDIHDR; RT_SYSEX_BUFFER_COUNT],
    in_handle: Option<Mutex<HMIDIIN>>,
    ignore_flags: Ignore,
    callback: Box<FnMut(f64, &[u8], &mut T)+Send>,
    user_data: Option<T>
}

impl MidiInput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiInput { ignore_flags: Ignore::None })
    }

    pub fn ignore(&mut self, flags: Ignore) {
        self.ignore_flags = flags;
    }

    pub fn port_count(&self) -> u32 {
        unsafe { midiInGetNumDevs() }
    }

    pub fn port_name(&self, port_number: u32) -> Result<String, PortInfoError> {
        use std::fmt::Write;

        let mut device_caps: MIDIINCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiInGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIINCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        }
        assert!(result == MMSYSERR_NOERROR, "could not retrieve Windows MM MIDI input port name");
        let mut output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();

        // Next lines added to add the portNumber to the name so that
        // the device's names are sure to be listed with individual names
        // even when they have the same brand name
        let _ = write!(&mut output, " {}", port_number);
        Ok(output)
    }

    pub fn connect<F, T: Send>(
        self, port_number: u32, _port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(f64, &[u8], &mut T) + Send + 'static {

        let mut handler_data = Box::new(HandlerData {
            message: MidiMessage::new(),
            last_time: None,
            sysex_buffer: unsafe { mem::uninitialized() },
            in_handle: None,
            ignore_flags: self.ignore_flags,
            callback: Box::new(callback),
            user_data: Some(data)
        });

        let mut in_handle: HMIDIIN = unsafe { mem::uninitialized() };
        let result = unsafe { midiInOpen(&mut in_handle,
                        port_number,
                        handler::handle_input::<T> as DWORD_PTR,
                        mem::transmute_copy::<_, *mut HandlerData<T>>(&handler_data) as DWORD_PTR,
                        CALLBACK_FUNCTION) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI input port", self));
        }

        // Allocate and init the sysex buffers.
        for i in 0..RT_SYSEX_BUFFER_COUNT {
            handler_data.sysex_buffer[i] = Box::into_raw(Box::new(MIDIHDR {
                lpData: unsafe { allocate(RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/) } as *mut i8,
                dwBufferLength: RT_SYSEX_BUFFER_SIZE as u32,
                dwBytesRecorded: 0,
                dwUser: i as DWORD_PTR, // We use the dwUser parameter as buffer indicator
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            }));

            // TODO: are those buffers ever freed if an error occurs here (altough these calls probably only fail with out-of-memory)?
            // TODO: close port in case of error?

            let result = unsafe { midiInPrepareHeader(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (PrepareHeader)", self));
            }

            // Register the buffer.
            let result = unsafe { midiInAddBuffer(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (AddBuffer)", self));
            }
        }

        handler_data.in_handle = Some(Mutex::new(in_handle));

        // We can safely access (a copy of) `in_handle` here, although
        // it has been copied into the Mutex already, because the callback
        // has not been called yet.
        let result = unsafe { midiInStart(in_handle) };
        if result != MMSYSERR_NOERROR {
            unsafe { midiInClose(in_handle) };
            return Err(ConnectError::other("could not start Windows MM MIDI input port", self));
        }

        Ok(MidiInputConnection {
            handler_data: handler_data
        })
    }
}

impl<T> MidiInputConnection<T> {
    pub fn close(mut self) -> (MidiInput, T) {
        self.close_internal();

        (MidiInput {
            ignore_flags: self.handler_data.ignore_flags,
        }, self.handler_data.user_data.take().unwrap())
    }

    fn close_internal(&mut self) {
        // for information about his lock, see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
        let in_handle_lock = self.handler_data.in_handle.as_ref().unwrap().lock().unwrap();

        // TODO: Call both reset and stop here? The difference seems to be that
        //       reset "returns all pending input buffers to the callback function"
        unsafe {
            midiInReset(*in_handle_lock);
            midiInStop(*in_handle_lock);
        }

        for i in 0..RT_SYSEX_BUFFER_COUNT {
            let result;
            unsafe {
                result = midiInUnprepareHeader(*in_handle_lock, self.handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32);
                deallocate((*self.handler_data.sysex_buffer[i]).lpData as *mut u8, RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/);
                // recreate the Box so that it will be dropped/deallocated at the end of this scope
                let _ = Box::from_raw(self.handler_data.sysex_buffer[i]);
            }

            if result != MMSYSERR_NOERROR {
                let _ = writeln!(stderr(), "Warning: Ignoring error shutting down Windows MM input port (UnprepareHeader).");
            }
        }

        unsafe { midiInClose(*in_handle_lock) };
    }
}

impl<T> Drop for MidiInputConnection<T> {
    fn drop(&mut self) {
        // If user_data has been emptied, we know that we already have closed the connection
        if self.handler_data.user_data.is_some() {
            self.close_internal()
        }
    }
}

#[derive(Debug)]
pub struct MidiOutput;

pub struct MidiOutputConnection {
    out_handle: HMIDIOUT,
}

impl MidiOutput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiOutput)
    }

    pub fn port_count(&self) -> u32 {
        unsafe { midiOutGetNumDevs() }
    }

    pub fn port_name(&self, port_number: u32) -> Result<String, PortInfoError> {
        use std::fmt::Write;

        let mut device_caps: MIDIOUTCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiOutGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIINCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        }
        assert!(result == MMSYSERR_NOERROR, "could not retrieve Windows MM MIDI output port name");
        let mut output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();

        // Next lines added to add the portNumber to the name so that
        // the device's names are sure to be listed with individual names
        // even when they have the same brand name
        let _ = write!(&mut output, " {}", port_number);
        Ok(output)
    }

    pub fn connect(self, port_number: u32, _port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        let mut out_handle = unsafe { mem::uninitialized() };

        let result = unsafe { midiOutOpen(&mut out_handle, port_number, 0, 0, CALLBACK_NULL) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI output port", self));
        }

        Ok(MidiOutputConnection {
            out_handle: out_handle
        })
    }
}

impl MidiOutputConnection {
    pub fn close(self) -> MidiOutput {
        // The actual closing is done by the implementation of Drop
        MidiOutput // In this API this is a noop
    }

    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        let nbytes = message.len();
        if nbytes == 0 {
            return Err(SendError::InvalidData("message to be sent must not be empty"));
        }

        if message[0] == 0xF0 { // Sysex message
            // Allocate buffer for sysex data and copy message
            let mut buffer = message.to_vec();

            // Create and prepare MIDIHDR structure.
            let mut sysex = MIDIHDR {
                lpData: buffer.as_mut_ptr() as *mut i8,
                dwBufferLength: nbytes as u32,
                dwBytesRecorded: 0,
                dwUser: 0,
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            };

            let result = unsafe { midiOutPrepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };

            if result != MMSYSERR_NOERROR {
                return Err(SendError::Other("preparation for sending sysex message failed (OutPrepareHeader)"));
            }

            // Send the message.
            loop {
                let result = unsafe { midiOutLongMsg(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending sysex message failed"));
                    }
                    break;
                }
            }

            loop {
                let result = unsafe { midiOutUnprepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_STILLPLAYING {
                    sleep(Duration::from_millis(1));
                    continue;
                } else { break; }
            }
        } else { // Channel or system message.
            // Make sure the message size isn't too big.
            if nbytes > 3 {
                return Err(SendError::InvalidData("non-sysex message must not be longer than 3 bytes"));
            }

            // Pack MIDI bytes into double word.
            let packet: DWORD = 0;
            let ptr = &packet as *const u32 as *mut u8;
            for i in 0..nbytes {
                unsafe { *ptr.offset(i as isize) = message[i] };
            }

            // Send the message immediately.
            loop {
                let result = unsafe { midiOutShortMsg(self.out_handle, packet) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending non-sysex message failed"));
                    }
                    break;
                }
            }
        }

        Ok(())
    }
}

impl Drop for MidiOutputConnection {
    fn drop(&mut self) {
        unsafe {
            midiOutReset(self.out_handle);
            midiOutClose(self.out_handle);
        }
    }
}<commit_msg>Removed a transmute<commit_after>use std::{mem, ptr, slice};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::Mutex;
use std::io::{stderr, Write};
use std::thread::sleep;
use std::time::Duration;
use memalloc::{allocate, deallocate};

use winapi::*;

use winmm_sys::{
    midiInGetNumDevs,
    midiInGetDevCapsW,
    midiInOpen,
    midiInStart,
    midiInClose,
    midiInReset,
    midiInStop,
    midiInAddBuffer,
    midiInPrepareHeader,
    midiInUnprepareHeader,
    midiOutGetNumDevs,
    midiOutGetDevCapsW,
    midiOutOpen,
    midiOutReset,
    midiOutClose,
    midiOutPrepareHeader,
    midiOutUnprepareHeader,
    midiOutLongMsg,
    midiOutShortMsg,
};

use ::{MidiMessage, Ignore};
use ::errors::*;

mod handler;

const RT_SYSEX_BUFFER_SIZE: usize = 1024;
const RT_SYSEX_BUFFER_COUNT: usize = 4;

// helper for string conversion
fn from_wide_ptr<'a>(ptr: *const u16, max_len: usize) -> OsString {
    unsafe {
        assert!(!ptr.is_null());
        let len = (0..max_len as isize).position(|i| *ptr.offset(i) == 0).unwrap();
        let slice = slice::from_raw_parts(ptr, len);
        OsString::from_wide(slice)
    }
}

// TODO: make sure that these structs are all `Send`

#[derive(Debug)]
pub struct MidiInput {
    ignore_flags: Ignore
}

pub struct MidiInputConnection<T> {
    handler_data: Box<HandlerData<T>>,
}

/// This is all the data that is stored on the heap as long as a connection
/// is opened and passed to the callback handler.
///
/// It is important that `user_data` is the last field to not influence
/// offsets after monomorphization.
struct HandlerData<T> {
    message: MidiMessage,
    last_time: Option<u64>,
    sysex_buffer: [LPMIDIHDR; RT_SYSEX_BUFFER_COUNT],
    in_handle: Option<Mutex<HMIDIIN>>,
    ignore_flags: Ignore,
    callback: Box<FnMut(f64, &[u8], &mut T)+Send>,
    user_data: Option<T>
}

impl MidiInput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiInput { ignore_flags: Ignore::None })
    }

    pub fn ignore(&mut self, flags: Ignore) {
        self.ignore_flags = flags;
    }

    pub fn port_count(&self) -> u32 {
        unsafe { midiInGetNumDevs() }
    }

    pub fn port_name(&self, port_number: u32) -> Result<String, PortInfoError> {
        use std::fmt::Write;

        let mut device_caps: MIDIINCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiInGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIINCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        }
        assert!(result == MMSYSERR_NOERROR, "could not retrieve Windows MM MIDI input port name");
        let mut output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();

        // Next lines added to add the portNumber to the name so that
        // the device's names are sure to be listed with individual names
        // even when they have the same brand name
        let _ = write!(&mut output, " {}", port_number);
        Ok(output)
    }

    pub fn connect<F, T: Send>(
        self, port_number: u32, _port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(f64, &[u8], &mut T) + Send + 'static {

        let mut handler_data = Box::new(HandlerData {
            message: MidiMessage::new(),
            last_time: None,
            sysex_buffer: unsafe { mem::uninitialized() },
            in_handle: None,
            ignore_flags: self.ignore_flags,
            callback: Box::new(callback),
            user_data: Some(data)
        });

        let mut in_handle: HMIDIIN = unsafe { mem::uninitialized() };
        let handler_data_ptr: *mut HandlerData<T> = &mut *handler_data;
        let result = unsafe { midiInOpen(&mut in_handle,
                        port_number,
                        handler::handle_input::<T> as DWORD_PTR,
                        handler_data_ptr as DWORD_PTR,
                        CALLBACK_FUNCTION) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI input port", self));
        }

        // Allocate and init the sysex buffers.
        for i in 0..RT_SYSEX_BUFFER_COUNT {
            handler_data.sysex_buffer[i] = Box::into_raw(Box::new(MIDIHDR {
                lpData: unsafe { allocate(RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/) } as *mut i8,
                dwBufferLength: RT_SYSEX_BUFFER_SIZE as u32,
                dwBytesRecorded: 0,
                dwUser: i as DWORD_PTR, // We use the dwUser parameter as buffer indicator
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            }));

            // TODO: are those buffers ever freed if an error occurs here (altough these calls probably only fail with out-of-memory)?
            // TODO: close port in case of error?

            let result = unsafe { midiInPrepareHeader(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (PrepareHeader)", self));
            }

            // Register the buffer.
            let result = unsafe { midiInAddBuffer(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (AddBuffer)", self));
            }
        }

        handler_data.in_handle = Some(Mutex::new(in_handle));

        // We can safely access (a copy of) `in_handle` here, although
        // it has been copied into the Mutex already, because the callback
        // has not been called yet.
        let result = unsafe { midiInStart(in_handle) };
        if result != MMSYSERR_NOERROR {
            unsafe { midiInClose(in_handle) };
            return Err(ConnectError::other("could not start Windows MM MIDI input port", self));
        }

        Ok(MidiInputConnection {
            handler_data: handler_data
        })
    }
}

impl<T> MidiInputConnection<T> {
    pub fn close(mut self) -> (MidiInput, T) {
        self.close_internal();

        (MidiInput {
            ignore_flags: self.handler_data.ignore_flags,
        }, self.handler_data.user_data.take().unwrap())
    }

    fn close_internal(&mut self) {
        // for information about his lock, see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
        let in_handle_lock = self.handler_data.in_handle.as_ref().unwrap().lock().unwrap();

        // TODO: Call both reset and stop here? The difference seems to be that
        //       reset "returns all pending input buffers to the callback function"
        unsafe {
            midiInReset(*in_handle_lock);
            midiInStop(*in_handle_lock);
        }

        for i in 0..RT_SYSEX_BUFFER_COUNT {
            let result;
            unsafe {
                result = midiInUnprepareHeader(*in_handle_lock, self.handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32);
                deallocate((*self.handler_data.sysex_buffer[i]).lpData as *mut u8, RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/);
                // recreate the Box so that it will be dropped/deallocated at the end of this scope
                let _ = Box::from_raw(self.handler_data.sysex_buffer[i]);
            }

            if result != MMSYSERR_NOERROR {
                let _ = writeln!(stderr(), "Warning: Ignoring error shutting down Windows MM input port (UnprepareHeader).");
            }
        }

        unsafe { midiInClose(*in_handle_lock) };
    }
}

impl<T> Drop for MidiInputConnection<T> {
    fn drop(&mut self) {
        // If user_data has been emptied, we know that we already have closed the connection
        if self.handler_data.user_data.is_some() {
            self.close_internal()
        }
    }
}

#[derive(Debug)]
pub struct MidiOutput;

pub struct MidiOutputConnection {
    out_handle: HMIDIOUT,
}

impl MidiOutput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiOutput)
    }

    pub fn port_count(&self) -> u32 {
        unsafe { midiOutGetNumDevs() }
    }

    pub fn port_name(&self, port_number: u32) -> Result<String, PortInfoError> {
        use std::fmt::Write;

        let mut device_caps: MIDIOUTCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiOutGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIINCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        }
        assert!(result == MMSYSERR_NOERROR, "could not retrieve Windows MM MIDI output port name");
        let mut output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();

        // Next lines added to add the portNumber to the name so that
        // the device's names are sure to be listed with individual names
        // even when they have the same brand name
        let _ = write!(&mut output, " {}", port_number);
        Ok(output)
    }

    pub fn connect(self, port_number: u32, _port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        let mut out_handle = unsafe { mem::uninitialized() };

        let result = unsafe { midiOutOpen(&mut out_handle, port_number, 0, 0, CALLBACK_NULL) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI output port", self));
        }

        Ok(MidiOutputConnection {
            out_handle: out_handle
        })
    }
}

impl MidiOutputConnection {
    pub fn close(self) -> MidiOutput {
        // The actual closing is done by the implementation of Drop
        MidiOutput // In this API this is a noop
    }

    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        let nbytes = message.len();
        if nbytes == 0 {
            return Err(SendError::InvalidData("message to be sent must not be empty"));
        }

        if message[0] == 0xF0 { // Sysex message
            // Allocate buffer for sysex data and copy message
            let mut buffer = message.to_vec();

            // Create and prepare MIDIHDR structure.
            let mut sysex = MIDIHDR {
                lpData: buffer.as_mut_ptr() as *mut i8,
                dwBufferLength: nbytes as u32,
                dwBytesRecorded: 0,
                dwUser: 0,
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            };

            let result = unsafe { midiOutPrepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };

            if result != MMSYSERR_NOERROR {
                return Err(SendError::Other("preparation for sending sysex message failed (OutPrepareHeader)"));
            }

            // Send the message.
            loop {
                let result = unsafe { midiOutLongMsg(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending sysex message failed"));
                    }
                    break;
                }
            }

            loop {
                let result = unsafe { midiOutUnprepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_STILLPLAYING {
                    sleep(Duration::from_millis(1));
                    continue;
                } else { break; }
            }
        } else { // Channel or system message.
            // Make sure the message size isn't too big.
            if nbytes > 3 {
                return Err(SendError::InvalidData("non-sysex message must not be longer than 3 bytes"));
            }

            // Pack MIDI bytes into double word.
            let packet: DWORD = 0;
            let ptr = &packet as *const u32 as *mut u8;
            for i in 0..nbytes {
                unsafe { *ptr.offset(i as isize) = message[i] };
            }

            // Send the message immediately.
            loop {
                let result = unsafe { midiOutShortMsg(self.out_handle, packet) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending non-sysex message failed"));
                    }
                    break;
                }
            }
        }

        Ok(())
    }
}

impl Drop for MidiOutputConnection {
    fn drop(&mut self) {
        unsafe {
            midiOutReset(self.out_handle);
            midiOutClose(self.out_handle);
        }
    }
}<|endoftext|>


<commit_before>use primal_bit::BitVec;

pub struct BehavioralBitvec {
    bitvec: BitVec,
    bitpos: usize,
}

impl BehavioralBitvec {
    pub fn new(n: usize) -> Self {
        BehavioralBitvec {
            bitvec: BitVec::from_elem(n, false),
            bitpos: 0,
        }
    }

    #[inline]
    pub fn push(&mut self, output: f64) {
        if output >= 0.0 {
            self.bitvec.set(self.bitpos, true);
        }
        self.bitpos += 1;
    }
}

<commit_msg>Add hamming distance and test cases<commit_after>use primal_bit::BitVec;
use hamming;

pub struct BehavioralBitvec {
    bitvec: BitVec,
    bitpos: usize,
}

impl BehavioralBitvec {
    pub fn new(n: usize) -> Self {
        BehavioralBitvec {
            bitvec: BitVec::from_elem(n, false),
            bitpos: 0,
        }
    }

    pub fn hamming_distance(&self, other: &Self) -> u64 {
        hamming::distance_fast(self.bitvec.as_bytes(), other.bitvec.as_bytes()).unwrap()
    }

    #[inline]
    pub fn push(&mut self, output: f64) {
        if output >= 0.0 {
            self.bitvec.set(self.bitpos, true);
        }
        self.bitpos += 1;
    }
}

#[test]
fn test_behavioral_bitvec() {
   let mut a = BehavioralBitvec::new(3);
   let mut b = BehavioralBitvec::new(3);

   // [1, 1, 0]
   a.push(1.0);
   a.push(2.0);
   a.push(-1.0);
   let ba: Vec<_> = a.bitvec.iter().collect();

   // [0, 1, 1]
   b.push(-1.0);
   b.push(1.0);
   b.push(1.0);
   let bb: Vec<_> = b.bitvec.iter().collect();

   assert_eq!(vec![true, true, false], ba);
   assert_eq!(vec![false, true, true], bb);

   let d1 = a.hamming_distance(&b);
   let d2 = b.hamming_distance(&a);

   assert_eq!(d1, d2);
   assert_eq!(2, d1);
}
<|endoftext|>


<commit_before>use std::rc::{Rc,Weak};
use std::collections::hash_map::{HashMap,Entry};
use std::collections::hash_state::HashState;
use std::cell::RefCell;

use router::Router;

#[derive(Clone,Debug)]
pub struct StoreValue {
    last_changed: usize,
}

pub trait DBStore {
    fn get_value(&self, k: &str) -> Option<StoreValue>;
    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue>;
}

impl <S> DBStore for HashMap<String,StoreValue,S>
where S: HashState {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        self.get(k).cloned()
    }

    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue> {
        match self.get_mut(k) {
            None => Some(value),
            Some(entry) => {
                *entry = value;
                None
            }
        }
    }
}

impl <T> DBStore for [T]
where T: DBStore {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        for i in self.iter().rev() {
            let value = i.get_value(k);
            if value.is_some() {
                return value;
            }
        }
        None
    }

    fn set_value(&mut self, k: &str, mut value: StoreValue) -> Option<StoreValue> {
        for i in self.iter_mut().rev() {
            match i.set_value(k, value) {
                None => return None,
                Some(ret) => value = ret,
            }
        }
        Some(value)
    }
}

impl <'a> DBStore for Box<DBStore + 'a> {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        (**self).get_value(k)
    }

    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue> {
        (**self).set_value(k, value)
    }
}

#[derive(Default)]
pub struct DataBinderContext {
    global_values: HashMap<String,StoreValue>,
    global_context: Vec<Box<DBStore>>,
    views_context: HashMap<String,Vec<Box<DBStore>>>,
    current_view: String,
}

impl DataBinderContext {
    pub fn new(router: &Router) -> DataBinderContext {
        let mut binder = DataBinderContext::default();
        binder.register_views(router);
        binder
    }

    pub fn register_views(&mut self, router: &Router) {
        // XXX: Could have better implementation: use Entry
        for name in router.iter_name_views() {
            self.views_context.entry(name.clone()).or_insert(Vec::new());
        }
    }

    pub fn register_global_single_value(&mut self, key: String, value: StoreValue) {
        // XXX: Any better way to handle the log?
        match self.global_values.entry(key.clone()) {
            Entry::Occupied(mut occupied) => {
                // TODO: Use log
                println!("WARNING: registering an already existing value for key {} : {:?}", key, occupied.get());
                occupied.insert(value);
            }
            Entry::Vacant(v) => {
                v.insert(value);
            }
        }
    }

    pub fn register_global<T>(&mut self, scope: usize, value: Rc<RefCell<T>>)
    where T: DBStore + 'static {
        let v = Box::new(Proxy::new(value));
        let len = self.global_context.len();
        self.global_context.insert(::std::cmp::max(scope, len), v);
    }

    pub fn register_for_view<T>(&mut self, view: &str, scope: usize, value: Rc<RefCell<T>>) -> Result<(),String>
    where T: DBStore + 'static {
        let v = Box::new(Proxy::new(value));
        let len = self.global_context.len();
        match self.views_context.get_mut(view) {
            None => Err(format!("Could not find view {}", view)),
            Some(vec) => {
                vec.insert(::std::cmp::max(scope, len), v);
                Ok(())
            }
        }
    }
}

// Private trait for UIL
pub trait DBCLookup {
    fn get_value(&self, k: &str) -> Option<StoreValue>;
    fn set_value(&mut self, k: &str, value: StoreValue);
}

impl DBCLookup for DataBinderContext {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        match self.views_context.get(&self.current_view) {
            None => {
                println!("WARNING: Did not find view {}", &self.current_view);
            }
            Some(view_store) => {
                let result = view_store.get_value(k);
                if result.is_some() {
                    return result;
                }
            }
        }
        // Did not find view, or view did not have the corresponding value
        let result = self.global_context.get_value(k);
        if result.is_some() {
            return result;
        }
        self.global_values.get_value(k)
    }

    fn set_value(&mut self, k: &str, value: StoreValue) {
        match self.views_context.get_mut(&self.current_view) {
            None => {
                println!("WARNING: Did not find view {}", &self.current_view);
            }
            Some(view_store) => {
                let result = view_store.set_value(k, value);
                match result {
                    None => {},
                    Some(a) => {
                        match self.global_context.set_value(k, a) {
                            None => {},
                            Some(a) => {self.global_values.set_value(k, a);}
                        }
                    }
                }
            }
        }
    }
}

struct Proxy<T: DBStore> {
    data: Weak<RefCell<T>>,
}

impl <T> DBStore for Proxy<T>
where T: DBStore {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        match self.data.upgrade() {
            None => None,
            Some(p) => p.borrow().get_value(k),
        }
    }

    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue> {
        match self.data.upgrade() {
            None => Some(value),
            Some(p) => p.borrow_mut().set_value(k, value),
        }
    }
}

impl <T: DBStore> Proxy<T> {
    fn new(value: Rc<RefCell<T>>) -> Proxy<T> {
        Proxy {
            data: value.downgrade(),
        }
    }
}
<commit_msg>Simple data bindings should now work<commit_after>use std::rc::{Rc,Weak};
use std::collections::HashMap;
use std::collections::hash_state::HashState;
use std::cell::RefCell;

use router::Router;

macro_rules! declare_data_binding {
    ($name:ident {
        $($field:ident:$type_field:ty),*
    }) => (
        declare_data_binding! {
            $name {
                $($field -> $field: $type_field),*
            }
        }
        );
    ($name:ident {
        $($key:ident -> $field:ident : $type_field:ty),*
    }) => (
        impl DBStore for $name {
            fn get_value(&self, k: &str) -> Option<StoreValue> {
                match k {
                    $(stringify!($key) => Some(StoreValue{data: self.$field.to_string()}),)*
                    _ => None,
                }
            }
            fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue> {
                use std::str::FromStr;
                match k {
                    $(stringify!($key) => {
                        match <$type_field as FromStr>::from_str(&value.data) {
                            Ok(value) => {
                                self.$field = value;
                                None
                            }
                            Err(..) => {
                                println!("WARNING: Failed to parse data binding {} as {}", &value.data, stringify!($type_field));
                                Some(value)
                            }
                        }
                    })*
                    _ => Some(value),
                }
            }
        }

        )
}

#[derive(Clone,Debug)]
pub struct StoreValue {
    data: String,
}

pub trait DBStore: ::std::fmt::Debug {
    fn get_value(&self, k: &str) -> Option<StoreValue>;
    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue>;
}

impl <S> DBStore for HashMap<String,StoreValue,S>
where S: HashState {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        self.get(k).cloned()
    }

    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue> {
        match self.get_mut(k) {
            None => Some(value),
            Some(entry) => {
                *entry = value;
                None
            }
        }
    }
}

impl <T> DBStore for [T]
where T: DBStore {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        for i in self.iter().rev() {
            let value = i.get_value(k);
            if value.is_some() {
                return value;
            }
        }
        None
    }

    fn set_value(&mut self, k: &str, mut value: StoreValue) -> Option<StoreValue> {
        for i in self.iter_mut().rev() {
            match i.set_value(k, value) {
                None => return None,
                Some(ret) => value = ret,
            }
        }
        Some(value)
    }
}

impl <'a> DBStore for Box<DBStore + 'a> {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        (**self).get_value(k)
    }

    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue> {
        (**self).set_value(k, value)
    }
}

#[derive(Default,Debug)]
struct DataBinderScope {
    values: HashMap<String,StoreValue>,
    stores: HashMap<String,Box<DBStore>>,
}

impl DBStore for DataBinderScope {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        for (prefix, key) in PrefixKeyIterator::new(k) {
            if let Some(store) = self.stores.get(prefix) {
                // If we have a store registered, we look here first
                let result = store.get_value(key);
                if result.is_some() {
                    return result;
                }
            }
        }
        self.values.get_value(k)
    }

    fn set_value(&mut self, k: &str, mut value: StoreValue) -> Option<StoreValue> {
        for (prefix, key) in PrefixKeyIterator::new(k) {
            if let Some(store) = self.stores.get_mut(prefix) {
                // If we have a store registered, we look here first
                match store.set_value(key, value) {
                    None => return None,
                    Some(ret) => value = ret,
                }
            }
        }
        self.values.set_value(k, value)
    }
}

impl DataBinderScope {
    fn register_value(&mut self, key: String, value: StoreValue) -> Result<(),StoreValue> {
        match self.values.insert(key, value) {
            Some(old) => Err(old),
            None => Ok(()),
        }
    }

    fn register_store(&mut self, prefix: String, store: Box<DBStore + 'static>)
        -> Result<(),Box<DBStore + 'static>> {
        match self.stores.insert(prefix, store) {
            Some(old) => Err(old),
            None => Ok(()),
        }
    }
}

#[derive(Default)]
pub struct DataBinderContext {
    global: DataBinderScope,
    views: HashMap<String,DataBinderScope>,
    current_view: String,
}

impl DataBinderContext {
    pub fn new(router: &Router) -> DataBinderContext {
        let mut binder = DataBinderContext::default();
        binder.register_views(router);
        binder
    }

    pub fn register_views(&mut self, router: &Router) {
        for name in router.iter_name_views() {
            self.register_view(name.clone());
        }
    }

    pub fn switch_to_view(&mut self, view: String) {
        self.current_view = view;
    }

    pub fn register_global_value(&mut self, key: String, value: StoreValue) {
        if let Err(old) = self.global.register_value(key.clone(), value) {
            println!("WARNING: re-registering global value {} (old value {:?})", key, old);
        }
    }

    pub fn register_global_store<T>(&mut self, prefix: String, value: Rc<RefCell<T>>)
    where T: DBStore + 'static {
        let v = Box::new(Proxy::new(value));
        if let Err(old) = self.global.register_store(prefix.clone(), v) {
            println!("WARNING: overriding global object {} (old value {:?})", prefix, old);
        }
    }

    pub fn register_value(&mut self, view: &str, key: String, value: StoreValue) -> Result<(),String> {
        match self.views.get_mut(view) {
            None => Err(format!("Could not find view {}", view)),
            Some(view_scope) => {
                if let Err(old) = view_scope.register_value(key.clone(), value) {
                    // Don't throw an error, just print a warning
                    println!("WARNING: View {}: re-registering value {} (old value {:?})", view, key, old);
                }
                Ok(())
            }
        }
    }

    pub fn register_store<T>(&mut self, view: &str, prefix: String, value: Rc<RefCell<T>>) -> Result<(),String>
    where T: DBStore + 'static {
        match self.views.get_mut(view) {
            None => Err(format!("Could not find view {}", view)),
            Some(view_scope) => {
                let v = Box::new(Proxy::new(value));
                if let Err(old) = view_scope.register_store(prefix.clone(), v) {
                    // Don't throw an error, just print a warning
                    println!("WARNING: View {}: overriding object {} (old value {:?})", view, prefix, old);
                }
                Ok(())
            }
        }
    }

    fn register_view(&mut self, view: String) {
        self.views.entry(view).or_insert_with(|| DataBinderScope::default());
    }
}

// Private trait for UIL
pub trait DBCLookup {
    fn get_value(&self, k: &str) -> Option<StoreValue>;
    fn set_value(&mut self, k: &str, value: StoreValue);
}

impl DBCLookup for DataBinderContext {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        match self.views.get(&self.current_view) {
            None => {
                println!("WARNING: Did not find view {}", &self.current_view);
            }
            Some(view_store) => {
                let result = view_store.get_value(k);
                if result.is_some() {
                    return result;
                }
            }
        }
        // Did not find view, or view did not have the corresponding value
        self.global.get_value(k)
    }

    fn set_value(&mut self, k: &str, value: StoreValue) {
        match self.views.get_mut(&self.current_view) {
            None => {
                println!("WARNING: Did not find view {}", &self.current_view);
            }
            Some(view_store) => {
                let result = view_store.set_value(k, value);
                match result {
                    None => {},
                    Some(value) => {
                        self.global.set_value(k, value);
                    }
                }
            }
        }
    }
}

#[derive(Debug)]
struct Proxy<T: DBStore> {
    data: Weak<RefCell<T>>,
}

impl <T> DBStore for Proxy<T>
where T: DBStore {
    fn get_value(&self, k: &str) -> Option<StoreValue> {
        match self.data.upgrade() {
            None => None,
            Some(p) => p.borrow().get_value(k),
        }
    }

    fn set_value(&mut self, k: &str, value: StoreValue) -> Option<StoreValue> {
        match self.data.upgrade() {
            None => Some(value),
            Some(p) => p.borrow_mut().set_value(k, value),
        }
    }
}

impl <T: DBStore> Proxy<T> {
    fn new(value: Rc<RefCell<T>>) -> Proxy<T> {
        Proxy {
            data: value.downgrade(),
        }
    }
}

// An iterator over the different combinations of prefix-key
struct PrefixKeyIterator<'a> {
    data: &'a str,
    position: i8,
}

impl <'a> PrefixKeyIterator<'a> {
    fn new(data: &'a str) -> PrefixKeyIterator<'a> {
        PrefixKeyIterator {
            data: data,
            position: 0,
        }
    }
}

impl <'a> Iterator for PrefixKeyIterator<'a> {
    type Item = (&'a str, &'a str);

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        if self.position == 0 {
            self.position += 1;
            return Some(("", self.data));
        }
        let mut position = self.position;
        self.position += 1;
        let mut iterator = self.data.split(|c| {
            if c == '.' {
                position -= 1;
                if position == 0 {
                    return true;
                }
            }
            false
        });
        let prefix = match iterator.next() {
            None => return None,
            Some(a) => a,
        };
        let key = match iterator.next() {
            None => return None,
            Some(a) => a,
        };
        Some((prefix,key))
    }
}

#[cfg(test)]
mod test {
    use std::rc::Rc;
    use std::cell::RefCell;
    use super::*;
#[derive(Debug)]
    struct Player {
        pv: usize,
        xp: usize,
    }

    declare_data_binding! {
        Player {
            pv: usize,
            xp: usize
        }
    }

    #[test]
    fn register_global_player() {
        let mut context = DataBinderContext::default();
        let player = Rc::new(RefCell::new(Player{pv: 42, xp: 100}));
        // Clone the Rc, as it will get downgraded to Weak when registered
        context.register_global_store("player".to_string(), player.clone());
        assert_eq!(context.get_value("player.pv").unwrap().data, "42");
        assert_eq!(context.get_value("player.xp").unwrap().data, "100");
    }

    #[test]
    fn register_global_value() {
        let mut context = DataBinderContext::default();
        context.register_global_value("option.width".to_string(),
            StoreValue{data: "42".to_string()});
        assert_eq!(context.get_value("option.width").unwrap().data, "42");
    }

    #[test]
    fn register_view_player() {
        let mut context = DataBinderContext::default();
        context.register_view("foo".to_string());
        let player = Rc::new(RefCell::new(Player{pv: 42, xp: 100}));
        // Clone the Rc, as it will get downgraded to Weak when registered
        context.register_store("foo", "player".to_string(), player.clone()).unwrap();

        // Not in the correct view
        assert!(context.get_value("player.pv").is_none());
        context.switch_to_view("foo".to_string());
        assert_eq!(context.get_value("player.pv").unwrap().data, "42");
        assert_eq!(context.get_value("player.xp").unwrap().data, "100");
    }

    #[test]
    fn register_view_value() {
        let mut context = DataBinderContext::default();
        context.register_view("foo".to_string());
        context.register_value("foo", "option.width".to_string(),
            StoreValue{data: "42".to_string()}).unwrap();
        assert!(context.get_value("option.width").is_none());
        context.switch_to_view("foo".to_string());
        assert_eq!(context.get_value("option.width").unwrap().data, "42");
    }

    #[test]
    fn masking_value_by_object() {
        let mut context = DataBinderContext::default();
        context.register_global_value("player.pv".to_string(),
            StoreValue{data: "12".to_string()});
        assert_eq!(context.get_value("player.pv").unwrap().data, "12");
        let player = Rc::new(RefCell::new(Player{pv: 42, xp: 100}));
        // Clone the Rc, as it will get downgraded to Weak when registered
        context.register_global_store("player".to_string(), player.clone());
        assert_eq!(context.get_value("player.pv").unwrap().data, "42");
    }

    #[test]
    fn masking_global_value_by_view() {
        let foo = "foo".to_string();
        let bar = "bar".to_string();
        let mut context = DataBinderContext::default();
        context.register_view(foo.clone());
        context.register_view(bar.clone());
        context.register_view("foobar".to_string());
        context.register_value("foo", "option.width".to_string(),
            StoreValue{data: "foo_value".to_string()}).unwrap();
        context.register_value("bar", "option.width".to_string(),
            StoreValue{data: "bar_value".to_string()}).unwrap();
        context.register_global_value("option.width".to_string(),
            StoreValue{data: "global_value".to_string()});

        // In view "foobar" -> get global value
        context.switch_to_view("foobar".to_string());
        assert_eq!(context.get_value("option.width").unwrap().data, "global_value");
        // In view "foo" -> get foo specific value
        context.switch_to_view("foo".to_string());
        assert_eq!(context.get_value("option.width").unwrap().data, "foo_value");
        // In view "bar" -> get bar specific value
        context.switch_to_view("bar".to_string());
        assert_eq!(context.get_value("option.width").unwrap().data, "bar_value");
    }
}
<|endoftext|>


<commit_before>mod emit;
mod line_info;

use crate::prelude::*;

use rustc_span::FileName;

use cranelift_codegen::ir::{StackSlots, ValueLabel, ValueLoc};
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::ValueLocRange;

use gimli::write::{
    self, Address, AttributeValue, DwarfUnit, Expression, LineProgram, LineString, Location,
    LocationList, Range, RangeList, UnitEntryId, Writer,
};
use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64};

pub(crate) use emit::{DebugReloc, DebugRelocName};

fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian {
    use rustc_target::abi::Endian;

    match tcx.data_layout.endian {
        Endian::Big => RunTimeEndian::Big,
        Endian::Little => RunTimeEndian::Little,
    }
}

pub(crate) struct DebugContext<'tcx> {
    tcx: TyCtxt<'tcx>,

    endian: RunTimeEndian,
    symbols: indexmap::IndexMap<FuncId, String>,

    dwarf: DwarfUnit,
    unit_range_list: RangeList,

    types: FxHashMap<Ty<'tcx>, UnitEntryId>,
}

impl<'tcx> DebugContext<'tcx> {
    pub(crate) fn new(tcx: TyCtxt<'tcx>, address_size: u8) -> Self {
        let encoding = Encoding {
            format: Format::Dwarf32,
            // TODO: this should be configurable
            // macOS doesn't seem to support DWARF > 3
            // 5 version is required for md5 file hash
            version: if tcx.sess.target.target.options.is_like_osx {
                3
            } else {
                5
            },
            address_size,
        };

        let mut dwarf = DwarfUnit::new(encoding);

        // FIXME: how to get version when building out of tree?
        // Normally this would use option_env!("CFG_VERSION").
        let producer = format!("cg_clif (rustc {})", "unknown version");
        let comp_dir = tcx.sess.working_dir.0.to_string_lossy().into_owned();
        let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
            Some(path) => {
                let name = path.to_string_lossy().into_owned();
                let info = tcx.sess
                    .source_map()
                    .get_source_file(&FileName::Real(path))
                    .map(|f| f.src_hash)
                    .and_then(line_info::make_file_info);
                (name, info)
            },
            None => (tcx.crate_name(LOCAL_CRATE).to_string(), None),
        };

        let mut line_program = LineProgram::new(
            encoding,
            LineEncoding::default(),
            LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings),
            LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings),
            file_info,
        );
        line_program.file_has_md5 = file_info.is_some();

        dwarf.unit.line_program = line_program;

        {
            let name = dwarf.strings.add(name);
            let comp_dir = dwarf.strings.add(comp_dir);

            let root = dwarf.unit.root();
            let root = dwarf.unit.get_mut(root);
            root.set(
                gimli::DW_AT_producer,
                AttributeValue::StringRef(dwarf.strings.add(producer)),
            );
            root.set(
                gimli::DW_AT_language,
                AttributeValue::Language(gimli::DW_LANG_Rust),
            );
            root.set(gimli::DW_AT_name, AttributeValue::StringRef(name));
            root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir));
            root.set(
                gimli::DW_AT_low_pc,
                AttributeValue::Address(Address::Constant(0)),
            );
        }

        DebugContext {
            tcx,

            endian: target_endian(tcx),
            symbols: indexmap::IndexMap::new(),

            dwarf,
            unit_range_list: RangeList(Vec::new()),

            types: FxHashMap::default(),
        }
    }

    fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
        if let Some(type_id) = self.types.get(ty) {
            return *type_id;
        }

        let new_entry = |dwarf: &mut DwarfUnit, tag| dwarf.unit.add(dwarf.unit.root(), tag);

        let primitive = |dwarf: &mut DwarfUnit, ate| {
            let type_id = new_entry(dwarf, gimli::DW_TAG_base_type);
            let type_entry = dwarf.unit.get_mut(type_id);
            type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate));
            type_id
        };

        let name = format!("{}", ty);
        let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();

        let type_id = match ty.kind {
            ty::Bool => primitive(&mut self.dwarf, gimli::DW_ATE_boolean),
            ty::Char => primitive(&mut self.dwarf, gimli::DW_ATE_UTF),
            ty::Uint(_) => primitive(&mut self.dwarf, gimli::DW_ATE_unsigned),
            ty::Int(_) => primitive(&mut self.dwarf, gimli::DW_ATE_signed),
            ty::Float(_) => primitive(&mut self.dwarf, gimli::DW_ATE_float),
            ty::Ref(_, pointee_ty, _mutbl)
            | ty::RawPtr(ty::TypeAndMut {
                ty: pointee_ty,
                mutbl: _mutbl,
            }) => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let pointee = self.dwarf_ty(pointee_ty);

                let type_entry = self.dwarf.unit.get_mut(type_id);

                //type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc_hir::Mutability::Mut));
                type_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(pointee));

                type_id
            }
            ty::Adt(adt_def, _substs) if adt_def.is_struct() && !layout.is_unsized() => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let variant = adt_def.non_enum_variant();

                for (field_idx, field_def) in variant.fields.iter().enumerate() {
                    let field_offset = layout.fields.offset(field_idx);
                    let field_layout = layout.field(&layout::LayoutCx {
                        tcx: self.tcx,
                        param_env: ParamEnv::reveal_all(),
                    }, field_idx).unwrap();

                    let field_type = self.dwarf_ty(field_layout.ty);

                    let field_id = self.dwarf.unit.add(type_id, gimli::DW_TAG_member);
                    let field_entry = self.dwarf.unit.get_mut(field_id);

                    field_entry.set(gimli::DW_AT_name, AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()));
                    field_entry.set(gimli::DW_AT_data_member_location, AttributeValue::Udata(field_offset.bytes()));
                    field_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(field_type));
                }

                type_id
            }
            _ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type),
        };

        let type_entry = self.dwarf.unit.get_mut(type_id);

        type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        type_entry.set(
            gimli::DW_AT_byte_size,
            AttributeValue::Udata(layout.size.bytes()),
        );

        self.types.insert(ty, type_id);

        type_id
    }
}

pub(crate) struct FunctionDebugContext<'a, 'tcx> {
    debug_context: &'a mut DebugContext<'tcx>,
    entry_id: UnitEntryId,
    symbol: usize,
    instance: Instance<'tcx>,
    mir: &'tcx mir::Body<'tcx>,
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(crate) fn new(
        debug_context: &'a mut DebugContext<'tcx>,
        instance: Instance<'tcx>,
        func_id: FuncId,
        name: &str,
    ) -> Self {
        let mir = *debug_context.tcx.instance_mir(instance.def);

        let (symbol, _) = debug_context.symbols.insert_full(func_id, name.to_string());

        // FIXME: add to appropriate scope intead of root
        let scope = debug_context.dwarf.unit.root();

        let entry_id = debug_context
            .dwarf
            .unit
            .add(scope, gimli::DW_TAG_subprogram);
        let entry = debug_context.dwarf.unit.get_mut(entry_id);
        let name_id = debug_context.dwarf.strings.add(name);
        entry.set(
            gimli::DW_AT_linkage_name,
            AttributeValue::StringRef(name_id),
        );

        FunctionDebugContext {
            debug_context,
            entry_id,
            symbol,
            instance,
            mir,
        }
    }

    fn define_local(&mut self, name: String, ty: Ty<'tcx>) -> UnitEntryId {
        let ty = self.debug_context.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            &ty,
        );
        let dw_ty = self.debug_context.dwarf_ty(ty);

        let var_id = self
            .debug_context
            .dwarf
            .unit
            .add(self.entry_id, gimli::DW_TAG_variable);
        let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);

        var_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        var_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(dw_ty));

        var_id
    }

    pub(crate) fn define(
        &mut self,
        context: &Context,
        isa: &dyn TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
        local_map: FxHashMap<mir::Local, CPlace<'tcx>>,
    ) {
        let end = self.create_debug_lines(context, isa, source_info_set);

        self.debug_context
            .unit_range_list
            .0
            .push(Range::StartLength {
                begin: Address::Symbol {
                    symbol: self.symbol,
                    addend: 0,
                },
                length: end as u64,
            });

        // FIXME make it more reliable and implement scopes before re-enabling this.
        if false {
            let value_labels_ranges = context.build_value_labels_ranges(isa).unwrap();

            for (local, _local_decl) in self.mir.local_decls.iter_enumerated() {
                let var_id = self.define_local(format!("{:?}", local), &self.mir.local_decls[local].ty);

                let location = place_location(
                    self,
                    isa,
                    context,
                    &local_map,
                    &value_labels_ranges,
                    Place {
                        local,
                        projection: ty::List::empty(),
                    },
                );

                let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);
                var_entry.set(gimli::DW_AT_location, location);
            }
        }

        // FIXME create locals for all entries in mir.var_debug_info
    }
}

fn place_location<'a, 'tcx>(
    func_debug_ctx: &mut FunctionDebugContext<'a, 'tcx>,
    isa: &dyn TargetIsa,
    context: &Context,
    local_map: &FxHashMap<mir::Local, CPlace<'tcx>>,
    #[allow(rustc::default_hash_types)]
    value_labels_ranges: &std::collections::HashMap<ValueLabel, Vec<ValueLocRange>>,
    place: Place<'tcx>,
) -> AttributeValue {
    assert!(place.projection.is_empty()); // FIXME implement them

    match local_map[&place.local].inner() {
        CPlaceInner::Var(local) => {
            let value_label = cranelift_codegen::ir::ValueLabel::from_u32(local.as_u32());
            if let Some(value_loc_ranges) = value_labels_ranges.get(&value_label) {
                let loc_list = LocationList(
                    value_loc_ranges
                        .iter()
                        .map(|value_loc_range| Location::StartEnd {
                            begin: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.start),
                            },
                            end: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.end),
                            },
                            data: Expression(
                                translate_loc(isa, value_loc_range.loc, &context.func.stack_slots).unwrap(),
                            ),
                        })
                        .collect(),
                );
                let loc_list_id = func_debug_ctx.debug_context.dwarf.unit.locations.add(loc_list);

                AttributeValue::LocationListRef(loc_list_id)
            } else {
                // FIXME set value labels for unused locals

                AttributeValue::Exprloc(Expression(vec![]))
            }
        }
        CPlaceInner::Addr(_, _) => {
            // FIXME implement this (used by arguments and returns)

            AttributeValue::Exprloc(Expression(vec![]))

            // For PointerBase::Stack:
            //AttributeValue::Exprloc(Expression(translate_loc(ValueLoc::Stack(*stack_slot), &context.func.stack_slots).unwrap()))
        }
    }
}

// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137
fn translate_loc(isa: &dyn TargetIsa, loc: ValueLoc, stack_slots: &StackSlots) -> Option<Vec<u8>> {
    match loc {
        ValueLoc::Reg(reg) => {
            let machine_reg = isa.map_dwarf_register(reg).unwrap();
            assert!(machine_reg <= 32); // FIXME
            Some(vec![gimli::constants::DW_OP_reg0.0 + machine_reg as u8])
        }
        ValueLoc::Stack(ss) => {
            if let Some(ss_offset) = stack_slots[ss].offset {
                let endian = gimli::RunTimeEndian::Little;
                let mut writer = write::EndianVec::new(endian);
                writer
                    .write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8)
                    .expect("bp wr");
                writer.write_sleb128(ss_offset as i64 + 16).expect("ss wr");
                let buf = writer.into_vec();
                return Some(buf);
            }
            None
        }
        _ => None,
    }
}
<commit_msg>Use DWARF version 4 for now<commit_after>mod emit;
mod line_info;

use crate::prelude::*;

use rustc_span::FileName;

use cranelift_codegen::ir::{StackSlots, ValueLabel, ValueLoc};
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::ValueLocRange;

use gimli::write::{
    self, Address, AttributeValue, DwarfUnit, Expression, LineProgram, LineString, Location,
    LocationList, Range, RangeList, UnitEntryId, Writer,
};
use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64};

pub(crate) use emit::{DebugReloc, DebugRelocName};

fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian {
    use rustc_target::abi::Endian;

    match tcx.data_layout.endian {
        Endian::Big => RunTimeEndian::Big,
        Endian::Little => RunTimeEndian::Little,
    }
}

pub(crate) struct DebugContext<'tcx> {
    tcx: TyCtxt<'tcx>,

    endian: RunTimeEndian,
    symbols: indexmap::IndexMap<FuncId, String>,

    dwarf: DwarfUnit,
    unit_range_list: RangeList,

    types: FxHashMap<Ty<'tcx>, UnitEntryId>,
}

impl<'tcx> DebugContext<'tcx> {
    pub(crate) fn new(tcx: TyCtxt<'tcx>, address_size: u8) -> Self {
        let encoding = Encoding {
            format: Format::Dwarf32,
            // TODO: this should be configurable
            // macOS doesn't seem to support DWARF > 3
            // 5 version is required for md5 file hash
            version: if tcx.sess.target.target.options.is_like_osx {
                3
            } else {
                // FIXME change to version 5 once the gdb and lldb shipping with the latest debian
                // support it.
                4
            },
            address_size,
        };

        let mut dwarf = DwarfUnit::new(encoding);

        // FIXME: how to get version when building out of tree?
        // Normally this would use option_env!("CFG_VERSION").
        let producer = format!("cg_clif (rustc {})", "unknown version");
        let comp_dir = tcx.sess.working_dir.0.to_string_lossy().into_owned();
        let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
            Some(path) => {
                let name = path.to_string_lossy().into_owned();
                let info = tcx.sess
                    .source_map()
                    .get_source_file(&FileName::Real(path))
                    .map(|f| f.src_hash)
                    .and_then(line_info::make_file_info);
                (name, info)
            },
            None => (tcx.crate_name(LOCAL_CRATE).to_string(), None),
        };

        let mut line_program = LineProgram::new(
            encoding,
            LineEncoding::default(),
            LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings),
            LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings),
            file_info,
        );
        line_program.file_has_md5 = file_info.is_some();

        dwarf.unit.line_program = line_program;

        {
            let name = dwarf.strings.add(name);
            let comp_dir = dwarf.strings.add(comp_dir);

            let root = dwarf.unit.root();
            let root = dwarf.unit.get_mut(root);
            root.set(
                gimli::DW_AT_producer,
                AttributeValue::StringRef(dwarf.strings.add(producer)),
            );
            root.set(
                gimli::DW_AT_language,
                AttributeValue::Language(gimli::DW_LANG_Rust),
            );
            root.set(gimli::DW_AT_name, AttributeValue::StringRef(name));
            root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir));
            root.set(
                gimli::DW_AT_low_pc,
                AttributeValue::Address(Address::Constant(0)),
            );
        }

        DebugContext {
            tcx,

            endian: target_endian(tcx),
            symbols: indexmap::IndexMap::new(),

            dwarf,
            unit_range_list: RangeList(Vec::new()),

            types: FxHashMap::default(),
        }
    }

    fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
        if let Some(type_id) = self.types.get(ty) {
            return *type_id;
        }

        let new_entry = |dwarf: &mut DwarfUnit, tag| dwarf.unit.add(dwarf.unit.root(), tag);

        let primitive = |dwarf: &mut DwarfUnit, ate| {
            let type_id = new_entry(dwarf, gimli::DW_TAG_base_type);
            let type_entry = dwarf.unit.get_mut(type_id);
            type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate));
            type_id
        };

        let name = format!("{}", ty);
        let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();

        let type_id = match ty.kind {
            ty::Bool => primitive(&mut self.dwarf, gimli::DW_ATE_boolean),
            ty::Char => primitive(&mut self.dwarf, gimli::DW_ATE_UTF),
            ty::Uint(_) => primitive(&mut self.dwarf, gimli::DW_ATE_unsigned),
            ty::Int(_) => primitive(&mut self.dwarf, gimli::DW_ATE_signed),
            ty::Float(_) => primitive(&mut self.dwarf, gimli::DW_ATE_float),
            ty::Ref(_, pointee_ty, _mutbl)
            | ty::RawPtr(ty::TypeAndMut {
                ty: pointee_ty,
                mutbl: _mutbl,
            }) => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let pointee = self.dwarf_ty(pointee_ty);

                let type_entry = self.dwarf.unit.get_mut(type_id);

                //type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc_hir::Mutability::Mut));
                type_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(pointee));

                type_id
            }
            ty::Adt(adt_def, _substs) if adt_def.is_struct() && !layout.is_unsized() => {
                let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type);

                // Ensure that type is inserted before recursing to avoid duplicates
                self.types.insert(ty, type_id);

                let variant = adt_def.non_enum_variant();

                for (field_idx, field_def) in variant.fields.iter().enumerate() {
                    let field_offset = layout.fields.offset(field_idx);
                    let field_layout = layout.field(&layout::LayoutCx {
                        tcx: self.tcx,
                        param_env: ParamEnv::reveal_all(),
                    }, field_idx).unwrap();

                    let field_type = self.dwarf_ty(field_layout.ty);

                    let field_id = self.dwarf.unit.add(type_id, gimli::DW_TAG_member);
                    let field_entry = self.dwarf.unit.get_mut(field_id);

                    field_entry.set(gimli::DW_AT_name, AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()));
                    field_entry.set(gimli::DW_AT_data_member_location, AttributeValue::Udata(field_offset.bytes()));
                    field_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(field_type));
                }

                type_id
            }
            _ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type),
        };

        let type_entry = self.dwarf.unit.get_mut(type_id);

        type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        type_entry.set(
            gimli::DW_AT_byte_size,
            AttributeValue::Udata(layout.size.bytes()),
        );

        self.types.insert(ty, type_id);

        type_id
    }
}

pub(crate) struct FunctionDebugContext<'a, 'tcx> {
    debug_context: &'a mut DebugContext<'tcx>,
    entry_id: UnitEntryId,
    symbol: usize,
    instance: Instance<'tcx>,
    mir: &'tcx mir::Body<'tcx>,
}

impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
    pub(crate) fn new(
        debug_context: &'a mut DebugContext<'tcx>,
        instance: Instance<'tcx>,
        func_id: FuncId,
        name: &str,
    ) -> Self {
        let mir = *debug_context.tcx.instance_mir(instance.def);

        let (symbol, _) = debug_context.symbols.insert_full(func_id, name.to_string());

        // FIXME: add to appropriate scope intead of root
        let scope = debug_context.dwarf.unit.root();

        let entry_id = debug_context
            .dwarf
            .unit
            .add(scope, gimli::DW_TAG_subprogram);
        let entry = debug_context.dwarf.unit.get_mut(entry_id);
        let name_id = debug_context.dwarf.strings.add(name);
        entry.set(
            gimli::DW_AT_linkage_name,
            AttributeValue::StringRef(name_id),
        );

        FunctionDebugContext {
            debug_context,
            entry_id,
            symbol,
            instance,
            mir,
        }
    }

    fn define_local(&mut self, name: String, ty: Ty<'tcx>) -> UnitEntryId {
        let ty = self.debug_context.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            &ty,
        );
        let dw_ty = self.debug_context.dwarf_ty(ty);

        let var_id = self
            .debug_context
            .dwarf
            .unit
            .add(self.entry_id, gimli::DW_TAG_variable);
        let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);

        var_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
        var_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(dw_ty));

        var_id
    }

    pub(crate) fn define(
        &mut self,
        context: &Context,
        isa: &dyn TargetIsa,
        source_info_set: &indexmap::IndexSet<SourceInfo>,
        local_map: FxHashMap<mir::Local, CPlace<'tcx>>,
    ) {
        let end = self.create_debug_lines(context, isa, source_info_set);

        self.debug_context
            .unit_range_list
            .0
            .push(Range::StartLength {
                begin: Address::Symbol {
                    symbol: self.symbol,
                    addend: 0,
                },
                length: end as u64,
            });

        // FIXME make it more reliable and implement scopes before re-enabling this.
        if false {
            let value_labels_ranges = context.build_value_labels_ranges(isa).unwrap();

            for (local, _local_decl) in self.mir.local_decls.iter_enumerated() {
                let var_id = self.define_local(format!("{:?}", local), &self.mir.local_decls[local].ty);

                let location = place_location(
                    self,
                    isa,
                    context,
                    &local_map,
                    &value_labels_ranges,
                    Place {
                        local,
                        projection: ty::List::empty(),
                    },
                );

                let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);
                var_entry.set(gimli::DW_AT_location, location);
            }
        }

        // FIXME create locals for all entries in mir.var_debug_info
    }
}

fn place_location<'a, 'tcx>(
    func_debug_ctx: &mut FunctionDebugContext<'a, 'tcx>,
    isa: &dyn TargetIsa,
    context: &Context,
    local_map: &FxHashMap<mir::Local, CPlace<'tcx>>,
    #[allow(rustc::default_hash_types)]
    value_labels_ranges: &std::collections::HashMap<ValueLabel, Vec<ValueLocRange>>,
    place: Place<'tcx>,
) -> AttributeValue {
    assert!(place.projection.is_empty()); // FIXME implement them

    match local_map[&place.local].inner() {
        CPlaceInner::Var(local) => {
            let value_label = cranelift_codegen::ir::ValueLabel::from_u32(local.as_u32());
            if let Some(value_loc_ranges) = value_labels_ranges.get(&value_label) {
                let loc_list = LocationList(
                    value_loc_ranges
                        .iter()
                        .map(|value_loc_range| Location::StartEnd {
                            begin: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.start),
                            },
                            end: Address::Symbol {
                                symbol: func_debug_ctx.symbol,
                                addend: i64::from(value_loc_range.end),
                            },
                            data: Expression(
                                translate_loc(isa, value_loc_range.loc, &context.func.stack_slots).unwrap(),
                            ),
                        })
                        .collect(),
                );
                let loc_list_id = func_debug_ctx.debug_context.dwarf.unit.locations.add(loc_list);

                AttributeValue::LocationListRef(loc_list_id)
            } else {
                // FIXME set value labels for unused locals

                AttributeValue::Exprloc(Expression(vec![]))
            }
        }
        CPlaceInner::Addr(_, _) => {
            // FIXME implement this (used by arguments and returns)

            AttributeValue::Exprloc(Expression(vec![]))

            // For PointerBase::Stack:
            //AttributeValue::Exprloc(Expression(translate_loc(ValueLoc::Stack(*stack_slot), &context.func.stack_slots).unwrap()))
        }
    }
}

// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137
fn translate_loc(isa: &dyn TargetIsa, loc: ValueLoc, stack_slots: &StackSlots) -> Option<Vec<u8>> {
    match loc {
        ValueLoc::Reg(reg) => {
            let machine_reg = isa.map_dwarf_register(reg).unwrap();
            assert!(machine_reg <= 32); // FIXME
            Some(vec![gimli::constants::DW_OP_reg0.0 + machine_reg as u8])
        }
        ValueLoc::Stack(ss) => {
            if let Some(ss_offset) = stack_slots[ss].offset {
                let endian = gimli::RunTimeEndian::Little;
                let mut writer = write::EndianVec::new(endian);
                writer
                    .write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8)
                    .expect("bp wr");
                writer.write_sleb128(ss_offset as i64 + 16).expect("ss wr");
                let buf = writer.into_vec();
                return Some(buf);
            }
            None
        }
        _ => None,
    }
}
<|endoftext|>


<commit_before>#[link(name = "distrust",
       vers = "0",
       url  = "http://github.com/thewonderidiot/distrust")];
#[desc = "A simple disassembler in Rust"];
#[license = "MIT"];
#[crate_type = "bin"];

extern mod extra;
use extra::getopts::*;
use std::path::Path;
use std::os;
use std::io;

fn print_usage() {
    println("Usage: distrust [OPTIONS] INPUT\n");
    println("Options:");
    println("    -h --help    Display this message");
    println("");
}

fn main() {
    let args = os::args();
    if args.len() == 1 {
        print_usage();
        return;
    }

    let opts = [
        optflag("h"),
        optflag("help")
    ];
    let matches = getopts(args.tail(), opts).unwrap();

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage();
        return;
    }
    // process more (actually useful) arguments...

    let file = match matches.free.len() {
        0u => fail!("no filename supplied"),
        1u => io::file_reader(&Path(matches.free[0])).unwrap(),
        _  => fail!("multiple input filenames")
    };

    println!("Successfully opened {}", matches.free[0]);
}
<commit_msg>Updated for wildcard use being feature-flagged in 0.9-pre<commit_after>#[link(name = "distrust",
       vers = "0",
       url  = "http://github.com/thewonderidiot/distrust")];
#[desc = "A simple disassembler in Rust"];
#[license = "MIT"];
#[crate_type = "bin"];

extern mod extra;
use extra::getopts::{getopts, optflag};
use std::path::Path;
use std::os;
use std::io;

fn print_usage() {
    println("Usage: distrust [OPTIONS] INPUT\n");
    println("Options:");
    println("    -h --help    Display this message");
    println("");
}

fn main() {
    let args = os::args();
    if args.len() == 1 {
        print_usage();
        return;
    }

    let opts = [
        optflag("h"),
        optflag("help")
    ];
    let matches = getopts(args.tail(), opts).unwrap();

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage();
        return;
    }
    // process more (actually useful) arguments...

    let file = match matches.free.len() {
        0u => fail!("no filename supplied"),
        1u => io::file_reader(&Path(matches.free[0])).unwrap(),
        _  => fail!("multiple input filenames")
    };

    println!("Successfully opened {}", matches.free[0]);
}
<|endoftext|>