<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use data_model::*;
use std;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::result;
use sys_util::{Error as SysError, EventFd};

use std::fs::File;
use std::net::{TcpListener, TcpStream, UdpSocket};
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};

#[derive(Debug, PartialEq)]
/// An error during transaction or serialization/deserialization.
pub enum MsgError {
    /// Error while sending a request or response.
    Send(SysError),
    /// Error while receiving a request or response.
    Recv(SysError),
    /// The type of a received request or response is unknown.
    InvalidType,
    /// There was not the expected amount of data when receiving a message. The inner
    /// value is how much data is needed.
    BadRecvSize(usize),
    /// There was no associated file descriptor received for a request that expected it.
    ExpectFd,
    /// There was some associated file descriptor received but not used when deserialize.
    NotExpectFd,
    /// Trying to serialize/deserialize, but fd buffer size is too small. This typically happens
    /// when max_fd_count() returns a value that is too small.
    WrongFdBufferSize,
    /// Trying to serialize/deserialize, but msg buffer size is too small. This typically happens
    /// when msg_size() returns a value that is too small.
    WrongMsgBufferSize,
}

pub type MsgResult<T> = result::Result<T, MsgError>;

/// A msg that could be serialized to and deserialize from array in little endian.
///
/// For structs, we always have fixed size of bytes and fixed count of fds.
/// For enums, the size needed might be different for each variant.
///
/// e.g.
/// ```
/// use std::os::unix::io::RawFd;
/// enum Message {
///     VariantA(u8),
///     VariantB(u32, RawFd),
///     VariantC,
/// }
/// ```
///
/// For variant A, we need 1 byte to store its inner value.
/// For variant B, we need 4 bytes and 1 RawFd to store its inner value.
/// For variant C, we need 0 bytes to store its inner value.
/// When we serialize Message to (buffer, fd_buffer), we always use fixed number of bytes in
/// the buffer. Unused buffer bytes will be padded with zero.
/// However, for fd_buffer, we could not do the same thing. Otherwise, we are essentially sending
/// fd 0 through the socket.
/// Thus, read/write functions always the return correct count of fds in this variant. There will be
/// no padding in fd_buffer.
pub trait MsgOnSocket: Sized {
    /// Size of message in bytes.
    fn msg_size() -> usize;
    /// Max possible fd count in this type.
    fn max_fd_count() -> usize {
        0
    }
    /// Returns (self, fd read count).
    /// This function is safe only when:
    ///     0. fds contains valid fds, received from socket, serialized by Self::write_to_buffer.
    ///     1. For enum, fds contains correct fd layout of the particular variant.
    ///     2. write_to_buffer is implemented correctly(put valid fds into the buffer, has no padding,
    ///        return correct count).
    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)>;
    /// Serialize self to buffers.
    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize>;
}

impl MsgOnSocket for SysError {
    fn msg_size() -> usize {
        u32::msg_size()
    }
    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
        let (v, size) = u32::read_from_buffer(buffer, fds)?;
        Ok((SysError::new(v as i32), size))
    }
    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
        let v = self.errno() as u32;
        v.write_to_buffer(buffer, fds)
    }
}

impl MsgOnSocket for RawFd {
    fn msg_size() -> usize {
        0
    }
    fn max_fd_count() -> usize {
        1
    }
    unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
        if fds.len() < 1 {
            return Err(MsgError::ExpectFd);
        }
        Ok((fds[0], 1))
    }
    fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
        if fds.len() < 1 {
            return Err(MsgError::WrongFdBufferSize);
        }
        fds[0] = self.clone();
        Ok(1)
    }
}

macro_rules! rawfd_impl {
    ($type:ident) => {
        impl MsgOnSocket for $type {
            fn msg_size() -> usize {
                0
            }
            fn max_fd_count() -> usize {
                1
            }
            unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
                if fds.len() < 1 {
                    return Err(MsgError::ExpectFd);
                }
                Ok(($type::from_raw_fd(fds[0].clone()), 1))
            }
            fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
                if fds.len() < 1 {
                    return Err(MsgError::WrongFdBufferSize);
                }
                fds[0] = self.as_raw_fd();
                Ok(1)
            }
        }
    };
}

rawfd_impl!(EventFd);
rawfd_impl!(File);
rawfd_impl!(UnixStream);
rawfd_impl!(TcpStream);
rawfd_impl!(TcpListener);
rawfd_impl!(UdpSocket);
rawfd_impl!(UnixListener);
rawfd_impl!(UnixDatagram);

// usize could be different sizes on different targets. We always use u64.
impl MsgOnSocket for usize {
    fn msg_size() -> usize {
        std::mem::size_of::<u64>()
    }
    unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
        if buffer.len() < std::mem::size_of::<u64>() {
            return Err(MsgError::WrongMsgBufferSize);
        }
        let t: u64 = Le64::from_slice(&buffer[0..Self::msg_size()])
            .unwrap()
            .clone()
            .into();
        Ok((t as usize, 0))
    }

    fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
        if buffer.len() < std::mem::size_of::<u64>() {
            return Err(MsgError::WrongMsgBufferSize);
        }
        let t: Le64 = (*self as u64).into();
        buffer[0..Self::msg_size()].copy_from_slice(t.as_slice());
        Ok(0)
    }
}

macro_rules! le_impl {
    ($type:ident, $le_type:ident) => {
        impl MsgOnSocket for $type {
            fn msg_size() -> usize {
                std::mem::size_of::<$le_type>()
            }
            unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
                if buffer.len() < std::mem::size_of::<$le_type>() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let t = $le_type::from_slice(&buffer[0..Self::msg_size()])
                    .unwrap()
                    .clone();
                Ok((t.into(), 0))
            }

            fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
                if buffer.len() < std::mem::size_of::<$le_type>() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let t: $le_type = self.clone().into();
                buffer[0..Self::msg_size()].copy_from_slice(t.as_slice());
                Ok(0)
            }
        }
    };
}

le_impl!(u8, u8);
le_impl!(u16, Le16);
le_impl!(u32, Le32);
le_impl!(u64, Le64);

le_impl!(Le16, Le16);
le_impl!(Le32, Le32);
le_impl!(Le64, Le64);

macro_rules! array_impls {
    ($N:expr, $t: ident $($ts:ident)*)
    => {
        impl<T: MsgOnSocket + Clone> MsgOnSocket for [T; $N] {
            fn msg_size() -> usize {
                T::msg_size() * $N
            }
            fn max_fd_count() -> usize {
                T::max_fd_count() * $N
            }
            unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
                if buffer.len() < Self::msg_size() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let mut offset = 0usize;
                let mut fd_offset = 0usize;
                let ($t, fd_size) =
                    T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
                offset += T::msg_size();
                fd_offset += fd_size;
                $(
                    let ($ts, fd_size) =
                        T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
                    offset += T::msg_size();
                    fd_offset += fd_size;
                    )*
                assert_eq!(offset, Self::msg_size());
                Ok(([$t, $($ts),*], fd_offset))
            }

            fn write_to_buffer(
                &self,
                buffer: &mut [u8],
                fds: &mut [RawFd],
                ) -> MsgResult<usize> {
                if buffer.len() < Self::msg_size() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let mut offset = 0usize;
                let mut fd_offset = 0usize;
                for idx in 0..$N {
                    let fd_size = self[idx].clone().write_to_buffer(&mut buffer[offset..],
                                                            &mut fds[fd_offset..])?;
                    offset += T::msg_size();
                    fd_offset += fd_size;
                }

                Ok(fd_offset)
            }
        }
        array_impls!(($N - 1), $($ts)*);
    };
    {$N:expr, } => {};
}

array_impls! {
    32, tmp1 tmp2 tmp3 tmp4 tmp5 tmp6 tmp7 tmp8 tmp9 tmp10 tmp11 tmp12 tmp13 tmp14 tmp15 tmp16
        tmp17 tmp18 tmp19 tmp20 tmp21 tmp22 tmp23 tmp24 tmp25 tmp26 tmp27 tmp28 tmp29 tmp30 tmp31
        tmp32
}

// TODO(jkwang) Define MsgOnSocket for tuple?
<commit_msg>msg_socket: fix msg_on_socket alignment issue<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use data_model::*;
use std;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::result;
use sys_util::{Error as SysError, EventFd};

use std::fs::File;
use std::net::{TcpListener, TcpStream, UdpSocket};
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};

#[derive(Debug, PartialEq)]
/// An error during transaction or serialization/deserialization.
pub enum MsgError {
    /// Error while sending a request or response.
    Send(SysError),
    /// Error while receiving a request or response.
    Recv(SysError),
    /// The type of a received request or response is unknown.
    InvalidType,
    /// There was not the expected amount of data when receiving a message. The inner
    /// value is how much data is needed.
    BadRecvSize(usize),
    /// There was no associated file descriptor received for a request that expected it.
    ExpectFd,
    /// There was some associated file descriptor received but not used when deserialize.
    NotExpectFd,
    /// Trying to serialize/deserialize, but fd buffer size is too small. This typically happens
    /// when max_fd_count() returns a value that is too small.
    WrongFdBufferSize,
    /// Trying to serialize/deserialize, but msg buffer size is too small. This typically happens
    /// when msg_size() returns a value that is too small.
    WrongMsgBufferSize,
}

pub type MsgResult<T> = result::Result<T, MsgError>;

