<commit_before>use eventual::{self, Async};
use portaudio;
use std::sync::{mpsc, Mutex, Arc, MutexGuard};
use std::thread;
use vorbis;

use metadata::{FileFormat, Track, TrackRef};
use session::{Bitrate, Session};
use audio_decrypt::AudioDecrypt;
use util::{self, SpotifyId, Subfile};
use spirc::PlayStatus;

pub type PlayerObserver = Box<Fn(&PlayerState) + Send>;

pub struct Player {
    state: Arc<Mutex<PlayerState>>,
    observers: Arc<Mutex<Vec<PlayerObserver>>>,

    commands: mpsc::Sender<PlayerCommand>,
}

pub struct PlayerState {
    status: PlayStatus,
    position_ms: u32,
    position_measured_at: i64,
    update_time: i64,
    volume: u16,

    end_of_track: bool,
}

struct PlayerInternal {
    state: Arc<Mutex<PlayerState>>,
    observers: Arc<Mutex<Vec<PlayerObserver>>>,

    session: Session,
    commands: mpsc::Receiver<PlayerCommand>,
}

enum PlayerCommand {
    Load(SpotifyId, bool, u32),
    Play,
    Pause,
    Volume(u16),
    Stop,
    Seek(u32),
}

impl Player {
    pub fn new(session: Session) -> Player {
        let (cmd_tx, cmd_rx) = mpsc::channel();

        let state = Arc::new(Mutex::new(PlayerState {
            status: PlayStatus::kPlayStatusStop,
            position_ms: 0,
            position_measured_at: 0,
            update_time: util::now_ms(),
            volume: 0x8000,
            end_of_track: false,
        }));

        let observers = Arc::new(Mutex::new(Vec::new()));

        let internal = PlayerInternal {
            session: session,
            commands: cmd_rx,
            state: state.clone(),
            observers: observers.clone(),
        };

        thread::spawn(move || internal.run());

        Player {
            commands: cmd_tx,
            state: state,
            observers: observers,
        }
    }

    fn command(&self, cmd: PlayerCommand) {
        self.commands.send(cmd).unwrap();
    }

    pub fn load(&self, track: SpotifyId, start_playing: bool, position_ms: u32) {
        self.command(PlayerCommand::Load(track, start_playing, position_ms));
    }

    pub fn play(&self) {
        self.command(PlayerCommand::Play)
    }

    pub fn pause(&self) {
        self.command(PlayerCommand::Pause)
    }

    pub fn stop(&self) {
        self.command(PlayerCommand::Stop)
    }

    pub fn seek(&self, position_ms: u32) {
        self.command(PlayerCommand::Seek(position_ms));
    }

    pub fn state(&self) -> MutexGuard<PlayerState> {
        self.state.lock().unwrap()
    }

    pub fn volume(&self, vol: u16) {
        self.command(PlayerCommand::Volume(vol));
    }

    pub fn add_observer(&self, observer: PlayerObserver) {
        self.observers.lock().unwrap().push(observer);
    }
}

impl PlayerInternal {
    fn run(self) {
        portaudio::initialize().unwrap();

        let stream = portaudio::stream::Stream::<i16, i16>::open_default(
                0, 2, 44100.0,
                portaudio::stream::FRAMES_PER_BUFFER_UNSPECIFIED,
                None
        ).unwrap();

        let mut decoder = None;

        loop {
            let playing = self.state.lock().unwrap().status == PlayStatus::kPlayStatusPlay;
            let cmd = if playing {
                self.commands.try_recv().ok()
            } else {
                Some(self.commands.recv().unwrap())
            };

            match cmd {
                Some(PlayerCommand::Load(track_id, play, position)) => {
                    self.update(|state| {
                        if state.status == PlayStatus::kPlayStatusPlay {
                            stream.stop().unwrap();
                        }
                        state.end_of_track = false;
                        state.status = if play {
                            PlayStatus::kPlayStatusPlay
                        } else {
                            PlayStatus::kPlayStatusPause
                        };
                        state.position_ms = position;
                        state.position_measured_at = util::now_ms();
                        true
                    });
                    drop(decoder);

                    let mut track = self.session.metadata::<Track>(track_id).await().unwrap();

                    if !track.available {
                        let alternatives = track.alternatives
                                                .iter()
                                                .map(|alt_id| {
                                                    self.session.metadata::<Track>(*alt_id)
                                                })
                                                .collect::<Vec<TrackRef>>();

                        track = eventual::sequence(alternatives.into_iter())
                                    .iter()
                                    .find(|alt| alt.available)
                                    .unwrap();
                    }

                    let format = match self.session.config().bitrate {
                        Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96,
                        Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160,
                        Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320,
                    };
                    let (file_id, _) = track.files.into_iter().find(|&(_, f)| f == format).unwrap();

                    let key = self.session.audio_key(track.id, file_id).await().unwrap();
                    decoder = Some(
                        vorbis::Decoder::new(
                        Subfile::new(
                        AudioDecrypt::new(key,
                        self.session.audio_file(file_id)), 0xa7)).unwrap());
                    decoder.as_mut().unwrap().time_seek(position as f64 / 1000f64).unwrap();

                    self.update(|state| {
                        state.status = if play {
                            stream.start().unwrap();
                            PlayStatus::kPlayStatusPlay
                        } else {
                            PlayStatus::kPlayStatusPause
                        };
                        state.position_ms = position;
                        state.position_measured_at = util::now_ms();

                        true
                    });
                    println!("Load Done");
                }
                Some(PlayerCommand::Seek(ms)) => {
                    decoder.as_mut().unwrap().time_seek(ms as f64 / 1000f64).unwrap();
                    self.update(|state| {
                        state.position_ms =
                            (decoder.as_mut().unwrap().time_tell().unwrap() * 1000f64) as u32;
                        state.position_measured_at = util::now_ms();

                        true
                    });
                }
                Some(PlayerCommand::Play) => {
                    self.update(|state| {
                        state.status = PlayStatus::kPlayStatusPlay;
                        true
                    });

                    stream.start().unwrap();
                }
                Some(PlayerCommand::Pause) => {
                    self.update(|state| {
                        state.status = PlayStatus::kPlayStatusPause;
                        state.update_time = util::now_ms();
                        true
                    });

                    stream.stop().unwrap();
                }
                Some(PlayerCommand::Volume(vol)) => {
                    self.update(|state| {
                        state.volume = vol;
                        true
                    });
                }
                Some(PlayerCommand::Stop) => {
                    self.update(|state| {
                        if state.status == PlayStatus::kPlayStatusPlay {
                            state.status = PlayStatus::kPlayStatusPause;
                        }
                        true
                    });

                    stream.stop().unwrap();
                    decoder = None;
                }
                None => (),
            }

            if self.state.lock().unwrap().status == PlayStatus::kPlayStatusPlay {
                match decoder.as_mut().unwrap().packets().next() {
                    Some(Ok(packet)) => {
                        let buffer = packet.data
                                           .iter()
                                           .map(|&x| {
                                               (x as i32
                                                * self.state.lock().unwrap().volume as i32
                                                / 0xFFFF) as i16
                                           })
                                           .collect::<Vec<i16>>();
                        match stream.write(&buffer) {
                            Ok(_) => (),
                            Err(portaudio::PaError::OutputUnderflowed) => eprintln!("Underflow"),
                            Err(e) => panic!("PA Error {}", e),
                        };
                    }
                    Some(Err(vorbis::VorbisError::Hole)) => (),
                    Some(Err(e)) => panic!("Vorbis error {:?}", e),
                    None => {
                        self.update(|state| {
                            state.status = PlayStatus::kPlayStatusStop;
                            state.end_of_track = true;
                            true
                        });

                        stream.stop().unwrap();
                        decoder = None;
                    }
                }

                self.update(|state| {
                    let now = util::now_ms();

                    if now - state.position_measured_at > 5000 {
                        state.position_ms =
                            (decoder.as_mut().unwrap().time_tell().unwrap() * 1000f64) as u32;
                        state.position_measured_at = now;

                        true
                    } else {
                        false
                    }
                });
            }
        }

        drop(stream);

        portaudio::terminate().unwrap();
    }

    fn update<F>(&self, f: F)
        where F: FnOnce(&mut MutexGuard<PlayerState>) -> bool
    {
        let mut guard = self.state.lock().unwrap();
        let update = f(&mut guard);

        let observers = self.observers.lock().unwrap();
        if update {
            guard.update_time = util::now_ms();
            for observer in observers.iter() {
                observer(&guard);
            }
        }
    }
}

impl PlayerState {
    pub fn status(&self) -> PlayStatus {
        self.status
    }

    pub fn position(&self) -> (u32, i64) {
        (self.position_ms, self.position_measured_at)
    }

    pub fn volume(&self) -> u16 {
        self.volume
    }

    pub fn update_time(&self) -> i64 {
        self.update_time
    }

    pub fn end_of_track(&self) -> bool {
        self.end_of_track
    }
}
<commit_msg>Set the default volume to 100%, and add a fast path to volume control.<commit_after>use eventual::{self, Async};
use portaudio;
use std::borrow::Cow;
use std::sync::{mpsc, Mutex, Arc, MutexGuard};
use std::thread;
use vorbis;

use metadata::{FileFormat, Track, TrackRef};
use session::{Bitrate, Session};
use audio_decrypt::AudioDecrypt;
use util::{self, SpotifyId, Subfile};
use spirc::PlayStatus;

pub type PlayerObserver = Box<Fn(&PlayerState) + Send>;

pub struct Player {
    state: Arc<Mutex<PlayerState>>,
    observers: Arc<Mutex<Vec<PlayerObserver>>>,

    commands: mpsc::Sender<PlayerCommand>,
}

pub struct PlayerState {
    status: PlayStatus,
    position_ms: u32,
    position_measured_at: i64,
    update_time: i64,
    volume: u16,

    end_of_track: bool,
}

struct PlayerInternal {
    state: Arc<Mutex<PlayerState>>,
    observers: Arc<Mutex<Vec<PlayerObserver>>>,

    session: Session,
    commands: mpsc::Receiver<PlayerCommand>,
}

enum PlayerCommand {
    Load(SpotifyId, bool, u32),
    Play,
    Pause,
    Volume(u16),
    Stop,
    Seek(u32),
}

impl Player {
    pub fn new(session: Session) -> Player {
        let (cmd_tx, cmd_rx) = mpsc::channel();

        let state = Arc::new(Mutex::new(PlayerState {
            status: PlayStatus::kPlayStatusStop,
            position_ms: 0,
            position_measured_at: 0,
            update_time: util::now_ms(),
            volume: 0xFFFF,
            end_of_track: false,
        }));

        let observers = Arc::new(Mutex::new(Vec::new()));

        let internal = PlayerInternal {
            session: session,
            commands: cmd_rx,
            state: state.clone(),
            observers: observers.clone(),
        };

        thread::spawn(move || internal.run());

        Player {
            commands: cmd_tx,
            state: state,
            observers: observers,
        }
    }

    fn command(&self, cmd: PlayerCommand) {
        self.commands.send(cmd).unwrap();
    }