/// A msg that could be serialized to and deserialize from array in little endian.
///
/// For structs, we always have fixed size of bytes and fixed count of fds.
/// For enums, the size needed might be different for each variant.
///
/// e.g.
/// ```
/// use std::os::unix::io::RawFd;
/// enum Message {
///     VariantA(u8),
///     VariantB(u32, RawFd),
///     VariantC,
/// }
/// ```
///
/// For variant A, we need 1 byte to store its inner value.
/// For variant B, we need 4 bytes and 1 RawFd to store its inner value.
/// For variant C, we need 0 bytes to store its inner value.
/// When we serialize Message to (buffer, fd_buffer), we always use fixed number of bytes in
/// the buffer. Unused buffer bytes will be padded with zero.
/// However, for fd_buffer, we could not do the same thing. Otherwise, we are essentially sending
/// fd 0 through the socket.
/// Thus, read/write functions always the return correct count of fds in this variant. There will be
/// no padding in fd_buffer.
pub trait MsgOnSocket: Sized {
    /// Size of message in bytes.
    fn msg_size() -> usize;
    /// Max possible fd count in this type.
    fn max_fd_count() -> usize {
        0
    }
    /// Returns (self, fd read count).
    /// This function is safe only when:
    ///     0. fds contains valid fds, received from socket, serialized by Self::write_to_buffer.
    ///     1. For enum, fds contains correct fd layout of the particular variant.
    ///     2. write_to_buffer is implemented correctly(put valid fds into the buffer, has no padding,
    ///        return correct count).
    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)>;
    /// Serialize self to buffers.
    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize>;
}

impl MsgOnSocket for SysError {
    fn msg_size() -> usize {
        u32::msg_size()
    }
    unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
        let (v, size) = u32::read_from_buffer(buffer, fds)?;
        Ok((SysError::new(v as i32), size))
    }
    fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
        let v = self.errno() as u32;
        v.write_to_buffer(buffer, fds)
    }
}

impl MsgOnSocket for RawFd {
    fn msg_size() -> usize {
        0
    }
    fn max_fd_count() -> usize {
        1
    }
    unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
        if fds.len() < 1 {
            return Err(MsgError::ExpectFd);
        }
        Ok((fds[0], 1))
    }
    fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
        if fds.len() < 1 {
            return Err(MsgError::WrongFdBufferSize);
        }
        fds[0] = self.clone();
        Ok(1)
    }
}

macro_rules! rawfd_impl {
    ($type:ident) => {
        impl MsgOnSocket for $type {
            fn msg_size() -> usize {
                0
            }
            fn max_fd_count() -> usize {
                1
            }
            unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
                if fds.len() < 1 {
                    return Err(MsgError::ExpectFd);
                }
                Ok(($type::from_raw_fd(fds[0].clone()), 1))
            }
            fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
                if fds.len() < 1 {
                    return Err(MsgError::WrongFdBufferSize);
                }
                fds[0] = self.as_raw_fd();
                Ok(1)
            }
        }
    };
}

rawfd_impl!(EventFd);
rawfd_impl!(File);
rawfd_impl!(UnixStream);
rawfd_impl!(TcpStream);
rawfd_impl!(TcpListener);
rawfd_impl!(UdpSocket);
rawfd_impl!(UnixListener);
rawfd_impl!(UnixDatagram);

// This trait is unsafe as it use uninitialized memory.
// Please only implement it for primitive types.
unsafe trait AlignedNew: Sized + DataInit {
    unsafe fn from_unaligned(buffer: &[u8]) -> Option<Self> {
        let mut value = std::mem::uninitialized::<Self>();
        {
            let value_mem = value.as_mut_slice();
            if value_mem.len() != buffer.len() {
                return None;
            }
            value_mem.copy_from_slice(buffer);
        }
        Some(value)
    }
}

unsafe impl AlignedNew for u8 {}
unsafe impl AlignedNew for u16 {}
unsafe impl AlignedNew for u32 {}
unsafe impl AlignedNew for u64 {}

unsafe impl AlignedNew for Le16 {}
unsafe impl AlignedNew for Le32 {}
unsafe impl AlignedNew for Le64 {}

// usize could be different sizes on different targets. We always use u64.
impl MsgOnSocket for usize {
    fn msg_size() -> usize {
        std::mem::size_of::<u64>()
    }
    unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
        if buffer.len() < std::mem::size_of::<u64>() {
            return Err(MsgError::WrongMsgBufferSize);
        }
        let t: u64 = Le64::from_unaligned(&buffer[0..Self::msg_size()])
            .unwrap()
            .into();
        Ok((t as usize, 0))
    }

    fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
        if buffer.len() < std::mem::size_of::<u64>() {
            return Err(MsgError::WrongMsgBufferSize);
        }
        let t: Le64 = (*self as u64).into();
        buffer[0..Self::msg_size()].copy_from_slice(t.as_slice());
        Ok(0)
    }
}

macro_rules! le_impl {
    ($type:ident, $le_type:ident) => {
        impl MsgOnSocket for $type {
            fn msg_size() -> usize {
                std::mem::size_of::<$le_type>()
            }
            unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
                if buffer.len() < std::mem::size_of::<$le_type>() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let t = $le_type::from_unaligned(&buffer[0..Self::msg_size()])
                    .unwrap();
                Ok((t.into(), 0))
            }

            fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
                if buffer.len() < std::mem::size_of::<$le_type>() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let t: $le_type = self.clone().into();
                buffer[0..Self::msg_size()].copy_from_slice(t.as_slice());
                Ok(0)
            }
        }
    };
}

le_impl!(u8, u8);
le_impl!(u16, Le16);
le_impl!(u32, Le32);
le_impl!(u64, Le64);

le_impl!(Le16, Le16);
le_impl!(Le32, Le32);
le_impl!(Le64, Le64);

macro_rules! array_impls {
    ($N:expr, $t: ident $($ts:ident)*)
    => {
        impl<T: MsgOnSocket + Clone> MsgOnSocket for [T; $N] {
            fn msg_size() -> usize {
                T::msg_size() * $N
            }
            fn max_fd_count() -> usize {
                T::max_fd_count() * $N
            }
            unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
                if buffer.len() < Self::msg_size() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let mut offset = 0usize;
                let mut fd_offset = 0usize;
                let ($t, fd_size) =
                    T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
                offset += T::msg_size();
                fd_offset += fd_size;
                $(
                    let ($ts, fd_size) =
                        T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
                    offset += T::msg_size();
                    fd_offset += fd_size;
                    )*
                assert_eq!(offset, Self::msg_size());
                Ok(([$t, $($ts),*], fd_offset))
            }

            fn write_to_buffer(
                &self,
                buffer: &mut [u8],
                fds: &mut [RawFd],
                ) -> MsgResult<usize> {
                if buffer.len() < Self::msg_size() {
                    return Err(MsgError::WrongMsgBufferSize);
                }
                let mut offset = 0usize;
                let mut fd_offset = 0usize;
                for idx in 0..$N {
                    let fd_size = self[idx].clone().write_to_buffer(&mut buffer[offset..],
                                                            &mut fds[fd_offset..])?;
                    offset += T::msg_size();
                    fd_offset += fd_size;
                }

                Ok(fd_offset)
            }
        }
        array_impls!(($N - 1), $($ts)*);
    };
    {$N:expr, } => {};
}

array_impls! {
    32, tmp1 tmp2 tmp3 tmp4 tmp5 tmp6 tmp7 tmp8 tmp9 tmp10 tmp11 tmp12 tmp13 tmp14 tmp15 tmp16
        tmp17 tmp18 tmp19 tmp20 tmp21 tmp22 tmp23 tmp24 tmp25 tmp26 tmp27 tmp28 tmp29 tmp30 tmp31
        tmp32
}

// TODO(jkwang) Define MsgOnSocket for tuple?
<|endoftext|>


<commit_before>use futures::channel::mpsc as async_mpsc;

use gettextrs::gettext;
use gstreamer as gst;
use gtk;
use gtk::prelude::*;
use log::warn;

use std::{
    borrow::ToOwned,
    path::Path,
    rc::Rc,
    string::ToString,
    sync::{Arc, RwLock},
};

use media::{MediaEvent, SplitterPipeline};
use metadata::{get_default_chapter_title, Duration, Format, MediaInfo, Stream, TocVisitor};

use super::{PlaybackPipeline, UIController, UIEventSender, UIFocusContext};

use super::output_base_controller::{
    MediaProcessor, OutputBaseController, OutputControllerImpl, OutputMediaFileInfo,
    ProcessingState, ProcessingType, MEDIA_EVENT_CHANNEL_CAPACITY,
};

pub type SplitController = OutputBaseController<SplitControllerImpl>;

impl SplitController {
    pub fn new(builder: &gtk::Builder, ui_event: UIEventSender) -> Self {
        OutputBaseController::<SplitControllerImpl>::new_base(
            SplitControllerImpl::new(builder),
            builder,
            ui_event,
        )
    }
}

macro_rules! update_list_with_format(
    ($self_:expr, $format:expr, $row:ident, $label:ident) => {
        match SplitterPipeline::check_requirements($format) {
            Ok(_) => if !$self_.is_usable {
                $self_.split_list.select_row(Some(&$self_.$row));
                $self_.is_usable = true;
            },
            Err(err) => {
                warn!("{}", err);
                $self_.$label.set_label(&err);
                $self_.$row.set_sensitive(false);
            }
        }
    };
);

pub struct SplitControllerImpl {
    is_usable: bool,

    src_info: Option<Arc<RwLock<MediaInfo>>>,
    selected_audio: Option<Stream>,

    split_file_info: Option<OutputMediaFileInfo>,
    media_event_sender: Option<async_mpsc::Sender<MediaEvent>>,
    splitter_pipeline: Option<SplitterPipeline>,
    toc_visitor: Option<TocVisitor>,
    idx: usize,
    last_progress: f64,
    current_chapter: Option<gst::TocEntry>,
    current_path: Option<Rc<Path>>,

    split_list: gtk::ListBox,
    split_to_flac_row: gtk::ListBoxRow,
    flac_warning_lbl: gtk::Label,
    split_to_wave_row: gtk::ListBoxRow,
    wave_warning_lbl: gtk::Label,
    split_to_opus_row: gtk::ListBoxRow,
    opus_warning_lbl: gtk::Label,
    split_to_vorbis_row: gtk::ListBoxRow,
    vorbis_warning_lbl: gtk::Label,
    split_to_mp3_row: gtk::ListBoxRow,
    mp3_warning_lbl: gtk::Label,

    split_btn: gtk::Button,
}

impl OutputControllerImpl for SplitControllerImpl {
    const FOCUS_CONTEXT: UIFocusContext = UIFocusContext::SplitPage;
    const BTN_NAME: &'static str = "split-btn";
    const LIST_NAME: &'static str = "split-list-box";
    const PROGRESS_BAR_NAME: &'static str = "split-progress";
}

impl UIController for SplitControllerImpl {
    fn new_media(&mut self, pipeline: &PlaybackPipeline) {
        let info_arc = Arc::clone(&pipeline.info);
        self.src_info = Some(info_arc);
    }

    fn cleanup(&mut self) {
        self.src_info = None;
        self.selected_audio = None;

        self.reset();
    }

    fn streams_changed(&mut self, info: &MediaInfo) {
        self.selected_audio = info.streams.selected_audio().map(ToOwned::to_owned);
        if self.is_usable {
            self.split_btn.set_sensitive(self.selected_audio.is_some());
        }
    }
}

impl SplitControllerImpl {
    pub fn new(builder: &gtk::Builder) -> Self {
        let mut ctrl = SplitControllerImpl {
            is_usable: false,

            src_info: None,
            selected_audio: None,

            split_file_info: None,
            media_event_sender: None,
            splitter_pipeline: None,
            toc_visitor: None,
            idx: 0,
            last_progress: 0f64,
            current_chapter: None,
            current_path: None,

            split_list: builder.get_object(Self::LIST_NAME).unwrap(),
            split_to_flac_row: builder.get_object("flac_split-row").unwrap(),
            flac_warning_lbl: builder.get_object("flac_warning-lbl").unwrap(),
            split_to_wave_row: builder.get_object("wave_split-row").unwrap(),
            wave_warning_lbl: builder.get_object("wave_warning-lbl").unwrap(),
            split_to_opus_row: builder.get_object("opus_split-row").unwrap(),
            opus_warning_lbl: builder.get_object("opus_warning-lbl").unwrap(),
            split_to_vorbis_row: builder.get_object("vorbis_split-row").unwrap(),
            vorbis_warning_lbl: builder.get_object("vorbis_warning-lbl").unwrap(),
            split_to_mp3_row: builder.get_object("mp3_split-row").unwrap(),
            mp3_warning_lbl: builder.get_object("mp3_warning-lbl").unwrap(),

            split_btn: builder.get_object(Self::BTN_NAME).unwrap(),
        };

        update_list_with_format!(ctrl, Format::Flac, split_to_flac_row, flac_warning_lbl);
        update_list_with_format!(ctrl, Format::Wave, split_to_wave_row, wave_warning_lbl);
        update_list_with_format!(ctrl, Format::Opus, split_to_opus_row, opus_warning_lbl);
        update_list_with_format!(
            ctrl,
            Format::Vorbis,
            split_to_vorbis_row,
            vorbis_warning_lbl
        );
        update_list_with_format!(ctrl, Format::MP3, split_to_mp3_row, mp3_warning_lbl);

        ctrl.split_list.set_sensitive(ctrl.is_usable);
        ctrl.split_btn.set_sensitive(ctrl.is_usable);

        ctrl
    }

    fn reset(&mut self) {
        self.split_file_info = None;
        self.media_event_sender = None;
        self.splitter_pipeline = None;
        self.toc_visitor = None;
        self.idx = 0;
        self.last_progress = 0f64;
        self.current_chapter = None;
        self.current_path = None;
    }

    fn get_split_path(&self, chapter: &gst::TocEntry) -> Rc<Path> {
        let mut split_name = String::new();

        let src_info = self.src_info.as_ref().unwrap().read().unwrap();

        // TODO: make format customisable
        let artist = src_info
            .get_media_artist_sortname()
            .or_else(|| src_info.get_media_artist());
        if let Some(artist) = artist {
            split_name += &format!("{} - ", artist);
        }

        let album_title = src_info
            .get_media_title_sortname()
            .or_else(|| src_info.get_media_title());
        if let Some(album_title) = album_title {
            split_name += &format!("{} - ", album_title);
        }

        if self.toc_visitor.is_some() {
            split_name += &format!("{:02}", self.idx);
        }

        let track_title = chapter
            .get_tags()
            .and_then(|tags| {
                tags.get::<gst::tags::Title>()
                    .and_then(|tag| tag.get().map(ToString::to_string))
            })
            .unwrap_or_else(get_default_chapter_title);
        split_name += &format!(". {}", track_title);

        let lang = self.selected_audio.as_ref().and_then(|stream| {
            stream
                .tags
                .get_index::<gst::tags::LanguageName>(0)
                .or_else(|| stream.tags.get_index::<gst::tags::LanguageCode>(0))
                .and_then(|value| value.get().map(ToString::to_string))
        });
        if let Some(lang) = lang {
            split_name += &format!(" ({})", lang);
        }

        let split_file_info = self.split_file_info.as_ref().expect(concat!(
            "SplitControllerImpl: split_file_info not defined in `get_split_path()`, ",
            "did you call `init()`?"
        ));

        split_name += &format!(".{}", split_file_info.extension);

        split_file_info.path.with_file_name(split_name).into()
    }
}

impl MediaProcessor for SplitControllerImpl {
    fn init(&mut self) -> ProcessingType {
        let format = if self.split_to_flac_row.is_selected() {
            Format::Flac
        } else if self.split_to_wave_row.is_selected() {
            Format::Wave
        } else if self.split_to_opus_row.is_selected() {
            Format::Opus
        } else if self.split_to_vorbis_row.is_selected() {
            Format::Vorbis
        } else if self.split_to_mp3_row.is_selected() {
            Format::MP3
        } else {
            unreachable!("`SplitController`: unknown split type");
        };

        // Split button is not sensible when no audio
        // stream is selected (see `streams_changed`)
        debug_assert!(self.selected_audio.is_some());

        self.toc_visitor = self
            .src_info
            .as_ref()
            .unwrap()
            .read()
            .unwrap()
            .toc
            .as_ref()
            .map(|toc| TocVisitor::new(toc));
        self.idx = 0;

        self.split_file_info = Some({
            let src_info = self.src_info.as_ref().unwrap().read().unwrap();
            OutputMediaFileInfo::new(format, &src_info)
        });

        let (sender, receiver) = async_mpsc::channel(MEDIA_EVENT_CHANNEL_CAPACITY);
        self.media_event_sender = Some(sender);

        ProcessingType::Async(receiver)
    }

    fn next(&mut self) -> Result<ProcessingState, String> {
        let chapter = match self.toc_visitor.as_mut() {
            Some(toc_visitor) => match toc_visitor.next_chapter() {
                Some(chapter) => {
                    self.idx += 1;
                    chapter
                }
                None => {
                    self.split_file_info = None;
                    return Ok(ProcessingState::AllComplete(gettext(
                        "Media split succesfully",
                    )));
                }
            },
            None => {
                // No chapter defined => build a fake chapter corresponding to the whole file
                self.idx += 1;

                let src_info = self.src_info.as_ref().unwrap().read().unwrap();
                let mut toc_entry = gst::TocEntry::new(gst::TocEntryType::Chapter, &"".to_owned());
                toc_entry
                    .get_mut()
                    .unwrap()
                    .set_start_stop_times(0, src_info.duration.as_i64());

                let mut tag_list = gst::TagList::new();
                tag_list.get_mut().unwrap().add::<gst::tags::Title>(
                    &src_info.path.file_stem().unwrap().to_str().unwrap(),
                    gst::TagMergeMode::Replace,
                );
                toc_entry.get_mut().unwrap().set_tags(tag_list);

                toc_entry
            }
        };

        self.current_chapter = Some(
            self.src_info
                .as_ref()
                .unwrap()
                .read()
                .unwrap()
                .get_chapter_with_track_tags(&chapter, self.idx),
        );

        let split_path = self.get_split_path(&chapter);
        self.current_path = Some(Rc::clone(&split_path));

        Ok(ProcessingState::WouldOutputTo(split_path))
    }

    fn process(&mut self, output_path: &Path) -> Result<ProcessingState, String> {
        let res = {
            let src_info = self.src_info.as_ref().unwrap().read().unwrap();
            let split_file_info = self.split_file_info.as_ref().expect(
                "SplitControllerImpl: split_file_info not defined in `next()`, did you call `init()`?"
            );
            SplitterPipeline::try_new(
                &src_info.path,
                output_path,
                &self.selected_audio.as_ref().unwrap().id,
                split_file_info.format,
                self.current_chapter.take().expect(concat!(
                    "SplitControllerImpl: no current_chapter ",
                    "in `process_current_chapter()`",
                )),
                self.media_event_sender
                    .as_ref()
                    .expect(concat!(
                        "SplitControllerImpl: no media_event_sender in `process_current_chapter()` ",
                        "did you call `init()`?",
                    ))
                    .clone(),
            )
        };

        self.splitter_pipeline = Some(res.map_err(|err| {
            self.reset();
            gettext("Failed to prepare for split. {}").replacen("{}", &err, 1)
        })?);

        Ok(ProcessingState::PendingAsyncMediaEvent)
    }

    fn cancel(&mut self) {
        if let Some(pipeline) = self.splitter_pipeline.as_mut() {
            pipeline.cancel();

            if let Some(current_path) = self.current_path.take() {
                if std::fs::remove_file(&current_path).is_err() {
                    if let Some(printable_path) = current_path.to_str() {
                        warn!("Failed to remove canceled split file {}", printable_path);
                    }
                }
            }
        }

        self.reset();
    }