    pub fn load(&self, track: SpotifyId, start_playing: bool, position_ms: u32) {
        self.command(PlayerCommand::Load(track, start_playing, position_ms));
    }

    pub fn play(&self) {
        self.command(PlayerCommand::Play)
    }

    pub fn pause(&self) {
        self.command(PlayerCommand::Pause)
    }

    pub fn stop(&self) {
        self.command(PlayerCommand::Stop)
    }

    pub fn seek(&self, position_ms: u32) {
        self.command(PlayerCommand::Seek(position_ms));
    }

    pub fn state(&self) -> MutexGuard<PlayerState> {
        self.state.lock().unwrap()
    }

    pub fn volume(&self, vol: u16) {
        self.command(PlayerCommand::Volume(vol));
    }

    pub fn add_observer(&self, observer: PlayerObserver) {
        self.observers.lock().unwrap().push(observer);
    }
}

fn apply_volume(volume: u16, data: &[i16]) -> Cow<[i16]> {
    // Fast path when volume is 100%
    if volume == 0xFFFF {
        Cow::Borrowed(data)
    } else {
        Cow::Owned(data.iter()
                       .map(|&x| {
                           (x as i32
                            * volume as i32
                            / 0xFFFF) as i16
                       })
                       .collect())
    }
}

impl PlayerInternal {
    fn run(self) {
        portaudio::initialize().unwrap();

        let stream = portaudio::stream::Stream::<i16, i16>::open_default(
                0, 2, 44100.0,
                portaudio::stream::FRAMES_PER_BUFFER_UNSPECIFIED,
                None
        ).unwrap();

        let mut decoder = None;

        loop {
            let playing = self.state.lock().unwrap().status == PlayStatus::kPlayStatusPlay;
            let cmd = if playing {
                self.commands.try_recv().ok()
            } else {
                Some(self.commands.recv().unwrap())
            };

            match cmd {
                Some(PlayerCommand::Load(track_id, play, position)) => {
                    self.update(|state| {
                        if state.status == PlayStatus::kPlayStatusPlay {
                            stream.stop().unwrap();
                        }
                        state.end_of_track = false;
                        state.status = if play {
                            PlayStatus::kPlayStatusPlay
                        } else {
                            PlayStatus::kPlayStatusPause
                        };
                        state.position_ms = position;
                        state.position_measured_at = util::now_ms();
                        true
                    });
                    drop(decoder);

                    let mut track = self.session.metadata::<Track>(track_id).await().unwrap();

                    if !track.available {
                        let alternatives = track.alternatives
                                                .iter()
                                                .map(|alt_id| {
                                                    self.session.metadata::<Track>(*alt_id)
                                                })
                                                .collect::<Vec<TrackRef>>();

                        track = eventual::sequence(alternatives.into_iter())
                                    .iter()
                                    .find(|alt| alt.available)
                                    .unwrap();
                    }

                    let format = match self.session.config().bitrate {
                        Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96,
                        Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160,
                        Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320,
                    };
                    let (file_id, _) = track.files.into_iter().find(|&(_, f)| f == format).unwrap();

                    let key = self.session.audio_key(track.id, file_id).await().unwrap();
                    decoder = Some(
                        vorbis::Decoder::new(
                        Subfile::new(
                        AudioDecrypt::new(key,
                        self.session.audio_file(file_id)), 0xa7)).unwrap());
                    decoder.as_mut().unwrap().time_seek(position as f64 / 1000f64).unwrap();

                    self.update(|state| {
                        state.status = if play {
                            stream.start().unwrap();
                            PlayStatus::kPlayStatusPlay
                        } else {
                            PlayStatus::kPlayStatusPause
                        };
                        state.position_ms = position;
                        state.position_measured_at = util::now_ms();

                        true
                    });
                    println!("Load Done");
                }
                Some(PlayerCommand::Seek(ms)) => {
                    decoder.as_mut().unwrap().time_seek(ms as f64 / 1000f64).unwrap();
                    self.update(|state| {
                        state.position_ms =
                            (decoder.as_mut().unwrap().time_tell().unwrap() * 1000f64) as u32;
                        state.position_measured_at = util::now_ms();

                        true
                    });
                }
                Some(PlayerCommand::Play) => {
                    self.update(|state| {
                        state.status = PlayStatus::kPlayStatusPlay;
                        true
                    });

                    stream.start().unwrap();
                }
                Some(PlayerCommand::Pause) => {
                    self.update(|state| {
                        state.status = PlayStatus::kPlayStatusPause;
                        state.update_time = util::now_ms();
                        true
                    });

                    stream.stop().unwrap();
                }
                Some(PlayerCommand::Volume(vol)) => {
                    self.update(|state| {
                        state.volume = vol;
                        true
                    });
                }
                Some(PlayerCommand::Stop) => {
                    self.update(|state| {
                        if state.status == PlayStatus::kPlayStatusPlay {
                            state.status = PlayStatus::kPlayStatusPause;
                        }
                        true
                    });

                    stream.stop().unwrap();
                    decoder = None;
                }
                None => (),
            }

            if self.state.lock().unwrap().status == PlayStatus::kPlayStatusPlay {
                match decoder.as_mut().unwrap().packets().next() {
                    Some(Ok(packet)) => {
                        let buffer = apply_volume(self.state.lock().unwrap().volume,
                                                  &packet.data);
                        match stream.write(&buffer) {
                            Ok(_) => (),
                            Err(portaudio::PaError::OutputUnderflowed) => eprintln!("Underflow"),
                            Err(e) => panic!("PA Error {}", e),
                        };
                    }
                    Some(Err(vorbis::VorbisError::Hole)) => (),
                    Some(Err(e)) => panic!("Vorbis error {:?}", e),
                    None => {
                        self.update(|state| {
                            state.status = PlayStatus::kPlayStatusStop;
                            state.end_of_track = true;
                            true
                        });

                        stream.stop().unwrap();
                        decoder = None;
                    }
                }

                self.update(|state| {
                    let now = util::now_ms();

                    if now - state.position_measured_at > 5000 {
                        state.position_ms =
                            (decoder.as_mut().unwrap().time_tell().unwrap() * 1000f64) as u32;
                        state.position_measured_at = now;

                        true
                    } else {
                        false
                    }
                });
            }
        }

        drop(stream);

        portaudio::terminate().unwrap();
    }

    fn update<F>(&self, f: F)
        where F: FnOnce(&mut MutexGuard<PlayerState>) -> bool
    {
        let mut guard = self.state.lock().unwrap();
        let update = f(&mut guard);

        let observers = self.observers.lock().unwrap();
        if update {
            guard.update_time = util::now_ms();
            for observer in observers.iter() {
                observer(&guard);
            }
        }
    }
}

impl PlayerState {
    pub fn status(&self) -> PlayStatus {
        self.status
    }

    pub fn position(&self) -> (u32, i64) {
        (self.position_ms, self.position_measured_at)
    }

    pub fn volume(&self) -> u16 {
        self.volume
    }

    pub fn update_time(&self) -> i64 {
        self.update_time
    }