    fn handle_media_event(&mut self, event: MediaEvent) -> Result<ProcessingState, String> {
        match event {
            MediaEvent::Eos => {
                self.current_chapter = None;
                self.current_path = None;
                self.splitter_pipeline = None;
                Ok(ProcessingState::DoneWithCurrent)
            }
            MediaEvent::FailedToExport(err) => {
                self.reset();
                Err(gettext("Failed to split media. {}").replacen("{}", &err, 1))
            }
            other => unimplemented!("SplitController: can't handle media event {:?}", other),
        }
    }

    fn report_progress(&mut self) -> f64 {
        let duration = self.src_info.as_ref().unwrap().read().unwrap().duration;
        if duration > Duration::default() {
            // With some formats, we can't retrieve a proper ts between 2 files
            // some, just report known last progress in this case
            if let Some(ts) = self
                .splitter_pipeline
                .as_ref()
                .and_then(SplitterPipeline::get_current_ts)
            {
                self.last_progress = ts.as_f64() / duration.as_f64()
            }

            self.last_progress
        } else {
            0f64
        }
    }
}
<commit_msg>UI/split: fix progress not being reset... (#146)<commit_after>use futures::channel::mpsc as async_mpsc;

use gettextrs::gettext;
use gstreamer as gst;
use gtk;
use gtk::prelude::*;
use log::warn;

use std::{
    borrow::ToOwned,
    path::Path,
    rc::Rc,
    string::ToString,
    sync::{Arc, RwLock},
};

use media::{MediaEvent, SplitterPipeline};
use metadata::{get_default_chapter_title, Duration, Format, MediaInfo, Stream, TocVisitor};

use super::{PlaybackPipeline, UIController, UIEventSender, UIFocusContext};

use super::output_base_controller::{
    MediaProcessor, OutputBaseController, OutputControllerImpl, OutputMediaFileInfo,
    ProcessingState, ProcessingType, MEDIA_EVENT_CHANNEL_CAPACITY,
};

pub type SplitController = OutputBaseController<SplitControllerImpl>;

impl SplitController {
    pub fn new(builder: &gtk::Builder, ui_event: UIEventSender) -> Self {
        OutputBaseController::<SplitControllerImpl>::new_base(
            SplitControllerImpl::new(builder),
            builder,
            ui_event,
        )
    }
}

macro_rules! update_list_with_format(
    ($self_:expr, $format:expr, $row:ident, $label:ident) => {
        match SplitterPipeline::check_requirements($format) {
            Ok(_) => if !$self_.is_usable {
                $self_.split_list.select_row(Some(&$self_.$row));
                $self_.is_usable = true;
            },
            Err(err) => {
                warn!("{}", err);
                $self_.$label.set_label(&err);
                $self_.$row.set_sensitive(false);
            }
        }
    };
);

pub struct SplitControllerImpl {
    is_usable: bool,

    src_info: Option<Arc<RwLock<MediaInfo>>>,
    selected_audio: Option<Stream>,

    split_file_info: Option<OutputMediaFileInfo>,
    media_event_sender: Option<async_mpsc::Sender<MediaEvent>>,
    splitter_pipeline: Option<SplitterPipeline>,
    toc_visitor: Option<TocVisitor>,
    idx: usize,
    last_progress: f64,
    current_chapter: Option<gst::TocEntry>,
    current_path: Option<Rc<Path>>,

    split_list: gtk::ListBox,
    split_to_flac_row: gtk::ListBoxRow,
    flac_warning_lbl: gtk::Label,
    split_to_wave_row: gtk::ListBoxRow,
    wave_warning_lbl: gtk::Label,
    split_to_opus_row: gtk::ListBoxRow,
    opus_warning_lbl: gtk::Label,
    split_to_vorbis_row: gtk::ListBoxRow,
    vorbis_warning_lbl: gtk::Label,
    split_to_mp3_row: gtk::ListBoxRow,
    mp3_warning_lbl: gtk::Label,

    split_btn: gtk::Button,
}

impl OutputControllerImpl for SplitControllerImpl {
    const FOCUS_CONTEXT: UIFocusContext = UIFocusContext::SplitPage;
    const BTN_NAME: &'static str = "split-btn";
    const LIST_NAME: &'static str = "split-list-box";
    const PROGRESS_BAR_NAME: &'static str = "split-progress";
}

impl UIController for SplitControllerImpl {
    fn new_media(&mut self, pipeline: &PlaybackPipeline) {
        let info_arc = Arc::clone(&pipeline.info);
        self.src_info = Some(info_arc);
    }

    fn cleanup(&mut self) {
        self.src_info = None;
        self.selected_audio = None;

        self.reset();
    }

    fn streams_changed(&mut self, info: &MediaInfo) {
        self.selected_audio = info.streams.selected_audio().map(ToOwned::to_owned);
        if self.is_usable {
            self.split_btn.set_sensitive(self.selected_audio.is_some());
        }
    }
}

impl SplitControllerImpl {
    pub fn new(builder: &gtk::Builder) -> Self {
        let mut ctrl = SplitControllerImpl {
            is_usable: false,

            src_info: None,
            selected_audio: None,

            split_file_info: None,
            media_event_sender: None,
            splitter_pipeline: None,
            toc_visitor: None,
            idx: 0,
            last_progress: 0f64,
            current_chapter: None,
            current_path: None,

            split_list: builder.get_object(Self::LIST_NAME).unwrap(),
            split_to_flac_row: builder.get_object("flac_split-row").unwrap(),
            flac_warning_lbl: builder.get_object("flac_warning-lbl").unwrap(),
            split_to_wave_row: builder.get_object("wave_split-row").unwrap(),
            wave_warning_lbl: builder.get_object("wave_warning-lbl").unwrap(),
            split_to_opus_row: builder.get_object("opus_split-row").unwrap(),
            opus_warning_lbl: builder.get_object("opus_warning-lbl").unwrap(),
            split_to_vorbis_row: builder.get_object("vorbis_split-row").unwrap(),
            vorbis_warning_lbl: builder.get_object("vorbis_warning-lbl").unwrap(),
            split_to_mp3_row: builder.get_object("mp3_split-row").unwrap(),
            mp3_warning_lbl: builder.get_object("mp3_warning-lbl").unwrap(),

            split_btn: builder.get_object(Self::BTN_NAME).unwrap(),
        };

        update_list_with_format!(ctrl, Format::Flac, split_to_flac_row, flac_warning_lbl);
        update_list_with_format!(ctrl, Format::Wave, split_to_wave_row, wave_warning_lbl);
        update_list_with_format!(ctrl, Format::Opus, split_to_opus_row, opus_warning_lbl);
        update_list_with_format!(
            ctrl,
            Format::Vorbis,
            split_to_vorbis_row,
            vorbis_warning_lbl
        );
        update_list_with_format!(ctrl, Format::MP3, split_to_mp3_row, mp3_warning_lbl);

        ctrl.split_list.set_sensitive(ctrl.is_usable);
        ctrl.split_btn.set_sensitive(ctrl.is_usable);

        ctrl
    }

    fn reset(&mut self) {
        self.split_file_info = None;
        self.media_event_sender = None;
        self.splitter_pipeline = None;
        self.toc_visitor = None;
        self.idx = 0;
        self.last_progress = 0f64;
        self.current_chapter = None;
        self.current_path = None;
    }

    fn get_split_path(&self, chapter: &gst::TocEntry) -> Rc<Path> {
        let mut split_name = String::new();

        let src_info = self.src_info.as_ref().unwrap().read().unwrap();

        // TODO: make format customisable
        let artist = src_info
            .get_media_artist_sortname()
            .or_else(|| src_info.get_media_artist());
        if let Some(artist) = artist {
            split_name += &format!("{} - ", artist);
        }

        let album_title = src_info
            .get_media_title_sortname()
            .or_else(|| src_info.get_media_title());
        if let Some(album_title) = album_title {
            split_name += &format!("{} - ", album_title);
        }

        if self.toc_visitor.is_some() {
            split_name += &format!("{:02}", self.idx);
        }

        let track_title = chapter
            .get_tags()
            .and_then(|tags| {
                tags.get::<gst::tags::Title>()
                    .and_then(|tag| tag.get().map(ToString::to_string))
            })
            .unwrap_or_else(get_default_chapter_title);
        split_name += &format!(". {}", track_title);

        let lang = self.selected_audio.as_ref().and_then(|stream| {
            stream
                .tags
                .get_index::<gst::tags::LanguageName>(0)
                .or_else(|| stream.tags.get_index::<gst::tags::LanguageCode>(0))
                .and_then(|value| value.get().map(ToString::to_string))
        });
        if let Some(lang) = lang {
            split_name += &format!(" ({})", lang);
        }

        let split_file_info = self.split_file_info.as_ref().expect(concat!(
            "SplitControllerImpl: split_file_info not defined in `get_split_path()`, ",
            "did you call `init()`?"
        ));

        split_name += &format!(".{}", split_file_info.extension);

        split_file_info.path.with_file_name(split_name).into()
    }
}

impl MediaProcessor for SplitControllerImpl {
    fn init(&mut self) -> ProcessingType {
        self.reset();

        let format = if self.split_to_flac_row.is_selected() {
            Format::Flac
        } else if self.split_to_wave_row.is_selected() {
            Format::Wave
        } else if self.split_to_opus_row.is_selected() {
            Format::Opus
        } else if self.split_to_vorbis_row.is_selected() {
            Format::Vorbis
        } else if self.split_to_mp3_row.is_selected() {
            Format::MP3
        } else {
            unreachable!("`SplitController`: unknown split type");
        };

        // Split button is not sensible when no audio
        // stream is selected (see `streams_changed`)
        debug_assert!(self.selected_audio.is_some());

        self.toc_visitor = self
            .src_info
            .as_ref()
            .unwrap()
            .read()
            .unwrap()
            .toc
            .as_ref()
            .map(|toc| TocVisitor::new(toc));
        self.idx = 0;

        self.split_file_info = Some({
            let src_info = self.src_info.as_ref().unwrap().read().unwrap();
            OutputMediaFileInfo::new(format, &src_info)
        });

        let (sender, receiver) = async_mpsc::channel(MEDIA_EVENT_CHANNEL_CAPACITY);
        self.media_event_sender = Some(sender);

        ProcessingType::Async(receiver)
    }

    fn next(&mut self) -> Result<ProcessingState, String> {
        let chapter = match self.toc_visitor.as_mut() {
            Some(toc_visitor) => match toc_visitor.next_chapter() {
                Some(chapter) => {
                    self.idx += 1;
                    chapter
                }
                None => {
                    self.split_file_info = None;
                    return Ok(ProcessingState::AllComplete(gettext(
                        "Media split succesfully",
                    )));
                }
            },
            None => {
                // No chapter defined => build a fake chapter corresponding to the whole file
                self.idx += 1;

                let src_info = self.src_info.as_ref().unwrap().read().unwrap();
                let mut toc_entry = gst::TocEntry::new(gst::TocEntryType::Chapter, &"".to_owned());
                toc_entry
                    .get_mut()
                    .unwrap()
                    .set_start_stop_times(0, src_info.duration.as_i64());

                let mut tag_list = gst::TagList::new();
                tag_list.get_mut().unwrap().add::<gst::tags::Title>(
                    &src_info.path.file_stem().unwrap().to_str().unwrap(),
                    gst::TagMergeMode::Replace,
                );
                toc_entry.get_mut().unwrap().set_tags(tag_list);

                toc_entry
            }
        };

        self.current_chapter = Some(
            self.src_info
                .as_ref()
                .unwrap()
                .read()
                .unwrap()
                .get_chapter_with_track_tags(&chapter, self.idx),
        );

        let split_path = self.get_split_path(&chapter);
        self.current_path = Some(Rc::clone(&split_path));

        Ok(ProcessingState::WouldOutputTo(split_path))
    }

    fn process(&mut self, output_path: &Path) -> Result<ProcessingState, String> {
        let res = {
            let src_info = self.src_info.as_ref().unwrap().read().unwrap();
            let split_file_info = self.split_file_info.as_ref().expect(
                "SplitControllerImpl: split_file_info not defined in `next()`, did you call `init()`?"
            );
            SplitterPipeline::try_new(
                &src_info.path,
                output_path,
                &self.selected_audio.as_ref().unwrap().id,
                split_file_info.format,
                self.current_chapter.take().expect(concat!(
                    "SplitControllerImpl: no current_chapter ",
                    "in `process_current_chapter()`",
                )),
                self.media_event_sender
                    .as_ref()
                    .expect(concat!(
                        "SplitControllerImpl: no media_event_sender in `process_current_chapter()` ",
                        "did you call `init()`?",
                    ))
                    .clone(),
            )
        };

        self.splitter_pipeline = Some(res.map_err(|err| {
            self.reset();
            gettext("Failed to prepare for split. {}").replacen("{}", &err, 1)
        })?);

        Ok(ProcessingState::PendingAsyncMediaEvent)
    }

    fn cancel(&mut self) {
        if let Some(pipeline) = self.splitter_pipeline.as_mut() {
            pipeline.cancel();

            if let Some(current_path) = self.current_path.take() {
                if std::fs::remove_file(&current_path).is_err() {
                    if let Some(printable_path) = current_path.to_str() {
                        warn!("Failed to remove canceled split file {}", printable_path);
                    }
                }
            }
        }

        self.reset();
    }

    fn handle_media_event(&mut self, event: MediaEvent) -> Result<ProcessingState, String> {
        match event {
            MediaEvent::Eos => {
                self.current_chapter = None;
                self.current_path = None;
                self.splitter_pipeline = None;
                Ok(ProcessingState::DoneWithCurrent)
            }
            MediaEvent::FailedToExport(err) => {
                self.reset();
                Err(gettext("Failed to split media. {}").replacen("{}", &err, 1))
            }
            other => unimplemented!("SplitController: can't handle media event {:?}", other),
        }
    }

    fn report_progress(&mut self) -> f64 {
        let duration = self.src_info.as_ref().unwrap().read().unwrap().duration;
        if duration > Duration::default() {
            // With some formats, we can't retrieve a proper ts between 2 files
            // so, just report known last progress in this case
            if let Some(ts) = self
                .splitter_pipeline
                .as_ref()
                .and_then(SplitterPipeline::get_current_ts)
            {
                self.last_progress = ts.as_f64() / duration.as_f64()
            }

            self.last_progress
        } else {
            0f64
        }
    }
}
<|endoftext|>


<commit_before>// This file is released under the same terms as Rust itself.

use hex::FromHex;
use hyper::server::Request;
use std::io::Read;
use util::crypto::{SHA1_LEN, verify_sha1_hmac};

pub fn parse(req: &mut Request, secret: &[u8]) -> Option<(Vec<u8>, Vec<u8>)> {
    let x_github_event = {
        if let Some(xges) = req.headers.get_raw("X-Github-Event") {
            if let Some(xge) = xges.get(0) {
                xge.clone()
            } else {
                vec![]
            }
        } else {
            vec![]
        }
    };
    let body = {
        let mut body = Vec::new();
        let result = req.read_to_end(&mut body);
        if let Err(e) = result {
            warn!("Failed to read body: {:?}", e);
            return None;
        } else {
            body
        }
    };
    let x_hub_signature = {
        if let Some(xges) = req.headers.get_raw("X-Hub-Signature") {
            if let Some(xge) = xges.get(0) {
                xge.clone()
            } else {
                vec![]
            }
        } else {
            vec![]
        }
    };
    let signature = &x_hub_signature[5..]; // sha1=
    if signature.len() != SHA1_LEN {
        warn!("Got wrong length X-Hub-Signature");
        return None;
    }
    let signature = Vec::from_hex(&signature);
    let signature = if let Ok(signature) = signature {
        signature
    } else {
        warn!("Got invalid hex in X-Hub-Signature");
        return None;
    };
    if !verify_sha1_hmac(secret, &body, &signature) {
        warn!("Got incorrect signature");
        return None;
    }
    Some((x_github_event, body))
}
<commit_msg>Do not crash on short hub signatures<commit_after>// This file is released under the same terms as Rust itself.

use hex::FromHex;
use hyper::header::Headers;
use hyper::server::Request;
use std::io::Read;
use util::crypto::{SHA1_LEN, verify_sha1_hmac};

pub fn parse(req: &mut Request, secret: &[u8]) -> Option<(Vec<u8>, Vec<u8>)> {
    let x_github_event = {
        if let Some(xges) = req.headers.get_raw("X-Github-Event") {
            if let Some(xge) = xges.get(0) {
                xge.clone()
            } else {
                vec![]
            }
        } else {
            vec![]
        }
    };
    let body = {
        let mut body = Vec::new();
        let result = req.read_to_end(&mut body);
        if let Err(e) = result {
            warn!("Failed to read body: {:?}", e);
            return None;
        } else {
            body
        }
    };
    let signature = parse_signature(&req.headers);
    let signature = if let Some(signature) = signature {
        signature
    } else {
        return None;
    };
    if !verify_sha1_hmac(secret, &body, &signature) {
        warn!("Got incorrect signature");
        return None;
    }
    Some((x_github_event, body))
}

fn parse_signature(headers: &Headers) -> Option<Vec<u8>> {
    let x_hub_signature = {
        if let Some(xges) = headers.get_raw("X-Hub-Signature") {
            if let Some(xge) = xges.get(0) {
                xge.clone()
            } else {
                vec![]
            }
        } else {
            vec![]
        }
    };
    if x_hub_signature.len() != SHA1_LEN+5 {
        warn!("Got wrong length X-Hub-Signature");
        return None;
    }
    let signature = &x_hub_signature[5..]; // sha1=
    let signature = Vec::from_hex(&signature);
    let signature = if let Ok(signature) = signature {
        signature
    } else {
        warn!("Got invalid hex in X-Hub-Signature");
        return None;
    };
    Some(signature)
}

#[cfg(test)]
mod test {
    use hyper::header::Headers;
    use super::parse_signature;
    #[test]
    fn test_empty_signature() {
        let mut headers = Headers::new();
        headers.set_raw("X-Hub-Signature", vec![ vec![ ] ]);
        assert!(parse_signature(&headers).is_none());
        let mut headers = Headers::new();
        headers.set_raw("X-Hub-Signature", vec![ vec![ b' ' ] ]);
        assert!(parse_signature(&headers).is_none());
    }
}<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 kwantam <kwantam@gmail.com>
// * (c) 2020 nicoo   <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

// spell-checker: ignore (ToDO) INVS

use crate::Factors;

include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));

pub fn factor(num: &mut u64, factors: &mut Factors) {
    for &(prime, inv, ceil) in P_INVS_U64 {
        if *num == 1 {
            break;
        }

        // inv = prime^-1 mod 2^64
        // ceil = floor((2^64-1) / prime)
        // if (num * inv) mod 2^64 <= ceil, then prime divides num
        // See https://math.stackexchange.com/questions/1251327/
        // for a nice explanation.
        let mut k = 0;
        loop {
            let x = num.wrapping_mul(inv);

            // While prime divides num
            if x <= ceil {
                *num = x;
                k += 1;
                #[cfg(feature = "coz")]
                coz::progress!("factor found");
            } else {
                if k > 0 {
                    factors.add(prime, k);
                }
                break;
            }
        }
    }
}

pub const CHUNK_SIZE: usize = 4;
pub fn factor_chunk(n_s: &mut [u64; CHUNK_SIZE], f_s: &mut [Factors; CHUNK_SIZE]) {
    for (n, s) in n_s.iter_mut().zip(f_s.iter_mut()) {
        factor(n, s);
    }
}
<commit_msg>factor::table::factor_chunk: Turn loop inside-out<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 kwantam <kwantam@gmail.com>
// * (c) 2020 nicoo   <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

// spell-checker: ignore (ToDO) INVS