    pub fn end_of_track(&self) -> bool {
        self.end_of_track
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Write, Error ,ErrorKind};
use std::fs::File;
use cursor::Cursor;

pub struct Backend {
    buffers: Vec<Buffer>,
    current: usize,
}

impl Backend {
    pub fn new() -> Backend {
        Backend {
            buffers: vec![Buffer::from_file(String::from("test.txt")).unwrap()],
            current: 0,
        }
    }
    pub fn current_lines(&mut self) -> &Vec<String> {
        &self.current_buffer().lines
    }
    pub fn number_of_lines(&mut self) -> usize {
        self.current_buffer().lines.len()
    }
    pub fn current_line_length(&mut self, line: usize) -> usize {
        self.current_buffer().lines[line].len()
    }
    /// Inserts a newline
    pub fn newline(&mut self, cursor: &mut Cursor) {
        // TODO
    }
    /// Handles Backspace
    pub fn backspace(&mut self, cursor: &mut Cursor) {
        // TODO
    }
    /// Inserts a character
    pub fn insert(&mut self, c: char, cursor: &mut Cursor) {
        self.current_buffer().insert_char(c, cursor.line as usize, cursor.column as usize);
        cursor.column += 1;
    }
    /// Returns the current buffer
    pub fn current_buffer(&mut self) -> &mut Buffer {
        &mut self.buffers[self.current]
    }
}

/// A Buffer contains the text being edited and applies the edits to it.
/// It is also responsible for opening and saving files.
pub struct Buffer {
    /// The filename that the Buffer gets saved to.
    pub filename: Option<String>,
    /// The lines of text.
    lines: Vec<String>,
    /// The saved state of the buffer. If dirty is true then there are
    /// unsaved modifications to the Buffer that haven't saved.
    pub dirty: bool,
}
impl Buffer {
    /// Constructs a new, empty buffer that doesn't have a filename to save to.
    pub fn new() -> Buffer {
        Buffer {
            filename: None,
            lines: vec![String::new()],
            dirty: false,
        }
    }
    /// Contructs a new buffer from the contents of a file.
    pub fn from_file(filename: String) -> io::Result<Buffer> {
        let mut file = File::open(&filename)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let mut lines = Vec::new();
        for line in contents.lines() {
            lines.push(String::from(line))
        }
        Ok(Buffer {
            filename: Some(filename),
            lines: lines,
            dirty: false
        })
    }
    /// Saves the contents of the buffer to the file
    pub fn save(&mut self) -> io::Result<()> {
        if let Some(ref filename) = self.filename {
            let mut file = File::create(filename)?;
            for line in &self.lines {
                writeln!(&mut file, "{}", line)?;
            }
        } else {
            return Err(Error::new(ErrorKind::Other, "No file to write to"));
        }
        self.dirty = false;
        Ok(())
    }
    /// Adds a new line at the end of the text
    pub fn push_newline(&mut self) {
        self.lines.push(String::new());
    }
    /// Returns a line of text as a String
    pub fn get_line(&self, index: usize) -> &String {
        &self.lines[index]
    }
    /// Inserts a char at a specific line, column
    pub fn insert_char(&mut self, c: char, line: usize, column: usize) {
        // TODO fix for unicode
        self.lines[line].insert(column, c);
    }
}
<commit_msg>Allow a file to be passed in on the command line<commit_after>use std::io;
use std::io::{Read, Write, Error ,ErrorKind};
use std::fs::File;
use cursor::Cursor;

pub struct Backend {
    buffers: Vec<Buffer>,
    current: usize,
}

impl Backend {
    pub fn new() -> Backend {
        Backend {
            buffers: vec![Buffer::from_file(
                ::std::env::args().nth(1).unwrap_or(String::from("test.txt"))
                //String::from("test2.txt")
            ).unwrap()],
            current: 0,
        }
    }
    pub fn current_lines(&mut self) -> &Vec<String> {
        &self.current_buffer().lines
    }
    pub fn number_of_lines(&mut self) -> usize {
        self.current_buffer().lines.len()
    }
    pub fn current_line_length(&mut self, line: usize) -> usize {
        self.current_buffer().lines[line].len()
    }
    /// Inserts a newline
    pub fn newline(&mut self, cursor: &mut Cursor) {
        // TODO
    }
    /// Handles Backspace
    pub fn backspace(&mut self, cursor: &mut Cursor) {
        // TODO
    }
    /// Inserts a character
    pub fn insert(&mut self, c: char, cursor: &mut Cursor) {
        self.current_buffer().insert_char(c, cursor.line as usize, cursor.column as usize);
        cursor.column += 1;
    }
    /// Returns the current buffer
    pub fn current_buffer(&mut self) -> &mut Buffer {
        &mut self.buffers[self.current]
    }
}

/// A Buffer contains the text being edited and applies the edits to it.
/// It is also responsible for opening and saving files.
pub struct Buffer {
    /// The filename that the Buffer gets saved to.
    pub filename: Option<String>,
    /// The lines of text.
    lines: Vec<String>,
    /// The saved state of the buffer. If dirty is true then there are
    /// unsaved modifications to the Buffer that haven't saved.
    pub dirty: bool,
}
impl Buffer {
    /// Constructs a new, empty buffer that doesn't have a filename to save to.
    pub fn new() -> Buffer {
        Buffer {
            filename: None,
            lines: vec![String::new()],
            dirty: false,
        }
    }
    /// Contructs a new buffer from the contents of a file.
    pub fn from_file(filename: String) -> io::Result<Buffer> {
        let mut file = File::open(&filename)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let mut lines = Vec::new();
        for line in contents.lines() {
            lines.push(String::from(line))
        }
        Ok(Buffer {
            filename: Some(filename),
            lines: lines,
            dirty: false
        })
    }
    /// Saves the contents of the buffer to the file
    pub fn save(&mut self) -> io::Result<()> {
        if let Some(ref filename) = self.filename {
            let mut file = File::create(filename)?;
            for line in &self.lines {
                writeln!(&mut file, "{}", line)?;
            }
        } else {
            return Err(Error::new(ErrorKind::Other, "No file to write to"));
        }
        self.dirty = false;
        Ok(())
    }
    /// Adds a new line at the end of the text
    pub fn push_newline(&mut self) {
        self.lines.push(String::new());
    }
    /// Returns a line of text as a String
    pub fn get_line(&self, index: usize) -> &String {
        &self.lines[index]
    }
    /// Inserts a char at a specific line, column
    pub fn insert_char(&mut self, c: char, line: usize, column: usize) {
        // TODO fix for unicode
        self.lines[line].insert(column, c);
    }
}
<|endoftext|>


<commit_before>use ast;
use ir;
use std::io::prelude::*;
use std::io;
use itertools::Itertools;

pub fn gen_translation_unit<F: Write>(f: &mut F, tu: ir::TranslationUnit) -> io::Result<()> {
    writeln!(f, "#include <stdlib.h>")?;
    writeln!(f, "#include <stdio.h>\n")?;

    writeln!(f, "void print_int(int a) {{")?;
    writeln!(f, "\tprintf(\"%d\\n\", a);")?;
    writeln!(f, "}}")?;

    for declaration in tu.declarations {
        gen_declaration(f, declaration)?;
    }
    Ok(())
}

fn gen_declaration<F: Write>(f: &mut F, declaration: ir::Declaration) -> io::Result<()> {
    match declaration {
        ir::Declaration::ExternFunction { name, ty } => {
            writeln!(f,
                     "extern {} {}({});",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty.into_iter().map(type_to_string).join(", "))?;
        }
        ir::Declaration::Function {
            name,
            ty,
            locals,
            bbs,
        } => {
            writeln!(f,
                     "{} {}({}) {{",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty
                         .into_iter()
                         .map(type_to_string)
                         .enumerate()
                         .map(|(index, ty)| format!("{} arg{}", ty, index))
                         .join(", "))?;

            for local in locals {
                gen_local(f, local)?;
            }
            writeln!(f, "")?;
            for bb in bbs {
                gen_basic_block(f, bb)?;
            }

            writeln!(f, "}}")?;
        }
    }
    Ok(())
}

fn gen_local<F: Write>(f: &mut F, local: ir::LocalVar) -> io::Result<()> {
    writeln!(f,
             "\t{}{};",
             type_to_string_with_name(local.ty, format!("local_{}", local.id.0)),
             local
                 .param_index
                 .map(|index| format!(" = arg{}", index))
                 .unwrap_or(String::new()))
}

fn gen_basic_block<F: Write>(f: &mut F, bb: ir::BasicBlock) -> io::Result<()> {
    writeln!(f, "bb{}: {{", bb.id.0)?;
    for stmt in bb.stmts {
        gen_statement(f, stmt)?;
    }

    gen_terminator(f, bb.terminator)?;
    writeln!(f, "}}")?;
    Ok(())
}

fn gen_statement<F: Write>(f: &mut F, stmt: ir::Statement) -> io::Result<()> {
    match stmt {
        ir::Statement::LValueSet(dest, val) => {
            writeln!(f, "\t*temp_{} = temp_{};", dest.id, val.id)
        }
        ir::Statement::Assign(dest, expr) => {
            if dest.ty != ir::Type::Unit {
                write!(f,
                       "\t{} = ",
                       type_to_string_with_name(dest.ty, format!("temp_{}", dest.id)))?;
            }
            gen_expr(f, expr)?;
            writeln!(f, ";")
        }
    }
}

fn gen_expr<F: Write>(f: &mut F, expr: ir::Expression) -> io::Result<()> {
    match expr {
        ir::Expression::LocalVarLoad(id) => write!(f, "&local_{}", id.0),
        ir::Expression::GlobalLoad(name) => write!(f, "{}", name),
        ir::Expression::LValueLoad(val) => write!(f, "*temp_{}", val.id),
        ir::Expression::BinOp(op, lhs, rhs) => {
            use ir::BinOpCode::*;
            let op = match op {
                PtrAdd | IntAdd | DoubleAdd => "+",
                IntSub | DoubleSub => "-",
                IntTimes | DoubleTimes => "*",
                IntDivide | DoubleDivide => "/",
                IntMod => "%",
                IntLess | DoubleLess => "<",
                IntLessEqual | DoubleLessEqual => "<=",
                IntGreater | DoubleGreater => ">",
                IntGreaterEqual | DoubleGreaterEqual => ">=",
                IntEqual | DoubleEqual | BoolEqual => "==",
                IntNotEqual | DoubleNotEqual | BoolNotEqual => "!=",
                BoolLogicalAnd => "&&",
                BoolLogicalOr => "||",
            };

            write!(f, "temp_{} {} temp_{}", lhs.id, op, rhs.id)
        }
        ir::Expression::UnOp(op, sub) => {
            use ir::UnOpCode::*;
            let op = match op {
                IntMinus | DoubleMinus => "-",
                BoolLogicalNot => "!",
                AddressOf => "&",
                PtrDeref => "*",
            };

            write!(f, "{}temp_{}", op, sub.id)
        }
        ir::Expression::ReadArray(array, index) => {
            write!(f, "temp_{}[temp_{}]", array.id, index.id)
        }
        ir::Expression::FuncCall(func, params) => {
            write!(f,
                   "temp_{}({})",
                   func.id,
                   params
                       .into_iter()
                       .map(|val| format!("temp_{}", val.id))
                       .join(", "))
        }
        ir::Expression::Literal(lit) => {
            match lit {
                ast::Literal::Int(val) => write!(f, "{}", val),
                ast::Literal::Double(val) => write!(f, "{}", val),
                ast::Literal::Bool(val) => write!(f, "{}", if val { 1 } else { 0 }),
                ast::Literal::Unit => write!(f, "void"),
            }
        }
    }
}

fn gen_terminator<F: Write>(f: &mut F, term: ir::Terminator) -> io::Result<()> {
    match term {
        ir::Terminator::Br(id) => writeln!(f, "\tgoto bb{};", id.0),
        ir::Terminator::BrCond(value, id1, id2) => {
            writeln!(f,
                     "\tif (temp_{}) {{ goto bb{}; }} else {{ goto bb{}; }}",
                     value.id,
                     id1.0,
                     id2.0)
        }
        ir::Terminator::Ret(value) => {
            if value.ty != ir::Type::Unit {
                writeln!(f, "\treturn temp_{};", value.id)
            } else {
                writeln!(f, "\t return;")
            }
        },
    }
}

fn type_to_string_with_name(ty: ir::Type, name: String) -> String {
    match ty {
        ir::Type::Unit => format!("void {}", name),
        ir::Type::Bool => format!("int {}", name), // cause c you know
        ir::Type::Int => format!("int {}", name),
        ir::Type::Double => format!("double {}", name),
        ir::Type::LValue(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Array(sub) => format!("{} {}[]", type_to_string(*sub), name),
        ir::Type::Ptr(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Function(func) => {
            format!("{}(*{})({})",
                    type_to_string(*func.return_ty),
                    name,
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}

fn type_to_string(ty: ir::Type) -> String {
    match ty {
        ir::Type::Unit => format!("void"),
        ir::Type::Bool => format!("int"), // cause c you know
        ir::Type::Int => format!("int"),
        ir::Type::Double => format!("double"),
        ir::Type::LValue(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Array(sub) => format!("{}[]", type_to_string(*sub)),
        ir::Type::Ptr(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Function(func) => {
            format!("{}(*)({})",
                    type_to_string(*func.return_ty),
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}
<commit_msg>Little modification on output of void expr<commit_after>use ast;
use ir;
use std::io::prelude::*;
use std::io;
use itertools::Itertools;

pub fn gen_translation_unit<F: Write>(f: &mut F, tu: ir::TranslationUnit) -> io::Result<()> {
    writeln!(f, "#include <stdlib.h>")?;
    writeln!(f, "#include <stdio.h>\n")?;

    writeln!(f, "void print_int(int a) {{")?;
    writeln!(f, "\tprintf(\"%d\\n\", a);")?;
    writeln!(f, "}}")?;

    for declaration in tu.declarations {
        gen_declaration(f, declaration)?;
    }
    Ok(())
}

fn gen_declaration<F: Write>(f: &mut F, declaration: ir::Declaration) -> io::Result<()> {
    match declaration {
        ir::Declaration::ExternFunction { name, ty } => {
            writeln!(f,
                     "extern {} {}({});",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty.into_iter().map(type_to_string).join(", "))?;
        }
        ir::Declaration::Function {
            name,
            ty,
            locals,
            bbs,
        } => {
            writeln!(f,
                     "{} {}({}) {{",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty
                         .into_iter()
                         .map(type_to_string)
                         .enumerate()
                         .map(|(index, ty)| format!("{} arg{}", ty, index))
                         .join(", "))?;

            for local in locals {
                gen_local(f, local)?;
            }
            writeln!(f, "")?;
            for bb in bbs {
                gen_basic_block(f, bb)?;
            }

            writeln!(f, "}}")?;
        }
    }
    Ok(())
}

fn gen_local<F: Write>(f: &mut F, local: ir::LocalVar) -> io::Result<()> {
    writeln!(f,
             "\t{}{};",
             type_to_string_with_name(local.ty, format!("local_{}", local.id.0)),
             local
                 .param_index
                 .map(|index| format!(" = arg{}", index))
                 .unwrap_or(String::new()))
}

fn gen_basic_block<F: Write>(f: &mut F, bb: ir::BasicBlock) -> io::Result<()> {
    writeln!(f, "bb{}: {{", bb.id.0)?;
    for stmt in bb.stmts {
        gen_statement(f, stmt)?;
    }

    gen_terminator(f, bb.terminator)?;
    writeln!(f, "}}")?;
    Ok(())
}

fn gen_statement<F: Write>(f: &mut F, stmt: ir::Statement) -> io::Result<()> {
    match stmt {
        ir::Statement::LValueSet(dest, val) => {
            writeln!(f, "\t*temp_{} = temp_{};", dest.id, val.id)
        }
        ir::Statement::Assign(dest, expr) => {
            if dest.ty != ir::Type::Unit {
                write!(f,
                       "\t{} = ",
                       type_to_string_with_name(dest.ty, format!("temp_{}", dest.id)))?;
            }
            gen_expr(f, expr)?;
            writeln!(f, ";")
        }
    }
}

fn gen_expr<F: Write>(f: &mut F, expr: ir::Expression) -> io::Result<()> {
    match expr {
        ir::Expression::LocalVarLoad(id) => write!(f, "&local_{}", id.0),
        ir::Expression::GlobalLoad(name) => write!(f, "{}", name),
        ir::Expression::LValueLoad(val) => write!(f, "*temp_{}", val.id),
        ir::Expression::BinOp(op, lhs, rhs) => {
            use ir::BinOpCode::*;
            let op = match op {
                PtrAdd | IntAdd | DoubleAdd => "+",
                IntSub | DoubleSub => "-",
                IntTimes | DoubleTimes => "*",
                IntDivide | DoubleDivide => "/",
                IntMod => "%",
                IntLess | DoubleLess => "<",
                IntLessEqual | DoubleLessEqual => "<=",
                IntGreater | DoubleGreater => ">",
                IntGreaterEqual | DoubleGreaterEqual => ">=",
                IntEqual | DoubleEqual | BoolEqual => "==",
                IntNotEqual | DoubleNotEqual | BoolNotEqual => "!=",
                BoolLogicalAnd => "&&",
                BoolLogicalOr => "||",
            };

            write!(f, "temp_{} {} temp_{}", lhs.id, op, rhs.id)
        }
        ir::Expression::UnOp(op, sub) => {
            use ir::UnOpCode::*;
            let op = match op {
                IntMinus | DoubleMinus => "-",
                BoolLogicalNot => "!",
                AddressOf => "&",
                PtrDeref => "*",
            };

            write!(f, "{}temp_{}", op, sub.id)
        }
        ir::Expression::ReadArray(array, index) => {
            write!(f, "temp_{}[temp_{}]", array.id, index.id)
        }
        ir::Expression::FuncCall(func, params) => {
            write!(f,
                   "temp_{}({})",
                   func.id,
                   params
                       .into_iter()
                       .map(|val| format!("temp_{}", val.id))
                       .join(", "))
        }
        ir::Expression::Literal(lit) => {
            match lit {
                ast::Literal::Int(val) => write!(f, "{}", val),
                ast::Literal::Double(val) => write!(f, "{}", val),
                ast::Literal::Bool(val) => write!(f, "{}", if val { 1 } else { 0 }),
                ast::Literal::Unit => Ok(()),
            }
        }
    }
}

fn gen_terminator<F: Write>(f: &mut F, term: ir::Terminator) -> io::Result<()> {
    match term {
        ir::Terminator::Br(id) => writeln!(f, "\tgoto bb{};", id.0),
        ir::Terminator::BrCond(value, id1, id2) => {
            writeln!(f,
                     "\tif (temp_{}) {{ goto bb{}; }} else {{ goto bb{}; }}",
                     value.id,
                     id1.0,
                     id2.0)
        }
        ir::Terminator::Ret(value) => {
            if value.ty != ir::Type::Unit {
                writeln!(f, "\treturn temp_{};", value.id)
            } else {
                writeln!(f, "\treturn;")
            }
        },
    }
}

fn type_to_string_with_name(ty: ir::Type, name: String) -> String {
    match ty {
        ir::Type::Unit => format!("void {}", name),
        ir::Type::Bool => format!("int {}", name), // cause c you know
        ir::Type::Int => format!("int {}", name),
        ir::Type::Double => format!("double {}", name),
        ir::Type::LValue(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Array(sub) => format!("{} {}[]", type_to_string(*sub), name),
        ir::Type::Ptr(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Function(func) => {
            format!("{}(*{})({})",
                    type_to_string(*func.return_ty),
                    name,
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}

fn type_to_string(ty: ir::Type) -> String {
    match ty {
        ir::Type::Unit => format!("void"),
        ir::Type::Bool => format!("int"), // cause c you know
        ir::Type::Int => format!("int"),
        ir::Type::Double => format!("double"),
        ir::Type::LValue(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Array(sub) => format!("{}[]", type_to_string(*sub)),
        ir::Type::Ptr(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Function(func) => {
            format!("{}(*)({})",
                    type_to_string(*func.return_ty),
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
    // Pass our linker script to the top crate
    let mut ld = String::new();

    let interrupts = env::var_os("CARGO_FEATURE_INTERRUPTS").is_some();
    let static_ram = env::var_os("CARGO_FEATURE_STATIC_RAM").is_some();

    ld.push_str("
MEMORY
{
  CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
  RAM : ORIGIN = 0x20000000, LENGTH = 40K
}

ENTRY(_reset)

SECTIONS
{
  .text ORIGIN(FLASH) :
  {
    /* Vector table */
    LONG(ORIGIN(RAM) + LENGTH(RAM));
    LONG(_reset + 1);
    KEEP(*(.text.exceptions));
    _eexceptions = .;");

    if interrupts {
        ld.push_str("
    KEEP(*(.text.interrupts));
    _einterrupts = .;");
    }

    ld.push_str("
    /* Entry point: reset handler */
    _reset = .;
    KEEP(*(.text._reset));

    *(.text.*);
    *(.rodata.*);
  } > FLASH");

    if static_ram {
        ld.push_str("
  .bss : ALIGN(4)
  {
    _sbss = .;
    *(.bss.*);
    _ebss = ALIGN(4);
  } > RAM

  .data : ALIGN(4)
  {
    _sdata = .;
    *(.data.*);
    _edata = ALIGN(4);
  } > RAM AT > FLASH

  _sidata = LOADADDR(.data);");
    }

    ld.push_str("
  /DISCARD/ :
  {
    *(.ARM.exidx.*)");

    if !static_ram {
        ld.push_str("
    *(.bss.*)
    *(.data.*)");
    }

    ld.push_str("
  }
}

/* HACK to make these symbols overrideable by _dependencies_ (they were
   already overridable by the top crate), we declare them as undefined
   (EXTERN) here. */
EXTERN(_default_exception_handler);
EXTERN(_init);

/* Exceptions */
PROVIDE(_nmi = _default_exception_handler);
PROVIDE(_hard_fault = _default_exception_handler);
PROVIDE(_memmanage_fault = _default_exception_handler);
PROVIDE(_bus_fault = _default_exception_handler);
PROVIDE(_usage_fault = _default_exception_handler);
PROVIDE(_svcall = _default_exception_handler);
PROVIDE(_pendsv = _default_exception_handler);
PROVIDE(_systick = _default_exception_handler);");

    if interrupts {

        ld.push_str("
/* Interrupts */
PROVIDE(_wwdg = _default_exception_handler);
PROVIDE(_pvd = _default_exception_handler);
PROVIDE(_tamper_stamp = _default_exception_handler);
PROVIDE(_rtc_wkup = _default_exception_handler);
PROVIDE(_flash = _default_exception_handler);
PROVIDE(_rcc = _default_exception_handler);
PROVIDE(_exti0 = _default_exception_handler);
PROVIDE(_exti1 = _default_exception_handler);
PROVIDE(_exti2_ts = _default_exception_handler);
PROVIDE(_exti3 = _default_exception_handler);
PROVIDE(_exti4 = _default_exception_handler);
PROVIDE(_dma1_channel1 = _default_exception_handler);
PROVIDE(_dma1_channel2 = _default_exception_handler);
PROVIDE(_dma1_channel3 = _default_exception_handler);
PROVIDE(_dma1_channel4 = _default_exception_handler);
PROVIDE(_dma1_channel5 = _default_exception_handler);
PROVIDE(_dma1_channel6 = _default_exception_handler);
PROVIDE(_dma1_channel7 = _default_exception_handler);
PROVIDE(_adc1_2 = _default_exception_handler);
PROVIDE(_usb_hp_can_tx = _default_exception_handler);
PROVIDE(_usb_lp_can_rx0 = _default_exception_handler);
PROVIDE(_can_rx1 = _default_exception_handler);
PROVIDE(_can_sce = _default_exception_handler);
PROVIDE(_exti9_5 = _default_exception_handler);
PROVIDE(_tim1_brk_tim15 = _default_exception_handler);
PROVIDE(_tim1_up_tim16 = _default_exception_handler);
PROVIDE(_tim1_trg_com_tim17 = _default_exception_handler);
PROVIDE(_tim1_cc = _default_exception_handler);
PROVIDE(_tim2 = _default_exception_handler);
PROVIDE(_tim3 = _default_exception_handler);
PROVIDE(_tim4 = _default_exception_handler);
PROVIDE(_i2c1_ev = _default_exception_handler);
PROVIDE(_i2c1_er = _default_exception_handler);
PROVIDE(_i2c2_ev = _default_exception_handler);
PROVIDE(_i2c2_er = _default_exception_handler);
PROVIDE(_spi1 = _default_exception_handler);
PROVIDE(_spi2 = _default_exception_handler);
PROVIDE(_usart1 = _default_exception_handler);
PROVIDE(_usart2 = _default_exception_handler);
PROVIDE(_usart3 = _default_exception_handler);
PROVIDE(_exti15_10 = _default_exception_handler);
PROVIDE(_rtc_alarm = _default_exception_handler);
PROVIDE(_usb_wake_up = _default_exception_handler);
PROVIDE(_tim8_brk = _default_exception_handler);
PROVIDE(_tim8_up = _default_exception_handler);
PROVIDE(_tim8_trg_com = _default_exception_handler);
PROVIDE(_tim8_cc = _default_exception_handler);
PROVIDE(_adc3 = _default_exception_handler);
PROVIDE(_fmc = _default_exception_handler);
PROVIDE(_spi3 = _default_exception_handler);
PROVIDE(_uart4 = _default_exception_handler);
PROVIDE(_uart5 = _default_exception_handler);
PROVIDE(_tim6_dac = _default_exception_handler);
PROVIDE(_tim7 = _default_exception_handler);
PROVIDE(_dma2_channel1 = _default_exception_handler);
PROVIDE(_dma2_channel2 = _default_exception_handler);
PROVIDE(_dma2_channel3 = _default_exception_handler);
PROVIDE(_dma2_channel4 = _default_exception_handler);
PROVIDE(_dma2_channel5 = _default_exception_handler);
PROVIDE(_adc4 = _default_exception_handler);
PROVIDE(_comp1_2_3 = _default_exception_handler);
PROVIDE(_comp4_5_6 = _default_exception_handler);
PROVIDE(_comp7 = _default_exception_handler);
PROVIDE(_i2c3_ev = _default_exception_handler);
PROVIDE(_i2c3_er = _default_exception_handler);
PROVIDE(_usb_hp = _default_exception_handler);
PROVIDE(_usb_lp = _default_exception_handler);
PROVIDE(_usb_wake_up_rmp = _default_exception_handler);
PROVIDE(_tim20_brk = _default_exception_handler);
PROVIDE(_tim20_up = _default_exception_handler);
PROVIDE(_tim20_trg_com = _default_exception_handler);
PROVIDE(_tim20_cc = _default_exception_handler);
PROVIDE(_fpu = _default_exception_handler);
PROVIDE(_spi4 = _default_exception_handler);");
    }

    ld.push_str("
ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, \"exceptions \
                 not linked where expected\");");

    if interrupts {
        ld.push_str("
ASSERT(_einterrupts - ORIGIN(FLASH) == 0x194, \
                     \"interrupts not linked where expected\");");
    }

    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    File::create(out.join("stm32f3discovery.ld"))
        .unwrap()
        .write_all(ld.as_bytes())
        .unwrap();

    println!("cargo:rustc-link-search={}", out.display());
}
<commit_msg>hack to make the tests pass<commit_after>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
    // Pass our linker script to the top crate
    let mut ld = String::new();

    let interrupts = env::var_os("CARGO_FEATURE_INTERRUPTS").is_some();
    let static_ram = env::var_os("CARGO_FEATURE_STATIC_RAM").is_some();

    ld.push_str("
MEMORY
{
  CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
  RAM : ORIGIN = 0x20000000, LENGTH = 40K
}

ENTRY(_reset)

SECTIONS
{
  .text ORIGIN(FLASH) :
  {
    /* Vector table */
    LONG(ORIGIN(RAM) + LENGTH(RAM));
    LONG(_reset + 1);
    KEEP(*(.text.exceptions));
    _eexceptions = .;");

    if interrupts {
        ld.push_str("
    KEEP(*(.text.interrupts));
    _einterrupts = .;");
    }

    ld.push_str("
    /* Entry point: reset handler */
    _reset = .;
    KEEP(*(.text._reset));

    *(.text.*);
    *(.rodata.*);
  } > FLASH");

    if static_ram {
        ld.push_str("
  .bss : ALIGN(4)
  {
    _sbss = .;
    *(.bss.*);
    _ebss = ALIGN(4);
  } > RAM

  .data : ALIGN(4)
  {
    _sdata = .;
    *(.data.*);
    _edata = ALIGN(4);
  } > RAM AT > FLASH

  _sidata = LOADADDR(.data);");
    }

    ld.push_str("
  /DISCARD/ :
  {
    *(.ARM.exidx.*)");

    if !static_ram {
        ld.push_str("
    *(.bss.*)
    *(.data.*)");
    }

    ld.push_str("
  }
}

/* HACK to make these symbols overrideable by _dependencies_ (they were
   already overridable by the top crate), we declare them as undefined
   (EXTERN) here. */
EXTERN(__aeabi_memclr4);
EXTERN(_default_exception_handler);
EXTERN(_init);

/* Exceptions */
PROVIDE(_nmi = _default_exception_handler);
PROVIDE(_hard_fault = _default_exception_handler);
PROVIDE(_memmanage_fault = _default_exception_handler);
PROVIDE(_bus_fault = _default_exception_handler);
PROVIDE(_usage_fault = _default_exception_handler);
PROVIDE(_svcall = _default_exception_handler);
PROVIDE(_pendsv = _default_exception_handler);
PROVIDE(_systick = _default_exception_handler);");

    if interrupts {

        ld.push_str("
/* Interrupts */
PROVIDE(_wwdg = _default_exception_handler);
PROVIDE(_pvd = _default_exception_handler);
PROVIDE(_tamper_stamp = _default_exception_handler);
PROVIDE(_rtc_wkup = _default_exception_handler);
PROVIDE(_flash = _default_exception_handler);
PROVIDE(_rcc = _default_exception_handler);
PROVIDE(_exti0 = _default_exception_handler);
PROVIDE(_exti1 = _default_exception_handler);
PROVIDE(_exti2_ts = _default_exception_handler);
PROVIDE(_exti3 = _default_exception_handler);
PROVIDE(_exti4 = _default_exception_handler);
PROVIDE(_dma1_channel1 = _default_exception_handler);
PROVIDE(_dma1_channel2 = _default_exception_handler);
PROVIDE(_dma1_channel3 = _default_exception_handler);
PROVIDE(_dma1_channel4 = _default_exception_handler);
PROVIDE(_dma1_channel5 = _default_exception_handler);
PROVIDE(_dma1_channel6 = _default_exception_handler);
PROVIDE(_dma1_channel7 = _default_exception_handler);
PROVIDE(_adc1_2 = _default_exception_handler);
PROVIDE(_usb_hp_can_tx = _default_exception_handler);
PROVIDE(_usb_lp_can_rx0 = _default_exception_handler);
PROVIDE(_can_rx1 = _default_exception_handler);
PROVIDE(_can_sce = _default_exception_handler);
PROVIDE(_exti9_5 = _default_exception_handler);
PROVIDE(_tim1_brk_tim15 = _default_exception_handler);
PROVIDE(_tim1_up_tim16 = _default_exception_handler);
PROVIDE(_tim1_trg_com_tim17 = _default_exception_handler);
PROVIDE(_tim1_cc = _default_exception_handler);
PROVIDE(_tim2 = _default_exception_handler);
PROVIDE(_tim3 = _default_exception_handler);
PROVIDE(_tim4 = _default_exception_handler);
PROVIDE(_i2c1_ev = _default_exception_handler);
PROVIDE(_i2c1_er = _default_exception_handler);
PROVIDE(_i2c2_ev = _default_exception_handler);
PROVIDE(_i2c2_er = _default_exception_handler);
PROVIDE(_spi1 = _default_exception_handler);
PROVIDE(_spi2 = _default_exception_handler);
PROVIDE(_usart1 = _default_exception_handler);
PROVIDE(_usart2 = _default_exception_handler);
PROVIDE(_usart3 = _default_exception_handler);
PROVIDE(_exti15_10 = _default_exception_handler);
PROVIDE(_rtc_alarm = _default_exception_handler);
PROVIDE(_usb_wake_up = _default_exception_handler);
PROVIDE(_tim8_brk = _default_exception_handler);
PROVIDE(_tim8_up = _default_exception_handler);
PROVIDE(_tim8_trg_com = _default_exception_handler);
PROVIDE(_tim8_cc = _default_exception_handler);
PROVIDE(_adc3 = _default_exception_handler);
PROVIDE(_fmc = _default_exception_handler);
PROVIDE(_spi3 = _default_exception_handler);
PROVIDE(_uart4 = _default_exception_handler);
PROVIDE(_uart5 = _default_exception_handler);
PROVIDE(_tim6_dac = _default_exception_handler);
PROVIDE(_tim7 = _default_exception_handler);
PROVIDE(_dma2_channel1 = _default_exception_handler);
PROVIDE(_dma2_channel2 = _default_exception_handler);
PROVIDE(_dma2_channel3 = _default_exception_handler);
PROVIDE(_dma2_channel4 = _default_exception_handler);
PROVIDE(_dma2_channel5 = _default_exception_handler);
PROVIDE(_adc4 = _default_exception_handler);
PROVIDE(_comp1_2_3 = _default_exception_handler);
PROVIDE(_comp4_5_6 = _default_exception_handler);
PROVIDE(_comp7 = _default_exception_handler);
PROVIDE(_i2c3_ev = _default_exception_handler);
PROVIDE(_i2c3_er = _default_exception_handler);
PROVIDE(_usb_hp = _default_exception_handler);
PROVIDE(_usb_lp = _default_exception_handler);
PROVIDE(_usb_wake_up_rmp = _default_exception_handler);
PROVIDE(_tim20_brk = _default_exception_handler);
PROVIDE(_tim20_up = _default_exception_handler);
PROVIDE(_tim20_trg_com = _default_exception_handler);
PROVIDE(_tim20_cc = _default_exception_handler);
PROVIDE(_fpu = _default_exception_handler);
PROVIDE(_spi4 = _default_exception_handler);");
    }

    ld.push_str("
ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, \"exceptions \
                 not linked where expected\");");

    if interrupts {
        ld.push_str("
ASSERT(_einterrupts - ORIGIN(FLASH) == 0x194, \
                     \"interrupts not linked where expected\");");
    }

    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    File::create(out.join("stm32f3discovery.ld"))
        .unwrap()
        .write_all(ld.as_bytes())
        .unwrap();

    println!("cargo:rustc-link-search={}", out.display());
}
<|endoftext|>


<commit_before>#[cfg(feature = "simdcompression")]
mod build {
    extern crate gcc;

    pub fn build() {
        let mut config = gcc::Config::new();
        config
            .include("./cpp/simdcomp/include")
            .file("cpp/simdcomp/src/avxbitpacking.c")
            .file("cpp/simdcomp/src/simdintegratedbitpacking.c")
            .file("cpp/simdcomp/src/simdbitpacking.c")
            .file("cpp/simdcomp/src/simdpackedsearch.c")
            .file("cpp/simdcomp/src/simdcomputil.c")
            .file("cpp/simdcomp/src/simdpackedselect.c")
            .file("cpp/simdcomp/src/simdfor.c")
            .file("cpp/simdcomp_wrapper.c");

        if !cfg!(debug_assertions) {
            config.opt_level(3);

            if cfg!(target_env = "msvc") {
                config
                    .define("NDEBUG", None)
                    .flag("/Gm-")
                    .flag("/GS-")
                    .flag("/Gy")
                    .flag("/Oi")
                    .flag("/GL");
            }
        }

        if !cfg!(target_env = "msvc") {
            config
                .include("./cpp/streamvbyte/include")
                .file("cpp/streamvbyte/src/streamvbyte.c")
                .file("cpp/streamvbyte/src/streamvbytedelta.c")
                .flag("-msse4.1")
                .flag("-march=native")
                .flag("-std=c99");
        }

        config.compile("libsimdcomp.a");

        // Workaround for linking static libraries built with /GL
        // https://github.com/rust-lang/rust/issues/26003
        if !cfg!(debug_assertions) && cfg!(target_env = "msvc") {
            println!("cargo:rustc-link-lib=dylib=simdcomp");
        }
    }
}

#[cfg(not(feature = "simdcompression"))]
mod build {
    pub fn build() {}
}

fn main() {
    build::build();
}
<commit_msg>Avoid rebuilding simdcomp when running tests<commit_after>#[cfg(feature = "simdcompression")]
mod build {
    extern crate gcc;

    pub fn build() {
        let mut config = gcc::Config::new();
        config
            .include("./cpp/simdcomp/include")
            .file("cpp/simdcomp/src/avxbitpacking.c")
            .file("cpp/simdcomp/src/simdintegratedbitpacking.c")
            .file("cpp/simdcomp/src/simdbitpacking.c")
            .file("cpp/simdcomp/src/simdpackedsearch.c")
            .file("cpp/simdcomp/src/simdcomputil.c")
            .file("cpp/simdcomp/src/simdpackedselect.c")
            .file("cpp/simdcomp/src/simdfor.c")
            .file("cpp/simdcomp_wrapper.c");

        if !cfg!(debug_assertions) {
            config.opt_level(3);

            if cfg!(target_env = "msvc") {
                config
                    .define("NDEBUG", None)
                    .flag("/Gm-")
                    .flag("/GS-")
                    .flag("/Gy")
                    .flag("/Oi")
                    .flag("/GL");
            }
        }

        if !cfg!(target_env = "msvc") {
            config
                .include("./cpp/streamvbyte/include")
                .file("cpp/streamvbyte/src/streamvbyte.c")
                .file("cpp/streamvbyte/src/streamvbytedelta.c")
                .flag("-msse4.1")
                .flag("-march=native")
                .flag("-std=c99");
        }

        config.compile("libsimdcomp.a");

        // Workaround for linking static libraries built with /GL
        // https://github.com/rust-lang/rust/issues/26003
        if !cfg!(debug_assertions) && cfg!(target_env = "msvc") {
            println!("cargo:rustc-link-lib=dylib=simdcomp");
        }

        println!("cargo:rerun-if-changed=cpp");
    }
}

#[cfg(not(feature = "simdcompression"))]
mod build {
    pub fn build() {}
}

fn main() {
    build::build();
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

// Check that lifetime resolver enforces the lifetime name scoping
// rules correctly in various scenarios.

struct Foo<'a> {
    x: &'a int
}

impl<'a> Foo<'a> {
    // &'a is inherited:
    fn m1(&self, arg: &'a int) { }
    fn m2(&'a self) { }
    fn m3(&self, arg: Foo<'a>) { }

    // &'b is not:
    fn m4(&self, arg: &'b int) { } //~ ERROR undeclared lifetime
    fn m5(&'b self) { } //~ ERROR undeclared lifetime
    fn m6(&self, arg: Foo<'b>) { } //~ ERROR undeclared lifetime
}

fn bar<'a>(x: &'a int) {
    // &'a is visible to code:
    let y: &'a int = x;

    // &'a is not visible to *items*:
    type X = Option<&'a int>; //~ ERROR undeclared lifetime
    enum E {
        E1(&'a int) //~ ERROR undeclared lifetime
    }
    struct S {
        f: &'a int //~ ERROR undeclared lifetime
    }
    fn f(a: &'a int) { } //~ ERROR undeclared lifetime

    // &'a CAN be declared on functions and used then:
    fn g<'a>(a: &'a int) { } // OK
    fn h(a: for<'a>|&'a int|) { } // OK
}

// Test nesting of lifetimes in fn type declarations
fn fn_types(a: &'a int, //~ ERROR undeclared lifetime
            b: for<'a>|a: &'a int,
                       b: &'b int, //~ ERROR undeclared lifetime
                       c: for<'b>|a: &'a int,
                                  b: &'b int|,
                       d: &'b int|, //~ ERROR undeclared lifetime
            c: &'a int) //~ ERROR undeclared lifetime
{
}

pub fn main() {}
<commit_msg>Test resolving of names with `for` binders.<commit_after>// Copyright 2012-2013 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.

// Check that lifetime resolver enforces the lifetime name scoping
// rules correctly in various scenarios.

struct Foo<'a> {
    x: &'a int
}

impl<'a> Foo<'a> {
    // &'a is inherited:
    fn m1(&self, arg: &'a int) { }
    fn m2(&'a self) { }
    fn m3(&self, arg: Foo<'a>) { }

    // &'b is not:
    fn m4(&self, arg: &'b int) { } //~ ERROR undeclared lifetime
    fn m5(&'b self) { } //~ ERROR undeclared lifetime
    fn m6(&self, arg: Foo<'b>) { } //~ ERROR undeclared lifetime
}

fn bar<'a>(x: &'a int) {
    // &'a is visible to code:
    let y: &'a int = x;

    // &'a is not visible to *items*:
    type X = Option<&'a int>; //~ ERROR undeclared lifetime
    enum E {
        E1(&'a int) //~ ERROR undeclared lifetime
    }
    struct S {
        f: &'a int //~ ERROR undeclared lifetime
    }
    fn f(a: &'a int) { } //~ ERROR undeclared lifetime

    // &'a CAN be declared on functions and used then:
    fn g<'a>(a: &'a int) { } // OK
    fn h(a: for<'a>|&'a int|) { } // OK

    // But not in the bound of a closure, it's not in scope *there*
    fn i(a: for<'a>|&int|:'a) { } //~ ERROR undeclared lifetime
}

// Test nesting of lifetimes in fn type declarations
fn fn_types(a: &'a int, //~ ERROR undeclared lifetime
            b: for<'a>|a: &'a int,
                       b: &'b int, //~ ERROR undeclared lifetime
                       c: for<'b>|a: &'a int,
                                  b: &'b int|,
                       d: &'b int|, //~ ERROR undeclared lifetime
            c: &'a int) //~ ERROR undeclared lifetime
{
}

pub fn main() {}
<|endoftext|>


<commit_before>#![no_std]

use libtock_platform::Syscalls;

/// The low-level debug API provides tools to diagnose userspace issues that
/// make normal debugging workflows (e.g. printing to the console) difficult.
///
/// It allows libraries to print alert codes and apps to print numeric
/// information using only the command system call.
///
/// # Example
/// ```ignore
/// use libtock2::LowLevelDebug;
///
/// // Prints 0x45 and the app which called it.
/// LowLevelDebug::print_1(0x45);
/// ```

const DRIVER_NUM: u32 = 8;

// Command IDs
const DRIVER_CHECK: u32 = 0;
const PRINT_ALERT_CODE: u32 = 1;
const PRINT_1: u32 = 2;
const PRINT_2: u32 = 3;

pub struct LowLevelDebug<S: Syscalls>(S);

impl<S: Syscalls> LowLevelDebug<S> {
    /// Run a check against the low-level debug capsule to ensure it is present.
    ///
    /// Returns `true` if the driver was present. This does not necessarily mean
    /// that the driver is working, as it may still fail to allocate grant
    /// memory.
    #[inline(always)]
    pub fn driver_check() -> bool {
        S::command(DRIVER_NUM, DRIVER_CHECK, 0, 0).is_success()
    }

    /// Print one of the predefined alerts in [`AlertCode`].
    #[inline(always)]
    pub fn print_alert_code(code: AlertCode) {
        let _ = S::command(DRIVER_NUM, PRINT_ALERT_CODE, code as u32, 0);
    }

    /// Print a single number. The number will be printed in hexadecimal.
    ///
    /// In general, this should only be added temporarily for debugging and
    /// should not be called by released library code.
    #[inline(always)]
    pub fn print_1(x: u32) {
        let _ = S::command(DRIVER_NUM, PRINT_1, x, 0);
    }

    /// Print two numbers. The numbers will be printed in hexadecimal.
    ///
    /// Like `print_1`, this is intended for temporary debugging and should not
    /// be called by released library code. If you want to print multiple
    /// values, it is often useful to use the first argument to indicate what
    /// value is being printed.
    #[inline(always)]
    pub fn print_2(x: u32, y: u32) {
        let _ = S::command(DRIVER_NUM, PRINT_2, x, y);
    }
}

/// A predefined alert code, for use with [`LowLevelDebug::print_alert_code`].
pub enum AlertCode {
    /// Application panic (e.g. `panic!()` called in Rust code).
    Panic = 0x01,

    /// A statically-linked app was not installed in the correct location in
    /// flash.
    WrongLocation = 0x02,
}

#[cfg(test)]
mod tests;
<commit_msg>update<commit_after>#![no_std]

use libtock_platform::Syscalls;

/// The low-level debug API provides tools to diagnose userspace issues that
/// make normal debugging workflows (e.g. printing to the console) difficult.
///
/// It allows libraries to print alert codes and apps to print numeric
/// information using only the command system call.
///
/// # Example
/// ```ignore
/// use libtock2::LowLevelDebug;
///
/// // Prints 0x45 and the app which called it.
/// LowLevelDebug::print_1(0x45);
/// ```

pub struct LowLevelDebug<S: Syscalls>(S);

impl<S: Syscalls> LowLevelDebug<S> {
    /// Run a check against the low-level debug capsule to ensure it is present.
    ///
    /// Returns `true` if the driver was present. This does not necessarily mean
    /// that the driver is working, as it may still fail to allocate grant
    /// memory.
    #[inline(always)]
    pub fn driver_check() -> bool {
        S::command(DRIVER_NUM, DRIVER_CHECK, 0, 0).is_success()
    }

    /// Print one of the predefined alerts in [`AlertCode`].
    #[inline(always)]
    pub fn print_alert_code(code: AlertCode) {
        let _ = S::command(DRIVER_NUM, PRINT_ALERT_CODE, code as u32, 0);
    }

    /// Print a single number. The number will be printed in hexadecimal.
    ///
    /// In general, this should only be added temporarily for debugging and
    /// should not be called by released library code.
    #[inline(always)]
    pub fn print_1(x: u32) {
        let _ = S::command(DRIVER_NUM, PRINT_1, x, 0);
    }

    /// Print two numbers. The numbers will be printed in hexadecimal.
    ///
    /// Like `print_1`, this is intended for temporary debugging and should not
    /// be called by released library code. If you want to print multiple
    /// values, it is often useful to use the first argument to indicate what
    /// value is being printed.
    #[inline(always)]
    pub fn print_2(x: u32, y: u32) {
        let _ = S::command(DRIVER_NUM, PRINT_2, x, y);
    }
}

/// A predefined alert code, for use with [`LowLevelDebug::print_alert_code`].
pub enum AlertCode {
    /// Application panic (e.g. `panic!()` called in Rust code).
    Panic = 0x01,

    /// A statically-linked app was not installed in the correct location in
    /// flash.
    WrongLocation = 0x02,
}

#[cfg(test)]
mod tests;

// -----------------------------------------------------------------------------
// Driver number and command IDs
// -----------------------------------------------------------------------------

const DRIVER_NUM: u32 = 8;

// Command IDs
const DRIVER_CHECK: u32 = 0;
const PRINT_ALERT_CODE: u32 = 1;
const PRINT_1: u32 = 2;
const PRINT_2: u32 = 3;
<|endoftext|>


<commit_before>use applied::interval::{Interval, IntervalNode};
use base::{TeardownTree, TeardownTreeInternal, lefti, righti, parenti, Sink};
use base::drivers::{consume_ptr, consume_unchecked};
use base::BulkDeleteCommon;
use base::InternalAccess;
use std::{mem, cmp};

pub trait IntervalTeardownTree<Iv: Interval> {
    fn delete(&mut self, search: &IntervalNode<Iv>) -> Option<Iv>;
    fn delete_intersecting(&mut self, search: &Iv, idx: usize, output: &mut Vec<Iv>);
}

trait IntervalTreeInternal<Iv: Interval> {
    #[inline] fn update_maxb(&mut self, idx: usize);
}

trait IntervalDeleteRange<Iv: Interval> {
    fn delete_intersecting_ivl_rec<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize,
                                                              min_included: bool, sink: &mut S);
    fn descend_delete_intersecting_ivl_left<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool,
                                                                       min_included: bool, sink: &mut S) -> bool;
    fn descend_delete_intersecting_ivl_right<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool,
                                                                        min_included: bool, sink: &mut S) -> bool;
}

//trait IntervalDeleteRange<Iv: Interval> {
//    fn delete_with_driver<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S);
//
//    fn delete_range<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S);
//    fn delete_range_loop<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize);
//
//    fn delete_range_min<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize);
//    fn delete_range_max<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize);
//
//    fn descend_delete_left<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize, with_slot: bool) -> bool;
//    fn descend_delete_right<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize, with_slot: bool) -> bool;
//}

trait PlainDelete<Iv: Interval> {
    #[inline] fn delete_idx(&mut self, idx: usize) -> Iv;
    #[inline] fn delete_max(&mut self, idx: usize) -> (Iv, Iv::K);
    #[inline] fn delete_min(&mut self, idx: usize) -> Iv;
}

impl<Iv: Interval> IntervalTreeInternal<Iv> for TeardownTreeInternal<IntervalNode<Iv>> {
    #[inline]
    fn update_maxb(&mut self, idx: usize) {
        let item = self.item_mut_unsafe(idx);

        let left_self_maxb =
            if self.has_left(idx) {
                cmp::max(&self.left(idx).item.maxb, item.ivl.b())
            } else {
                item.ivl.b()
            };
        item.maxb =
            if self.has_right(idx) {
                cmp::max(&self.right(idx).item.maxb, left_self_maxb)
            } else {
                left_self_maxb
            }.clone();
    }

}

impl<Iv: Interval> IntervalTeardownTree<Iv> for TeardownTree<IntervalNode<Iv>> {
    /// Deletes the item with the given key from the tree and returns it (or None).
    // TODO: accepting IntervalNode is super ugly, temporary solution only
    fn delete(&mut self, search: &IntervalNode<Iv>) -> Option<Iv> {
        self.internal().index_of(search).map(|idx| {
            self.internal().delete_idx(idx)
        })
    }

    #[inline]
    fn delete_intersecting(&mut self, search: &Iv, idx: usize, output: &mut Vec<Iv>) {
        self.internal().delete_intersecting_ivl_rec(search, idx, false, &mut self::IntervalSink { output: output });
    }
}

impl<Iv: Interval> PlainDelete<Iv> for TeardownTreeInternal<IntervalNode<Iv>> {
    #[inline]
    fn delete_idx(&mut self, idx: usize) -> Iv {
        debug_assert!(!self.is_nil(idx));

        let item = self.item_mut_unsafe(idx);

        let replacement: Iv = match (self.has_left(idx), self.has_right(idx)) {
            (false, false) => {
                let item = self.take(idx);
                return item.ivl
            },

            (true, false)  => {
                let (removed, left_maxb) = self.delete_max(lefti(idx));
                item.maxb = left_maxb;
                removed
            },

            (false, true)  => {
//                let (removed, right_maxb) = self.delete_min(righti(idx));
//                item.maxb = right_maxb;
                let removed = self.delete_min(righti(idx));
                if &item.maxb == removed.b() {
                    self.update_maxb(idx)
                } else { // maxb remains the same
                    debug_assert!(removed.b() < &item.maxb);
                }
                removed
            },

            (true, true)   => {
                let (removed, left_maxb) = self.delete_max(lefti(idx));
                if &item.maxb == removed.b() {
                    item.maxb = cmp::max(left_maxb, self.right(idx).item.maxb);
                } else { // maxb remains the same
                    debug_assert!(removed.b() < &item.maxb);
                }
                removed
            },
        };

        mem::replace(&mut item.ivl, replacement)
    }

    /// returns the removed max-item of this subtree and the old maxb (before removal)
    #[inline]
    // we attempt to reduce the number of memory accesses as much as possible; might be overengineered
    fn delete_max(&mut self, idx: usize) -> (Iv, Iv::K) {
        let max_idx = self.find_max(idx);

        let (removed, mut old_maxb, mut new_maxb) = if self.has_left(max_idx) {
            let item = self.item_mut_unsafe(max_idx);
            let (left_max, left_maxb) = self.delete_max(lefti(max_idx));
            let removed = mem::replace(&mut item.ivl, left_max);

            let old_maxb = mem::replace(&mut item.maxb, left_maxb.clone());
            (removed, old_maxb, Some(left_maxb))
        } else {
            let IntervalNode { ivl, maxb:old_maxb } = self.take(max_idx);
            (ivl, old_maxb, None)
        };

        // update ancestors
        let mut upd_idx = max_idx;
        while upd_idx != idx {
            upd_idx = parenti(upd_idx);

            let item = self.item_mut_unsafe(upd_idx);
            old_maxb = item.maxb.clone();
            if &item.maxb == removed.b() {
                let mb = {
                    let self_left_maxb =
                        if self.has_left(upd_idx) {
                            cmp::max(&self.left(upd_idx).item.maxb, &item.maxb)
                        } else {
                            &item.maxb
                        };

                    new_maxb.map_or(self_left_maxb.clone(),
                                    |mb| cmp::max(mb, self_left_maxb.clone()))
                };
                item.maxb = mb.clone();
                new_maxb = Some(mb);
            } else {
                new_maxb = Some(old_maxb.clone());
            }
        }

        (removed, old_maxb)
    }

    // TODO: check whether optimizations similar to delete_max() are worth it
    #[inline]
    fn delete_min(&mut self, idx: usize) -> Iv {
        let min_idx = self.find_min(idx);

        let removed = if self.has_right(min_idx) {
            let right_min = self.delete_min(righti(min_idx));
            let item = self.item_mut_unsafe(min_idx);

            if self.has_right(min_idx) {
                let right_maxb = &self.right(min_idx).item.maxb;
                item.maxb = cmp::max(right_maxb, right_min.b()).clone();
            } else {
                item.maxb = right_min.b().clone();
            }

            mem::replace(&mut item.ivl, right_min)
        } else {
            self.take(min_idx).ivl
        };

        // update ancestors
        let mut upd_idx = min_idx;
        while upd_idx != idx {
            upd_idx = parenti(upd_idx);
            self.update_maxb(upd_idx);
        }

        removed
    }
}

impl<Iv: Interval> IntervalDeleteRange<Iv> for TeardownTreeInternal<IntervalNode<Iv>> {
    fn delete_intersecting_ivl_rec<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, mut min_included: bool, sink: &mut S) {
        let k: &IntervalNode<Iv> = &self.node_unsafe(idx).item;

        if k.max() <= search.a() {
            // whole subtree outside the range
            if self.slots_min().has_open() {
                self.fill_slots_min(idx);
            }
            if self.slots_max().has_open() && !self.is_nil(idx) {
                self.fill_slots_max(idx);
            }
        } else if search.b() <= k.a() {
            // root and right are outside the range
            self.descend_delete_intersecting_ivl_left(search, idx, false, min_included, sink);

            let removed = if self.slots_min().has_open() {
                self.fill_slot_min(idx);

                self.descend_fill_right(idx)
            } else {
                false
            };

            if self.slots_max().has_open() {
                if removed {
                    self.descend_fill_left(idx);
                } else {
                    self.fill_slots_max(idx);
                }
            }
        } else {
            // consume root if necessary
            let consume = search.a() < k.b() && k.a() < search.b();
            let item = if consume
                { Some(self.take(idx)) }
            else
                { None };

            // left subtree
            let mut removed = consume;
            if consume {
                if min_included {
                    self.consume_subtree(lefti(idx), sink)
                } else {
                    removed = self.descend_delete_intersecting_ivl_left(search, idx, true, false, sink);
                }

                sink.consume_unchecked(item.unwrap());
            } else {
                removed = self.descend_delete_intersecting_ivl_left(search, idx, false, min_included, sink);
            }

            // right subtree
            min_included = min_included || search.a() <= k.a();
            if min_included {
                let max_included = k.max() <= search.b();
                if max_included {
                    self.consume_subtree(righti(idx), sink);
                } else {
                    removed = self.descend_delete_intersecting_ivl_right(search, idx, removed, min_included, sink);
                }
            } else {
                removed = self.descend_delete_intersecting_ivl_right(search, idx, removed, false, sink);
            }

            // fill the remaining open slots_max from the left subtree
            if removed && self.slots_max().has_open() {
                self.descend_fill_left(righti(idx));
            }
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_intersecting_ivl_left<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool, min_included: bool, sink: &mut S) -> bool {
        if with_slot {
            self.descend_left_with_slot(idx,
                                        |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            )
        } else {
            self.descend_left(idx,
                              |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            );

            false
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_intersecting_ivl_right<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool, min_included: bool, sink: &mut S) -> bool {
        if with_slot {
            self.descend_right_with_slot(idx,
                                         |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            )
        } else {
            self.descend_right(idx,
                               |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            );

            false
        }
    }
}

struct IntervalSink<'a, Iv: Interval+'a> {
    output: &'a mut Vec<Iv>
}

impl<'a, Iv: Interval> Sink<IntervalNode<Iv>> for IntervalSink<'a, Iv> {
    fn consume(&mut self, item: IntervalNode<Iv>) {
        self.output.push(item.ivl)
    }

    fn consume_unchecked(&mut self, item: IntervalNode<Iv>) {
        consume_unchecked(&mut self.output, item.ivl);
    }

    fn consume_ptr(&mut self, src: *const IntervalNode<Iv>) {
        let p = unsafe { &(*src).ivl };
        consume_ptr(&mut self.output, p)
    }
}
<commit_msg>properly update IntervalNode::maxb in PlainDelete for TeardownTreeInternal<commit_after>use applied::interval::{Interval, IntervalNode};
use base::{TeardownTree, TeardownTreeInternal, lefti, righti, parenti, Sink};
use base::drivers::{consume_ptr, consume_unchecked};
use base::BulkDeleteCommon;
use base::InternalAccess;
use std::{mem, cmp};

pub trait IntervalTeardownTree<Iv: Interval> {
    fn delete(&mut self, search: &IntervalNode<Iv>) -> Option<Iv>;
    fn delete_intersecting(&mut self, search: &Iv, idx: usize, output: &mut Vec<Iv>);
}

trait IntervalTreeInternal<Iv: Interval> {
    #[inline] fn update_maxb(&mut self, idx: usize);

    #[inline] fn delete(&mut self, search: &IntervalNode<Iv>) -> Option<Iv>;

    #[inline] fn delete_intersecting(&mut self, search: &Iv, idx: usize, output: &mut Vec<Iv>);
}

trait IntervalDeleteRange<Iv: Interval> {
    fn delete_intersecting_ivl_rec<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize,
                                                              min_included: bool, sink: &mut S);
    fn descend_delete_intersecting_ivl_left<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool,
                                                                       min_included: bool, sink: &mut S) -> bool;
    fn descend_delete_intersecting_ivl_right<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool,
                                                                        min_included: bool, sink: &mut S) -> bool;
}

//trait IntervalDeleteRange<Iv: Interval> {
//    fn delete_with_driver<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S);
//
//    fn delete_range<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S);
//    fn delete_range_loop<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize);
//
//    fn delete_range_min<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize);
//    fn delete_range_max<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize);
//
//    fn descend_delete_left<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize, with_slot: bool) -> bool;
//    fn descend_delete_right<S: Sink<IntervalNode<Iv>>>(&mut self, drv: &mut S, idx: usize, with_slot: bool) -> bool;
//}

trait PlainDelete<Iv: Interval> {
    #[inline] fn delete_idx(&mut self, idx: usize) -> Iv;
    #[inline] fn delete_max(&mut self, idx: usize) -> (Iv, Iv::K);
    #[inline] fn delete_min(&mut self, idx: usize) -> Iv;
}

impl<Iv: Interval> IntervalTeardownTree<Iv> for TeardownTree<IntervalNode<Iv>> {
    /// Deletes the item with the given key from the tree and returns it (or None).
    // TODO: accepting IntervalNode is super ugly, temporary solution only
    #[inline]
    fn delete(&mut self, search: &IntervalNode<Iv>) -> Option<Iv> {
        self.internal().delete(search)
    }

    #[inline]
    fn delete_intersecting(&mut self, search: &Iv, idx: usize, output: &mut Vec<Iv>) {
        self.internal().delete_intersecting(search, idx, output)
    }
}

impl<Iv: Interval> IntervalTreeInternal<Iv> for TeardownTreeInternal<IntervalNode<Iv>> {
    /// Deletes the item with the given key from the tree and returns it (or None).
    // TODO: accepting IntervalNode is super ugly, temporary solution only
    #[inline]
    fn delete(&mut self, search: &IntervalNode<Iv>) -> Option<Iv> {
        self.index_of(search).map(|idx| {
            let removed = self.delete_idx(idx);
            let mut upd_idx = idx;
            while upd_idx != 0 {
                upd_idx = parenti(upd_idx);
                if removed.b() == &self.item(idx).maxb {
                    self.update_maxb(idx);
                } else {
                    break;
                }
            }
            removed
        })
    }

    #[inline]
    fn delete_intersecting(&mut self, search: &Iv, idx: usize, output: &mut Vec<Iv>) {
        self.delete_intersecting_ivl_rec(search, idx, false, &mut self::IntervalSink { output: output });
    }

    #[inline]
    fn update_maxb(&mut self, idx: usize) {
        let item = self.item_mut_unsafe(idx);

        let left_self_maxb =
            if self.has_left(idx) {
                cmp::max(&self.left(idx).item.maxb, item.ivl.b())
            } else {
                item.ivl.b()
            };
        item.maxb =
            if self.has_right(idx) {
                cmp::max(&self.right(idx).item.maxb, left_self_maxb)
            } else {
                left_self_maxb
            }.clone();
    }

}

impl<Iv: Interval> PlainDelete<Iv> for TeardownTreeInternal<IntervalNode<Iv>> {
    #[inline]
    fn delete_idx(&mut self, idx: usize) -> Iv {
        debug_assert!(!self.is_nil(idx));

        let item = self.item_mut_unsafe(idx);

        let replacement: Iv = match (self.has_left(idx), self.has_right(idx)) {
            (false, false) => {
                let item = self.take(idx);
                return item.ivl
            },

            (true, false)  => {
                let (removed, left_maxb) = self.delete_max(lefti(idx));
                item.maxb = left_maxb;
                removed
            },

            (false, true)  => {
//                let (removed, right_maxb) = self.delete_min(righti(idx));
//                item.maxb = right_maxb;
                let removed = self.delete_min(righti(idx));
                if &item.maxb == removed.b() {
                    self.update_maxb(idx)
                } else { // maxb remains the same
                    debug_assert!(removed.b() < &item.maxb);
                }
                removed
            },

            (true, true)   => {
                let (removed, left_maxb) = self.delete_max(lefti(idx));
                if &item.maxb == removed.b() {
                    item.maxb = cmp::max(left_maxb, self.right(idx).item.maxb.clone());
                } else { // maxb remains the same
                    debug_assert!(removed.b() < &item.maxb);
                }
                removed
            },
        };

        mem::replace(&mut item.ivl, replacement)
    }

    /// returns the removed max-item of this subtree and the old maxb (before removal)
    #[inline]
    // we attempt to reduce the number of memory accesses as much as possible; might be overengineered
    fn delete_max(&mut self, idx: usize) -> (Iv, Iv::K) {
        let max_idx = self.find_max(idx);

        let (removed, mut old_maxb, mut new_maxb) = if self.has_left(max_idx) {
            let item = self.item_mut_unsafe(max_idx);
            let (left_max, left_maxb) = self.delete_max(lefti(max_idx));
            let removed = mem::replace(&mut item.ivl, left_max);

            let old_maxb = mem::replace(&mut item.maxb, left_maxb.clone());
            (removed, old_maxb, Some(left_maxb))
        } else {
            let IntervalNode { ivl, maxb:old_maxb } = self.take(max_idx);
            (ivl, old_maxb, None)
        };

        // update ancestors
        let mut upd_idx = max_idx;
        while upd_idx != idx {
            upd_idx = parenti(upd_idx);

            let item = self.item_mut_unsafe(upd_idx);
            old_maxb = item.maxb.clone();
            if &item.maxb == removed.b() {
                let mb = {
                    let self_left_maxb =
                        if self.has_left(upd_idx) {
                            cmp::max(&self.left(upd_idx).item.maxb, &item.maxb)
                        } else {
                            &item.maxb
                        };

                    new_maxb.map_or(self_left_maxb.clone(),
                                    |mb| cmp::max(mb, self_left_maxb.clone()))
                };
                item.maxb = mb.clone();
                new_maxb = Some(mb);
            } else {
                new_maxb = Some(old_maxb.clone());
            }
        }

        (removed, old_maxb)
    }

    // TODO: check whether optimizations similar to delete_max() are worth it
    #[inline]
    fn delete_min(&mut self, idx: usize) -> Iv {
        let min_idx = self.find_min(idx);

        let removed = if self.has_right(min_idx) {
            let right_min = self.delete_min(righti(min_idx));
            let item = self.item_mut_unsafe(min_idx);

            if self.has_right(min_idx) {
                let right_maxb = &self.right(min_idx).item.maxb;
                item.maxb = cmp::max(right_maxb, right_min.b()).clone();
            } else {
                item.maxb = right_min.b().clone();
            }

            mem::replace(&mut item.ivl, right_min)
        } else {
            self.take(min_idx).ivl
        };

        // update ancestors
        let mut upd_idx = min_idx;
        while upd_idx != idx {
            upd_idx = parenti(upd_idx);
            self.update_maxb(upd_idx);
        }

        removed
    }
}

impl<Iv: Interval> IntervalDeleteRange<Iv> for TeardownTreeInternal<IntervalNode<Iv>> {
    fn delete_intersecting_ivl_rec<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, mut min_included: bool, sink: &mut S) {
        let k: &IntervalNode<Iv> = &self.node_unsafe(idx).item;

        if k.max() <= search.a() {
            // whole subtree outside the range
            if self.slots_min().has_open() {
                self.fill_slots_min(idx);
            }
            if self.slots_max().has_open() && !self.is_nil(idx) {
                self.fill_slots_max(idx);
            }
        } else if search.b() <= k.a() {
            // root and right are outside the range
            self.descend_delete_intersecting_ivl_left(search, idx, false, min_included, sink);

            let removed = if self.slots_min().has_open() {
                self.fill_slot_min(idx);

                self.descend_fill_right(idx)
            } else {
                false
            };

            if self.slots_max().has_open() {
                if removed {
                    self.descend_fill_left(idx);
                } else {
                    self.fill_slots_max(idx);
                }
            }
        } else {
            // consume root if necessary
            let consume = search.a() < k.b() && k.a() < search.b();
            let item = if consume
                { Some(self.take(idx)) }
            else
                { None };

            // left subtree
            let mut removed = consume;
            if consume {
                if min_included {
                    self.consume_subtree(lefti(idx), sink)
                } else {
                    removed = self.descend_delete_intersecting_ivl_left(search, idx, true, false, sink);
                }

                sink.consume_unchecked(item.unwrap());
            } else {
                removed = self.descend_delete_intersecting_ivl_left(search, idx, false, min_included, sink);
            }

            // right subtree
            min_included = min_included || search.a() <= k.a();
            if min_included {
                let max_included = k.max() <= search.b();
                if max_included {
                    self.consume_subtree(righti(idx), sink);
                } else {
                    removed = self.descend_delete_intersecting_ivl_right(search, idx, removed, min_included, sink);
                }
            } else {
                removed = self.descend_delete_intersecting_ivl_right(search, idx, removed, false, sink);
            }

            // fill the remaining open slots_max from the left subtree
            if removed && self.slots_max().has_open() {
                self.descend_fill_left(righti(idx));
            }
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_intersecting_ivl_left<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool, min_included: bool, sink: &mut S) -> bool {
        if with_slot {
            self.descend_left_with_slot(idx,
                                        |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            )
        } else {
            self.descend_left(idx,
                              |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            );

            false
        }
    }

    /// Returns true if the item is removed after recursive call, false otherwise.
    #[inline(always)]
    fn descend_delete_intersecting_ivl_right<S: Sink<IntervalNode<Iv>>>(&mut self, search: &Iv, idx: usize, with_slot: bool, min_included: bool, sink: &mut S) -> bool {
        if with_slot {
            self.descend_right_with_slot(idx,
                                         |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            )
        } else {
            self.descend_right(idx,
                               |this: &mut Self, child_idx| this.delete_intersecting_ivl_rec(search, child_idx, min_included, sink)
            );

            false
        }
    }
}

struct IntervalSink<'a, Iv: Interval+'a> {
    output: &'a mut Vec<Iv>
}

impl<'a, Iv: Interval> Sink<IntervalNode<Iv>> for IntervalSink<'a, Iv> {
    fn consume(&mut self, item: IntervalNode<Iv>) {
        self.output.push(item.ivl)
    }

    fn consume_unchecked(&mut self, item: IntervalNode<Iv>) {
        consume_unchecked(&mut self.output, item.ivl);
    }

    fn consume_ptr(&mut self, src: *const IntervalNode<Iv>) {
        let p = unsafe { &(*src).ivl };
        consume_ptr(&mut self.output, p)
    }
}
<|endoftext|>