use crate::Factors;

include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));

pub fn factor(num: &mut u64, factors: &mut Factors) {
    for &(prime, inv, ceil) in P_INVS_U64 {
        if *num == 1 {
            break;
        }

        // inv = prime^-1 mod 2^64
        // ceil = floor((2^64-1) / prime)
        // if (num * inv) mod 2^64 <= ceil, then prime divides num
        // See https://math.stackexchange.com/questions/1251327/
        // for a nice explanation.
        let mut k = 0;
        loop {
            let x = num.wrapping_mul(inv);

            // While prime divides num
            if x <= ceil {
                *num = x;
                k += 1;
                #[cfg(feature = "coz")]
                coz::progress!("factor found");
            } else {
                if k > 0 {
                    factors.add(prime, k);
                }
                break;
            }
        }
    }
}

pub const CHUNK_SIZE: usize = 4;
pub fn factor_chunk(n_s: &mut [u64; CHUNK_SIZE], f_s: &mut [Factors; CHUNK_SIZE]) {
    for &(prime, inv, ceil) in P_INVS_U64 {
        if n_s[0] == 1 && n_s[1] == 1 && n_s[2] == 1 && n_s[3] == 1 {
            break;
        }

        for (num, factors) in n_s.iter_mut().zip(f_s.iter_mut()) {
            if *num == 1 {
                continue;
            }
            let mut k = 0;
            loop {
                let x = num.wrapping_mul(inv);

                // While prime divides num
                if x <= ceil {
                    *num = x;
                    k += 1;
                } else {
                    if k > 0 {
                        factors.add(prime, k);
                    }
                    break;
                }
            }
        }
    }
}
<|endoftext|>


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

use driver::session;
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
use lib::llvm::{llvm, TargetData, TypeNames};
use lib::llvm::mk_target_data;
use metadata::common::LinkMeta;
use middle::astencode;
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::common::{C_i32, C_null};
use middle::ty;

use middle::trans::type_::Type;

use util::sha2::Sha256;

use std::cell::RefCell;
use std::c_str::ToCStr;
use std::hashmap::{HashMap, HashSet};
use std::local_data;
use std::libc::c_uint;
use syntax::ast;

use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};

use middle::trans::base::{decl_crate_map};

pub struct CrateContext {
     sess: session::Session,
     llmod: ModuleRef,
     llcx: ContextRef,
     metadata_llmod: ModuleRef,
     td: TargetData,
     tn: TypeNames,
     externs: ExternMap,
     intrinsics: HashMap<&'static str, ValueRef>,
     item_vals: RefCell<HashMap<ast::NodeId, ValueRef>>,
     exp_map2: resolve::ExportMap2,
     reachable: @mut HashSet<ast::NodeId>,
     item_symbols: RefCell<HashMap<ast::NodeId, ~str>>,
     link_meta: LinkMeta,
     enum_sizes: HashMap<ty::t, uint>,
     discrims: HashMap<ast::DefId, ValueRef>,
     discrim_symbols: HashMap<ast::NodeId, @str>,
     tydescs: HashMap<ty::t, @mut tydesc_info>,
     // Set when running emit_tydescs to enforce that no more tydescs are
     // created.
     finished_tydescs: bool,
     // Track mapping of external ids to local items imported for inlining
     external: HashMap<ast::DefId, Option<ast::NodeId>>,
     // Backwards version of the `external` map (inlined items to where they
     // came from)
     external_srcs: HashMap<ast::NodeId, ast::DefId>,
     // A set of static items which cannot be inlined into other crates. This
     // will pevent in ii_item() structures from being encoded into the metadata
     // that is generated
     non_inlineable_statics: HashSet<ast::NodeId>,
     // Cache instances of monomorphized functions
     monomorphized: RefCell<HashMap<mono_id, ValueRef>>,
     monomorphizing: RefCell<HashMap<ast::DefId, uint>>,
     // Cache generated vtables
     vtables: HashMap<(ty::t, mono_id), ValueRef>,
     // Cache of constant strings,
     const_cstr_cache: HashMap<@str, ValueRef>,

     // Reverse-direction for const ptrs cast from globals.
     // Key is an int, cast from a ValueRef holding a *T,
     // Val is a ValueRef holding a *[T].
     //
     // Needed because LLVM loses pointer->pointee association
     // when we ptrcast, and we have to ptrcast during translation
     // of a [T] const because we form a slice, a [*T,int] pair, not
     // a pointer to an LLVM array type.
     const_globals: HashMap<int, ValueRef>,

     // Cache of emitted const values
     const_values: HashMap<ast::NodeId, ValueRef>,

     // Cache of external const values
     extern_const_values: HashMap<ast::DefId, ValueRef>,

     impl_method_cache: HashMap<(ast::DefId, ast::Name), ast::DefId>,

     module_data: HashMap<~str, ValueRef>,
     lltypes: HashMap<ty::t, Type>,
     llsizingtypes: HashMap<ty::t, Type>,
     adt_reprs: HashMap<ty::t, @adt::Repr>,
     symbol_hasher: Sha256,
     type_hashcodes: HashMap<ty::t, @str>,
     type_short_names: HashMap<ty::t, ~str>,
     all_llvm_symbols: HashSet<@str>,
     tcx: ty::ctxt,
     maps: astencode::Maps,
     stats: @mut Stats,
     tydesc_type: Type,
     int_type: Type,
     opaque_vec_type: Type,
     builder: BuilderRef_res,
     crate_map: ValueRef,
     crate_map_name: ~str,
     // Set when at least one function uses GC. Needed so that
     // decl_gc_metadata knows whether to link to the module metadata, which
     // is not emitted by LLVM's GC pass when no functions use GC.
     uses_gc: bool,
     dbg_cx: Option<debuginfo::CrateDebugContext>,
     do_not_commit_warning_issued: bool
}

impl CrateContext {
    pub fn new(sess: session::Session,
               name: &str,
               tcx: ty::ctxt,
               emap2: resolve::ExportMap2,
               maps: astencode::Maps,
               symbol_hasher: Sha256,
               link_meta: LinkMeta,
               reachable: @mut HashSet<ast::NodeId>)
               -> CrateContext {
        unsafe {
            let llcx = llvm::LLVMContextCreate();
            set_task_llcx(llcx);
            let llmod = name.with_c_str(|buf| {
                llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
            });
            let metadata_llmod = format!("{}_metadata", name).with_c_str(|buf| {
                llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
            });
            let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
            let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
            data_layout.with_c_str(|buf| {
                llvm::LLVMSetDataLayout(llmod, buf);
                llvm::LLVMSetDataLayout(metadata_llmod, buf);
            });
            targ_triple.with_c_str(|buf| {
                llvm::LLVMRustSetNormalizedTarget(llmod, buf);
                llvm::LLVMRustSetNormalizedTarget(metadata_llmod, buf);
            });
            let targ_cfg = sess.targ_cfg;

            let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
            let mut tn = TypeNames::new();

            let mut intrinsics = base::declare_intrinsics(llmod);
            if sess.opts.extra_debuginfo {
                base::declare_dbg_intrinsics(llmod, &mut intrinsics);
            }
            let int_type = Type::int(targ_cfg.arch);
            let tydesc_type = Type::tydesc(targ_cfg.arch);
            let opaque_vec_type = Type::opaque_vec(targ_cfg.arch);

            let mut str_slice_ty = Type::named_struct("str_slice");
            str_slice_ty.set_struct_body([Type::i8p(), int_type], false);

            tn.associate_type("tydesc", &tydesc_type);
            tn.associate_type("str_slice", &str_slice_ty);

            let (crate_map_name, crate_map) = decl_crate_map(sess, link_meta.clone(), llmod);
            let dbg_cx = if sess.opts.debuginfo {
                Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned()))
            } else {
                None
            };

            if sess.count_llvm_insns() {
                base::init_insn_ctxt()
            }

            CrateContext {
                  sess: sess,
                  llmod: llmod,
                  llcx: llcx,
                  metadata_llmod: metadata_llmod,
                  td: td,
                  tn: tn,
                  externs: HashMap::new(),
                  intrinsics: intrinsics,
                  item_vals: RefCell::new(HashMap::new()),
                  exp_map2: emap2,
                  reachable: reachable,
                  item_symbols: RefCell::new(HashMap::new()),
                  link_meta: link_meta,
                  enum_sizes: HashMap::new(),
                  discrims: HashMap::new(),
                  discrim_symbols: HashMap::new(),
                  tydescs: HashMap::new(),
                  finished_tydescs: false,
                  external: HashMap::new(),
                  external_srcs: HashMap::new(),
                  non_inlineable_statics: HashSet::new(),
                  monomorphized: RefCell::new(HashMap::new()),
                  monomorphizing: RefCell::new(HashMap::new()),
                  vtables: HashMap::new(),
                  const_cstr_cache: HashMap::new(),
                  const_globals: HashMap::new(),
                  const_values: HashMap::new(),
                  extern_const_values: HashMap::new(),
                  impl_method_cache: HashMap::new(),
                  module_data: HashMap::new(),
                  lltypes: HashMap::new(),
                  llsizingtypes: HashMap::new(),
                  adt_reprs: HashMap::new(),
                  symbol_hasher: symbol_hasher,
                  type_hashcodes: HashMap::new(),
                  type_short_names: HashMap::new(),
                  all_llvm_symbols: HashSet::new(),
                  tcx: tcx,
                  maps: maps,
                  stats: @mut Stats {
                    n_static_tydescs: 0u,
                    n_glues_created: 0u,
                    n_null_glues: 0u,
                    n_real_glues: 0u,
                    n_fns: 0u,
                    n_monos: 0u,
                    n_inlines: 0u,
                    n_closures: 0u,
                    n_llvm_insns: 0u,
                    llvm_insn_ctxt: ~[],
                    llvm_insns: HashMap::new(),
                    fn_stats: ~[]
                  },
                  tydesc_type: tydesc_type,
                  int_type: int_type,
                  opaque_vec_type: opaque_vec_type,
                  builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
                  crate_map: crate_map,
                  crate_map_name: crate_map_name,
                  uses_gc: false,
                  dbg_cx: dbg_cx,
                  do_not_commit_warning_issued: false
            }
        }
    }

    pub fn builder(@mut self) -> Builder {
        Builder::new(self)
    }

    pub fn const_inbounds_gepi(&self,
                               pointer: ValueRef,
                               indices: &[uint]) -> ValueRef {
        debug!("const_inbounds_gepi: pointer={} indices={:?}",
               self.tn.val_to_str(pointer), indices);
        let v: ~[ValueRef] =
            indices.iter().map(|i| C_i32(*i as i32)).collect();
        unsafe {
            llvm::LLVMConstInBoundsGEP(pointer,
                                       v.as_ptr(),
                                       indices.len() as c_uint)
        }
    }

    pub fn offsetof_gep(&self,
                        llptr_ty: Type,
                        indices: &[uint]) -> ValueRef {
        /*!
         * Returns the offset of applying the given GEP indices
         * to an instance of `llptr_ty`. Similar to `offsetof` in C,
         * except that `llptr_ty` must be a pointer type.
         */

        unsafe {
            let null = C_null(llptr_ty);
            llvm::LLVMConstPtrToInt(self.const_inbounds_gepi(null, indices),
                                    self.int_type.to_ref())
        }
    }
}

#[unsafe_destructor]
impl Drop for CrateContext {
    fn drop(&mut self) {
        unset_task_llcx();
    }
}

local_data_key!(task_local_llcx_key: @ContextRef)

pub fn task_llcx() -> ContextRef {
    let opt = local_data::get(task_local_llcx_key, |k| k.map(|k| *k));
    *opt.expect("task-local LLVMContextRef wasn't ever set!")
}

fn set_task_llcx(c: ContextRef) {
    local_data::set(task_local_llcx_key, @c);
}

fn unset_task_llcx() {
    local_data::pop(task_local_llcx_key);
}
<commit_msg>librustc: Remove unused field `enum_sizes` from the crate context<commit_after>// Copyright 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.

use driver::session;
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
use lib::llvm::{llvm, TargetData, TypeNames};
use lib::llvm::mk_target_data;
use metadata::common::LinkMeta;
use middle::astencode;
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::common::{C_i32, C_null};
use middle::ty;

use middle::trans::type_::Type;

use util::sha2::Sha256;

use std::cell::RefCell;
use std::c_str::ToCStr;
use std::hashmap::{HashMap, HashSet};
use std::local_data;
use std::libc::c_uint;
use syntax::ast;

use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};

use middle::trans::base::{decl_crate_map};

pub struct CrateContext {
     sess: session::Session,
     llmod: ModuleRef,
     llcx: ContextRef,
     metadata_llmod: ModuleRef,
     td: TargetData,
     tn: TypeNames,
     externs: ExternMap,
     intrinsics: HashMap<&'static str, ValueRef>,
     item_vals: RefCell<HashMap<ast::NodeId, ValueRef>>,
     exp_map2: resolve::ExportMap2,
     reachable: @mut HashSet<ast::NodeId>,
     item_symbols: RefCell<HashMap<ast::NodeId, ~str>>,
     link_meta: LinkMeta,
     discrims: HashMap<ast::DefId, ValueRef>,
     discrim_symbols: HashMap<ast::NodeId, @str>,
     tydescs: HashMap<ty::t, @mut tydesc_info>,
     // Set when running emit_tydescs to enforce that no more tydescs are
     // created.
     finished_tydescs: bool,
     // Track mapping of external ids to local items imported for inlining
     external: HashMap<ast::DefId, Option<ast::NodeId>>,
     // Backwards version of the `external` map (inlined items to where they
     // came from)
     external_srcs: HashMap<ast::NodeId, ast::DefId>,
     // A set of static items which cannot be inlined into other crates. This
     // will pevent in ii_item() structures from being encoded into the metadata
     // that is generated
     non_inlineable_statics: HashSet<ast::NodeId>,
     // Cache instances of monomorphized functions
     monomorphized: RefCell<HashMap<mono_id, ValueRef>>,
     monomorphizing: RefCell<HashMap<ast::DefId, uint>>,
     // Cache generated vtables
     vtables: HashMap<(ty::t, mono_id), ValueRef>,
     // Cache of constant strings,
     const_cstr_cache: HashMap<@str, ValueRef>,

     // Reverse-direction for const ptrs cast from globals.
     // Key is an int, cast from a ValueRef holding a *T,
     // Val is a ValueRef holding a *[T].
     //
     // Needed because LLVM loses pointer->pointee association
     // when we ptrcast, and we have to ptrcast during translation
     // of a [T] const because we form a slice, a [*T,int] pair, not
     // a pointer to an LLVM array type.
     const_globals: HashMap<int, ValueRef>,

     // Cache of emitted const values
     const_values: HashMap<ast::NodeId, ValueRef>,

     // Cache of external const values
     extern_const_values: HashMap<ast::DefId, ValueRef>,

     impl_method_cache: HashMap<(ast::DefId, ast::Name), ast::DefId>,

     module_data: HashMap<~str, ValueRef>,
     lltypes: HashMap<ty::t, Type>,
     llsizingtypes: HashMap<ty::t, Type>,
     adt_reprs: HashMap<ty::t, @adt::Repr>,
     symbol_hasher: Sha256,
     type_hashcodes: HashMap<ty::t, @str>,
     type_short_names: HashMap<ty::t, ~str>,
     all_llvm_symbols: HashSet<@str>,
     tcx: ty::ctxt,
     maps: astencode::Maps,
     stats: @mut Stats,
     tydesc_type: Type,
     int_type: Type,
     opaque_vec_type: Type,
     builder: BuilderRef_res,
     crate_map: ValueRef,
     crate_map_name: ~str,
     // Set when at least one function uses GC. Needed so that
     // decl_gc_metadata knows whether to link to the module metadata, which
     // is not emitted by LLVM's GC pass when no functions use GC.
     uses_gc: bool,
     dbg_cx: Option<debuginfo::CrateDebugContext>,
     do_not_commit_warning_issued: bool
}

impl CrateContext {
    pub fn new(sess: session::Session,
               name: &str,
               tcx: ty::ctxt,
               emap2: resolve::ExportMap2,
               maps: astencode::Maps,
               symbol_hasher: Sha256,
               link_meta: LinkMeta,
               reachable: @mut HashSet<ast::NodeId>)
               -> CrateContext {
        unsafe {
            let llcx = llvm::LLVMContextCreate();
            set_task_llcx(llcx);
            let llmod = name.with_c_str(|buf| {
                llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
            });
            let metadata_llmod = format!("{}_metadata", name).with_c_str(|buf| {
                llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
            });
            let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
            let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
            data_layout.with_c_str(|buf| {
                llvm::LLVMSetDataLayout(llmod, buf);
                llvm::LLVMSetDataLayout(metadata_llmod, buf);
            });
            targ_triple.with_c_str(|buf| {
                llvm::LLVMRustSetNormalizedTarget(llmod, buf);
                llvm::LLVMRustSetNormalizedTarget(metadata_llmod, buf);
            });
            let targ_cfg = sess.targ_cfg;

            let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
            let mut tn = TypeNames::new();

            let mut intrinsics = base::declare_intrinsics(llmod);
            if sess.opts.extra_debuginfo {
                base::declare_dbg_intrinsics(llmod, &mut intrinsics);
            }
            let int_type = Type::int(targ_cfg.arch);
            let tydesc_type = Type::tydesc(targ_cfg.arch);
            let opaque_vec_type = Type::opaque_vec(targ_cfg.arch);

            let mut str_slice_ty = Type::named_struct("str_slice");
            str_slice_ty.set_struct_body([Type::i8p(), int_type], false);

            tn.associate_type("tydesc", &tydesc_type);
            tn.associate_type("str_slice", &str_slice_ty);

            let (crate_map_name, crate_map) = decl_crate_map(sess, link_meta.clone(), llmod);
            let dbg_cx = if sess.opts.debuginfo {
                Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned()))
            } else {
                None
            };

            if sess.count_llvm_insns() {
                base::init_insn_ctxt()
            }

            CrateContext {
                  sess: sess,
                  llmod: llmod,
                  llcx: llcx,
                  metadata_llmod: metadata_llmod,
                  td: td,
                  tn: tn,
                  externs: HashMap::new(),
                  intrinsics: intrinsics,
                  item_vals: RefCell::new(HashMap::new()),
                  exp_map2: emap2,
                  reachable: reachable,
                  item_symbols: RefCell::new(HashMap::new()),
                  link_meta: link_meta,
                  discrims: HashMap::new(),
                  discrim_symbols: HashMap::new(),
                  tydescs: HashMap::new(),
                  finished_tydescs: false,
                  external: HashMap::new(),
                  external_srcs: HashMap::new(),
                  non_inlineable_statics: HashSet::new(),
                  monomorphized: RefCell::new(HashMap::new()),
                  monomorphizing: RefCell::new(HashMap::new()),
                  vtables: HashMap::new(),
                  const_cstr_cache: HashMap::new(),
                  const_globals: HashMap::new(),
                  const_values: HashMap::new(),
                  extern_const_values: HashMap::new(),
                  impl_method_cache: HashMap::new(),
                  module_data: HashMap::new(),
                  lltypes: HashMap::new(),
                  llsizingtypes: HashMap::new(),
                  adt_reprs: HashMap::new(),
                  symbol_hasher: symbol_hasher,
                  type_hashcodes: HashMap::new(),
                  type_short_names: HashMap::new(),
                  all_llvm_symbols: HashSet::new(),
                  tcx: tcx,
                  maps: maps,
                  stats: @mut Stats {
                    n_static_tydescs: 0u,
                    n_glues_created: 0u,
                    n_null_glues: 0u,
                    n_real_glues: 0u,
                    n_fns: 0u,
                    n_monos: 0u,
                    n_inlines: 0u,
                    n_closures: 0u,
                    n_llvm_insns: 0u,
                    llvm_insn_ctxt: ~[],
                    llvm_insns: HashMap::new(),
                    fn_stats: ~[]
                  },
                  tydesc_type: tydesc_type,
                  int_type: int_type,
                  opaque_vec_type: opaque_vec_type,
                  builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
                  crate_map: crate_map,
                  crate_map_name: crate_map_name,
                  uses_gc: false,
                  dbg_cx: dbg_cx,
                  do_not_commit_warning_issued: false
            }
        }
    }

    pub fn builder(@mut self) -> Builder {
        Builder::new(self)
    }

    pub fn const_inbounds_gepi(&self,
                               pointer: ValueRef,
                               indices: &[uint]) -> ValueRef {
        debug!("const_inbounds_gepi: pointer={} indices={:?}",
               self.tn.val_to_str(pointer), indices);
        let v: ~[ValueRef] =
            indices.iter().map(|i| C_i32(*i as i32)).collect();
        unsafe {
            llvm::LLVMConstInBoundsGEP(pointer,
                                       v.as_ptr(),
                                       indices.len() as c_uint)
        }
    }

    pub fn offsetof_gep(&self,
                        llptr_ty: Type,
                        indices: &[uint]) -> ValueRef {
        /*!
         * Returns the offset of applying the given GEP indices
         * to an instance of `llptr_ty`. Similar to `offsetof` in C,
         * except that `llptr_ty` must be a pointer type.
         */

        unsafe {
            let null = C_null(llptr_ty);
            llvm::LLVMConstPtrToInt(self.const_inbounds_gepi(null, indices),
                                    self.int_type.to_ref())
        }
    }
}

#[unsafe_destructor]
impl Drop for CrateContext {
    fn drop(&mut self) {
        unset_task_llcx();
    }
}

local_data_key!(task_local_llcx_key: @ContextRef)

pub fn task_llcx() -> ContextRef {
    let opt = local_data::get(task_local_llcx_key, |k| k.map(|k| *k));
    *opt.expect("task-local LLVMContextRef wasn't ever set!")
}

fn set_task_llcx(c: ContextRef) {
    local_data::set(task_local_llcx_key, @c);
}

fn unset_task_llcx() {
    local_data::pop(task_local_llcx_key);
}
<|endoftext|>


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

//! Implementations of serialization for structures found in libcollections

use std::uint;
use std::default::Default;
use std::hash::{Hash, Hasher};

use {Decodable, Encodable, Decoder, Encoder};
use std::collections::{DList, RingBuf, TreeMap, TreeSet, Deque, HashMap, HashSet,
                       TrieMap, TrieSet};
use std::collections::enum_set::{EnumSet, CLike};

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for DList<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
    fn decode(d: &mut D) -> Result<DList<T>, E> {
        d.read_seq(|d, len| {
            let mut list = DList::new();
            for i in range(0u, len) {
                list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(list)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for RingBuf<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
    fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
        d.read_seq(|d, len| {
            let mut deque: RingBuf<T> = RingBuf::new();
            for i in range(0u, len) {
                deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(deque)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + PartialEq + Ord,
    V: Encodable<S, E> + PartialEq
> Encodable<S, E> for TreeMap<K, V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + PartialEq + Ord,
    V: Decodable<D, E> + PartialEq
> Decodable<D, E> for TreeMap<K, V> {
    fn decode(d: &mut D) -> Result<TreeMap<K, V>, E> {
        d.read_map(|d, len| {
            let mut map = TreeMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + PartialEq + Ord
> Encodable<S, E> for TreeSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + PartialEq + Ord
> Decodable<D, E> for TreeSet<T> {
    fn decode(d: &mut D) -> Result<TreeSet<T>, E> {
        d.read_seq(|d, len| {
            let mut set = TreeSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + CLike
> Encodable<S, E> for EnumSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let mut bits = 0;
        for item in self.iter() {
            bits |= item.to_uint();
        }
        s.emit_uint(bits)
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + CLike
> Decodable<D, E> for EnumSet<T> {
    fn decode(d: &mut D) -> Result<EnumSet<T>, E> {
        let bits = try!(d.read_uint());
        let mut set = EnumSet::empty();
        for bit in range(0, uint::BITS) {
            if bits & (1 << bit) != 0 {
                set.add(CLike::from_uint(1 << bit));
            }
        }
        Ok(set)
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + Hash<X> + Eq,
    V: Encodable<S, E>,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashMap<K, V, H> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + Hash<S> + Eq,
    V: Decodable<D, E>,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashMap<K, V, H> {
    fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
        d.read_map(|d, len| {
            let hasher = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, hasher);
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + Hash<X> + Eq,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashSet<T, H> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + Hash<S> + Eq,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashSet<T, H> {
    fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
        d.read_seq(|d, len| {
            let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    V: Encodable<S, E>
> Encodable<S, E> for TrieMap<V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
                for (i, (key, val)) in self.iter().enumerate() {
                    try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                    try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                }
                Ok(())
            })
    }
}

impl<
    E,
    D: Decoder<E>,
    V: Decodable<D, E>
> Decodable<D, E> for TrieMap<V> {
    fn decode(d: &mut D) -> Result<TrieMap<V>, E> {
        d.read_map(|d, len| {
            let mut map = TrieMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for TrieSet {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
                for (i, e) in self.iter().enumerate() {
                    try!(s.emit_seq_elt(i, |s| e.encode(s)));
                }
                Ok(())
            })
    }
}

impl<E, D: Decoder<E>> Decodable<D, E> for TrieSet {
    fn decode(d: &mut D) -> Result<TrieSet, E> {
        d.read_seq(|d, len| {
            let mut set = TrieSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}
<commit_msg>Convert some push_back users to push<commit_after>// Copyright 2014 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.

//! Implementations of serialization for structures found in libcollections

use std::uint;
use std::default::Default;
use std::hash::{Hash, Hasher};

use {Decodable, Encodable, Decoder, Encoder};
use std::collections::{DList, RingBuf, TreeMap, TreeSet, HashMap, HashSet,
                       TrieMap, TrieSet};
use std::collections::enum_set::{EnumSet, CLike};

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for DList<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
    fn decode(d: &mut D) -> Result<DList<T>, E> {
        d.read_seq(|d, len| {
            let mut list = DList::new();
            for i in range(0u, len) {
                list.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(list)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for RingBuf<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
    fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
        d.read_seq(|d, len| {
            let mut deque: RingBuf<T> = RingBuf::new();
            for i in range(0u, len) {
                deque.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(deque)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + PartialEq + Ord,
    V: Encodable<S, E> + PartialEq
> Encodable<S, E> for TreeMap<K, V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + PartialEq + Ord,
    V: Decodable<D, E> + PartialEq
> Decodable<D, E> for TreeMap<K, V> {
    fn decode(d: &mut D) -> Result<TreeMap<K, V>, E> {
        d.read_map(|d, len| {
            let mut map = TreeMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + PartialEq + Ord
> Encodable<S, E> for TreeSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + PartialEq + Ord
> Decodable<D, E> for TreeSet<T> {
    fn decode(d: &mut D) -> Result<TreeSet<T>, E> {
        d.read_seq(|d, len| {
            let mut set = TreeSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + CLike
> Encodable<S, E> for EnumSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let mut bits = 0;
        for item in self.iter() {
            bits |= item.to_uint();
        }
        s.emit_uint(bits)
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + CLike
> Decodable<D, E> for EnumSet<T> {
    fn decode(d: &mut D) -> Result<EnumSet<T>, E> {
        let bits = try!(d.read_uint());
        let mut set = EnumSet::empty();
        for bit in range(0, uint::BITS) {
            if bits & (1 << bit) != 0 {
                set.add(CLike::from_uint(1 << bit));
            }
        }
        Ok(set)
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + Hash<X> + Eq,
    V: Encodable<S, E>,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashMap<K, V, H> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + Hash<S> + Eq,
    V: Decodable<D, E>,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashMap<K, V, H> {
    fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
        d.read_map(|d, len| {
            let hasher = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, hasher);
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + Hash<X> + Eq,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashSet<T, H> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + Hash<S> + Eq,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashSet<T, H> {
    fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
        d.read_seq(|d, len| {
            let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    V: Encodable<S, E>
> Encodable<S, E> for TrieMap<V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
                for (i, (key, val)) in self.iter().enumerate() {
                    try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                    try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                }
                Ok(())
            })
    }
}

impl<
    E,
    D: Decoder<E>,
    V: Decodable<D, E>
> Decodable<D, E> for TrieMap<V> {
    fn decode(d: &mut D) -> Result<TrieMap<V>, E> {
        d.read_map(|d, len| {
            let mut map = TrieMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for TrieSet {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
                for (i, e) in self.iter().enumerate() {
                    try!(s.emit_seq_elt(i, |s| e.encode(s)));
                }
                Ok(())
            })
    }
}

impl<E, D: Decoder<E>> Decodable<D, E> for TrieSet {
    fn decode(d: &mut D) -> Result<TrieSet, E> {
        d.read_seq(|d, len| {
            let mut set = TrieSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}
<|endoftext|>